Merge pull request #81 from Random-Liu/upgrade-containerd

Upgrade containerd to 8ed1e24ae9
This commit is contained in:
Lantao Liu 2017-06-19 12:59:47 -07:00 committed by GitHub
commit 1a9d95244a
184 changed files with 2418 additions and 13888 deletions

182
Godeps/Godeps.json generated
View File

@ -6,11 +6,6 @@
"./..."
],
"Deps": [
{
"ImportPath": "github.com/Microsoft/go-winio",
"Comment": "v0.3.8",
"Rev": "fff283ad5116362ca252298cfc9b95828956d85d"
},
{
"ImportPath": "github.com/Sirupsen/logrus",
"Comment": "v0.11.0",
@ -28,157 +23,143 @@
},
{
"ImportPath": "github.com/containerd/containerd/api/services/containers",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/api/services/content",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/api/services/diff",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/api/services/execution",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/api/services/images",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/api/services/snapshot",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/api/services/version",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/api/types/descriptor",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/api/types/mount",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/api/types/task",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
},
{
"ImportPath": "github.com/containerd/containerd/archive",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
},
{
"ImportPath": "github.com/containerd/containerd/archive/compression",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/containers",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/content",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
},
{
"ImportPath": "github.com/containerd/containerd/fs",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/images",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/log",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/metadata",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/mount",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/namespaces",
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/plugin",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/reference",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/remotes",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/remotes/docker",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/remotes/docker/schema1",
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/rootfs",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/services/content",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/services/diff",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/services/images",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/services/snapshot",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/containerd/snapshot",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
},
{
"ImportPath": "github.com/containerd/containerd/sys",
"Comment": "v0.2.8-126-g4ae34cc",
"Rev": "4ae34cccc5b496c6547ff28dbeed1bde4773fa7a"
},
{
"ImportPath": "github.com/containerd/continuity/sysx",
"Rev": "86cec1535a968310e7532819f699ff2830ed7463"
"Comment": "v0.2.8-198-g8ed1e24",
"Rev": "8ed1e24ae925b5c6d8195858ee89dddb0507d65f"
},
{
"ImportPath": "github.com/containerd/fifo",
@ -279,15 +260,15 @@
},
{
"ImportPath": "github.com/golang/protobuf/proto",
"Rev": "8ee79997227bf9b34611aee7946ae64735e6fd93"
"Rev": "7a211bcf3bce0e3f1d74f9894916e6f116ae83b4"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes/any",
"Rev": "8ee79997227bf9b34611aee7946ae64735e6fd93"
"Rev": "7a211bcf3bce0e3f1d74f9894916e6f116ae83b4"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes/empty",
"Rev": "8ee79997227bf9b34611aee7946ae64735e6fd93"
"Rev": "7a211bcf3bce0e3f1d74f9894916e6f116ae83b4"
},
{
"ImportPath": "github.com/jpillora/backoff",
@ -298,43 +279,34 @@
"Comment": "v0.3",
"Rev": "f648cd6e60948e4da391040e5c75d8175fea4fb7"
},
{
"ImportPath": "github.com/nightlyone/lockfile",
"Rev": "1d49c987357a327b5b03aa84cbddd582c328615d"
},
{
"ImportPath": "github.com/opencontainers/go-digest",
"Rev": "21dfd564fd89c944783d00d069f33e3e7123c448"
},
{
"ImportPath": "github.com/opencontainers/image-spec/identity",
"Comment": "v1.0.0-rc4-51-ga431dbc",
"Rev": "a431dbcf6a74fca2e0e040b819a836dbe3fb23ca"
"Comment": "v1.0.0-rc6",
"Rev": "1a6593ab6c3ab5902072b4694a22ff19425396ae"
},
{
"ImportPath": "github.com/opencontainers/image-spec/specs-go",
"Comment": "v1.0.0-rc4-51-ga431dbc",
"Rev": "a431dbcf6a74fca2e0e040b819a836dbe3fb23ca"
"Comment": "v1.0.0-rc6",
"Rev": "1a6593ab6c3ab5902072b4694a22ff19425396ae"
},
{
"ImportPath": "github.com/opencontainers/image-spec/specs-go/v1",
"Comment": "v1.0.0-rc4-51-ga431dbc",
"Rev": "a431dbcf6a74fca2e0e040b819a836dbe3fb23ca"
"Comment": "v1.0.0-rc6",
"Rev": "1a6593ab6c3ab5902072b4694a22ff19425396ae"
},
{
"ImportPath": "github.com/opencontainers/runc/libcontainer/configs",
"Comment": "v1.0.0-rc3-21-g50401b5",
"Rev": "50401b5b4c2e01e4f1372b73a021742deeaf4e2d"
"Comment": "v1.0.0-rc3-74-g6394544",
"Rev": "639454475cb9c8b861cc599f8bcd5c8c790ae402"
},
{
"ImportPath": "github.com/opencontainers/runc/libcontainer/devices",
"Comment": "v1.0.0-rc3-21-g50401b5",
"Rev": "50401b5b4c2e01e4f1372b73a021742deeaf4e2d"
},
{
"ImportPath": "github.com/opencontainers/runc/libcontainer/system",
"Comment": "v1.0.0-rc3-21-g50401b5",
"Rev": "50401b5b4c2e01e4f1372b73a021742deeaf4e2d"
"Comment": "v1.0.0-rc3-74-g6394544",
"Rev": "639454475cb9c8b861cc599f8bcd5c8c790ae402"
},
{
"ImportPath": "github.com/opencontainers/runtime-spec/specs-go",
@ -426,10 +398,6 @@
"ImportPath": "golang.org/x/sys/unix",
"Rev": "f3918c30c5c2cb527c0b071a27c35120a6c0719a"
},
{
"ImportPath": "golang.org/x/sys/windows",
"Rev": "f3918c30c5c2cb527c0b071a27c35120a6c0719a"
},
{
"ImportPath": "golang.org/x/text/secure/bidirule",
"Rev": "19e51611da83d6be54ddafce4a4af510cb3e9ea4"

View File

@ -28,6 +28,7 @@ import (
containerdimages "github.com/containerd/containerd/images"
"github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker"
"github.com/containerd/containerd/remotes/docker/schema1"
containerdrootfs "github.com/containerd/containerd/rootfs"
"github.com/golang/glog"
imagedigest "github.com/opencontainers/go-digest"
@ -207,35 +208,37 @@ func (c *criContainerdService) pullImage(ctx context.Context, ref string) (
// TODO(random-liu): Always resolve image reference and use resolved image name in
// the system.
// Put the image information into containerd image store.
// In the future, containerd will rely on the information in the image store to perform image
// garbage collection.
// For now, we simply use it to store and retrieve information required for pulling an image.
if err = c.imageStoreService.Put(ctx, ref, desc); err != nil {
return "", "", fmt.Errorf("failed to put image %q desc %v into containerd image store: %v",
ref, desc, err)
}
// Do not cleanup if following operations fail so as to make resumable download possible.
glog.V(4).Infof("Start downloading resources for image %q", ref)
resources := newResourceSet()
resourceTrackHandler := containerdimages.HandlerFunc(func(ctx gocontext.Context, desc imagespec.Descriptor) (
[]imagespec.Descriptor, error) {
resources.add(remotes.MakeRefKey(ctx, desc))
return nil, nil
})
// Fetch all image resources into content store.
// Dispatch a handler which will run a sequence of handlers to:
// 1) track all resources associated using a customized handler;
// 2) fetch the object using a FetchHandler;
// 3) recurse through any sub-layers via a ChildrenHandler.
err = containerdimages.Dispatch(
ctx,
containerdimages.Handlers(
containerdimages.HandlerFunc(func(ctx gocontext.Context, desc imagespec.Descriptor) (
[]imagespec.Descriptor, error) {
resources.add(remotes.MakeRefKey(ctx, desc))
return nil, nil
}),
// Support schema1 image.
var (
schema1Converter *schema1.Converter
handler containerdimages.Handler
)
if desc.MediaType == containerdimages.MediaTypeDockerSchema1Manifest {
schema1Converter = schema1.NewConverter(c.contentStoreService, fetcher)
handler = containerdimages.Handlers(
resourceTrackHandler,
schema1Converter,
)
} else {
handler = containerdimages.Handlers(
resourceTrackHandler,
remotes.FetchHandler(c.contentStoreService, fetcher),
containerdimages.ChildrenHandler(c.contentStoreService)),
desc)
if err != nil {
containerdimages.ChildrenHandler(c.contentStoreService),
)
}
if err = containerdimages.Dispatch(ctx, handler, desc); err != nil {
// Dispatch returns error when requested resources are locked.
// In that case, we should start waiting and checking the pulling
// progress.
@ -247,7 +250,26 @@ func (c *criContainerdService) pullImage(ctx context.Context, ref string) (
return "", "", fmt.Errorf("failed to wait for image %q downloading: %v", ref, err)
}
glog.V(4).Infof("Finished downloading resources for image %q", ref)
if schema1Converter != nil {
desc, err = schema1Converter.Convert(ctx)
if err != nil {
return "", "", fmt.Errorf("failed to convert schema 1 image %q: %v", ref, err)
}
}
// In the future, containerd will rely on the information in the image store to perform image
// garbage collection.
// For now, we simply use it to store and retrieve information required for pulling an image.
// @stevvooe said we should `Put` before downloading content, However:
// 1) Containerd client put image metadata after downloading;
// 2) We need desc returned by schema1 converter.
// So just put the image metadata after downloading now.
// TODO(random-liu): Fix the potential garbage collection race.
if err = c.imageStoreService.Put(ctx, ref, desc); err != nil {
return "", "", fmt.Errorf("failed to put image %q desc %v into containerd image store: %v",
ref, desc, err)
}
// Do not cleanup if following operations fail so as to make resumable download possible.
// TODO(random-liu): Replace with image.Unpack.
// Unpack the image layers into snapshots.
image, err := c.imageStoreService.Get(ctx, ref)

View File

@ -23,15 +23,20 @@ import (
"syscall"
"time"
"github.com/containerd/containerd/namespaces"
"github.com/golang/glog"
"golang.org/x/net/context"
"google.golang.org/grpc"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
"k8s.io/kubernetes/pkg/util/interrupt"
)
// unixProtocol is the network protocol of unix socket.
const unixProtocol = "unix"
const (
// unixProtocol is the network protocol of unix socket.
unixProtocol = "unix"
// k8sContainerdNamespace is the namespace we use to connect containerd.
k8sContainerdNamespace = "k8s.io"
)
// CRIContainerdServer is the grpc server of cri-containerd.
type CRIContainerdServer struct {
@ -84,6 +89,28 @@ func ConnectToContainerd(path string, connectionTimeout time.Duration) (*grpc.Cl
grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout(unixProtocol, path, timeout)
}),
grpc.WithUnaryInterceptor(grpc.UnaryClientInterceptor(unary)),
grpc.WithStreamInterceptor(grpc.StreamClientInterceptor(stream)),
}
return grpc.Dial(fmt.Sprintf("%s://%s", unixProtocol, path), dialOpts...)
}
// TODO(random-liu): Get rid of following functions after switching to containerd client.
// unary is a wrapper to apply kubernetes namespace in each grpc unary call.
func unary(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
_, ok := namespaces.Namespace(ctx)
if !ok {
ctx = namespaces.WithNamespace(ctx, k8sContainerdNamespace)
}
return invoker(ctx, method, req, reply, cc, opts...)
}
// stream is a wrapper to apply kubernetes namespace in each grpc stream call.
func stream(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
_, ok := namespaces.Namespace(ctx)
if !ok {
ctx = namespaces.WithNamespace(ctx, k8sContainerdNamespace)
}
return streamer(ctx, desc, cc, method, opts...)
}

View File

@ -384,3 +384,9 @@ func (f *FakeExecutionClient) Processes(ctx context.Context, in *execution.Proce
// TODO: implement Processes()
return nil, nil
}
// DeleteProcess is a test implementation of execution.DeleteProcess
func (f *FakeExecutionClient) DeleteProcess(ctx context.Context, in *execution.DeleteProcessRequest, opts ...grpc.CallOption) (*execution.DeleteResponse, error) {
// TODO: implement DeleteProcess()
return nil, nil
}

View File

@ -1 +0,0 @@
*.exe

View File

@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 Microsoft
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,22 +0,0 @@
# go-winio
This repository contains utilities for efficiently performing Win32 IO operations in
Go. Currently, this is focused on accessing named pipes and other file handles, and
for using named pipes as a net transport.
This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go
to reuse the thread to schedule another goroutine. This limits support to Windows Vista and
newer operating systems. This is similar to the implementation of network sockets in Go's net
package.
Please see the LICENSE file for licensing information.
This project has adopted the [Microsoft Open Source Code of
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
see the [Code of Conduct
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
questions or comments.
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
for another named pipe implementation.

View File

@ -1,268 +0,0 @@
// +build windows
package winio
import (
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"runtime"
"syscall"
"unicode/utf16"
)
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
const (
BackupData = uint32(iota + 1)
BackupEaData
BackupSecurity
BackupAlternateData
BackupLink
BackupPropertyData
BackupObjectId
BackupReparseData
BackupSparseBlock
BackupTxfsData
)
const (
StreamSparseAttributes = uint32(8)
)
const (
WRITE_DAC = 0x40000
WRITE_OWNER = 0x80000
ACCESS_SYSTEM_SECURITY = 0x1000000
)
// BackupHeader represents a backup stream of a file.
type BackupHeader struct {
Id uint32 // The backup stream ID
Attributes uint32 // Stream attributes
Size int64 // The size of the stream in bytes
Name string // The name of the stream (for BackupAlternateData only).
Offset int64 // The offset of the stream in the file (for BackupSparseBlock only).
}
type win32StreamId struct {
StreamId uint32
Attributes uint32
Size uint64
NameSize uint32
}
// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series
// of BackupHeader values.
type BackupStreamReader struct {
r io.Reader
bytesLeft int64
}
// NewBackupStreamReader produces a BackupStreamReader from any io.Reader.
func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
return &BackupStreamReader{r, 0}
}
// Next returns the next backup stream and prepares for calls to Write(). It skips the remainder of the current stream if
// it was not completely read.
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
if r.bytesLeft > 0 {
if _, err := io.Copy(ioutil.Discard, r); err != nil {
return nil, err
}
}
var wsi win32StreamId
if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
return nil, err
}
hdr := &BackupHeader{
Id: wsi.StreamId,
Attributes: wsi.Attributes,
Size: int64(wsi.Size),
}
if wsi.NameSize != 0 {
name := make([]uint16, int(wsi.NameSize/2))
if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
return nil, err
}
hdr.Name = syscall.UTF16ToString(name)
}
if wsi.StreamId == BackupSparseBlock {
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
return nil, err
}
hdr.Size -= 8
}
r.bytesLeft = hdr.Size
return hdr, nil
}
// Read reads from the current backup stream.
func (r *BackupStreamReader) Read(b []byte) (int, error) {
if r.bytesLeft == 0 {
return 0, io.EOF
}
if int64(len(b)) > r.bytesLeft {
b = b[:r.bytesLeft]
}
n, err := r.r.Read(b)
r.bytesLeft -= int64(n)
if err == io.EOF {
err = io.ErrUnexpectedEOF
} else if r.bytesLeft == 0 && err == nil {
err = io.EOF
}
return n, err
}
// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API.
type BackupStreamWriter struct {
w io.Writer
bytesLeft int64
}
// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer.
func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter {
return &BackupStreamWriter{w, 0}
}
// WriteHeader writes the next backup stream header and prepares for calls to Write().
func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
if w.bytesLeft != 0 {
return fmt.Errorf("missing %d bytes", w.bytesLeft)
}
name := utf16.Encode([]rune(hdr.Name))
wsi := win32StreamId{
StreamId: hdr.Id,
Attributes: hdr.Attributes,
Size: uint64(hdr.Size),
NameSize: uint32(len(name) * 2),
}
if hdr.Id == BackupSparseBlock {
// Include space for the int64 block offset
wsi.Size += 8
}
if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil {
return err
}
if len(name) != 0 {
if err := binary.Write(w.w, binary.LittleEndian, name); err != nil {
return err
}
}
if hdr.Id == BackupSparseBlock {
if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil {
return err
}
}
w.bytesLeft = hdr.Size
return nil
}
// Write writes to the current backup stream.
func (w *BackupStreamWriter) Write(b []byte) (int, error) {
if w.bytesLeft < int64(len(b)) {
return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft)
}
n, err := w.w.Write(b)
w.bytesLeft -= int64(n)
return n, err
}
// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API.
type BackupFileReader struct {
f *os.File
includeSecurity bool
ctx uintptr
}
// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true,
// Read will attempt to read the security descriptor of the file.
func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
r := &BackupFileReader{f, includeSecurity, 0}
runtime.SetFinalizer(r, func(r *BackupFileReader) { r.Close() })
return r
}
// Read reads a backup stream from the file by calling the Win32 API BackupRead().
func (r *BackupFileReader) Read(b []byte) (int, error) {
var bytesRead uint32
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
if err != nil {
return 0, &os.PathError{"BackupRead", r.f.Name(), err}
}
if bytesRead == 0 {
return 0, io.EOF
}
return int(bytesRead), nil
}
// Close frees Win32 resources associated with the BackupFileReader. It does not close
// the underlying file.
func (r *BackupFileReader) Close() error {
if r.ctx != 0 {
backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
r.ctx = 0
}
return nil
}
// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API.
type BackupFileWriter struct {
f *os.File
includeSecurity bool
ctx uintptr
}
// NewBackupFileWrtier returns a new BackupFileWriter from a file handle. If includeSecurity is true,
// Write() will attempt to restore the security descriptor from the stream.
func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
w := &BackupFileWriter{f, includeSecurity, 0}
runtime.SetFinalizer(w, func(w *BackupFileWriter) { w.Close() })
return w
}
// Write restores a portion of the file using the provided backup stream.
func (w *BackupFileWriter) Write(b []byte) (int, error) {
var bytesWritten uint32
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
if err != nil {
return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
}
if int(bytesWritten) != len(b) {
return int(bytesWritten), errors.New("not all bytes could be written")
}
return len(b), nil
}
// Close frees Win32 resources associated with the BackupFileWriter. It does not
// close the underlying file.
func (w *BackupFileWriter) Close() error {
if w.ctx != 0 {
backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
w.ctx = 0
}
return nil
}
// OpenForBackup opens a file or directory, potentially skipping access checks if the backup
// or restore privileges have been acquired.
//
// If the file opened was a directory, it cannot be used with Readdir().
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
winPath, err := syscall.UTF16FromString(path)
if err != nil {
return nil, err
}
h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0)
if err != nil {
err = &os.PathError{Op: "open", Path: path, Err: err}
return nil, err
}
return os.NewFile(uintptr(h), path), nil
}

View File

@ -1,221 +0,0 @@
// +build windows
package winio
import (
"errors"
"io"
"runtime"
"sync"
"syscall"
"time"
)
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
//sys timeBeginPeriod(period uint32) (n int32) = winmm.timeBeginPeriod
const (
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
cFILE_SKIP_SET_EVENT_ON_HANDLE = 2
)
var (
ErrFileClosed = errors.New("file has already been closed")
ErrTimeout = &timeoutError{}
)
type timeoutError struct{}
func (e *timeoutError) Error() string { return "i/o timeout" }
func (e *timeoutError) Timeout() bool { return true }
func (e *timeoutError) Temporary() bool { return true }
var ioInitOnce sync.Once
var ioCompletionPort syscall.Handle
// ioResult contains the result of an asynchronous IO operation
type ioResult struct {
bytes uint32
err error
}
// ioOperation represents an outstanding asynchronous Win32 IO
type ioOperation struct {
o syscall.Overlapped
ch chan ioResult
}
func initIo() {
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
if err != nil {
panic(err)
}
ioCompletionPort = h
go ioCompletionProcessor(h)
}
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
// It takes ownership of this handle and will close it if it is garbage collected.
type win32File struct {
handle syscall.Handle
wg sync.WaitGroup
closing bool
readDeadline time.Time
writeDeadline time.Time
}
// makeWin32File makes a new win32File from an existing file handle
func makeWin32File(h syscall.Handle) (*win32File, error) {
f := &win32File{handle: h}
ioInitOnce.Do(initIo)
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
if err != nil {
return nil, err
}
err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
if err != nil {
return nil, err
}
runtime.SetFinalizer(f, (*win32File).closeHandle)
return f, nil
}
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
return makeWin32File(h)
}
// closeHandle closes the resources associated with a Win32 handle
func (f *win32File) closeHandle() {
if !f.closing {
// cancel all IO and wait for it to complete
f.closing = true
cancelIoEx(f.handle, nil)
f.wg.Wait()
// at this point, no new IO can start
syscall.Close(f.handle)
f.handle = 0
}
}
// Close closes a win32File.
func (f *win32File) Close() error {
f.closeHandle()
runtime.SetFinalizer(f, nil)
return nil
}
// prepareIo prepares for a new IO operation
func (f *win32File) prepareIo() (*ioOperation, error) {
f.wg.Add(1)
if f.closing {
return nil, ErrFileClosed
}
c := &ioOperation{}
c.ch = make(chan ioResult)
return c, nil
}
// ioCompletionProcessor processes completed async IOs forever
func ioCompletionProcessor(h syscall.Handle) {
// Set the timer resolution to 1. This fixes a performance regression in golang 1.6.
timeBeginPeriod(1)
for {
var bytes uint32
var key uintptr
var op *ioOperation
err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
if op == nil {
panic(err)
}
op.ch <- ioResult{bytes, err}
}
}
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
// the operation has actually completed.
func (f *win32File) asyncIo(c *ioOperation, deadline time.Time, bytes uint32, err error) (int, error) {
if err != syscall.ERROR_IO_PENDING {
f.wg.Done()
return int(bytes), err
} else {
var r ioResult
wait := true
timedout := false
if f.closing {
cancelIoEx(f.handle, &c.o)
} else if !deadline.IsZero() {
now := time.Now()
if !deadline.After(now) {
timedout = true
} else {
timeout := time.After(deadline.Sub(now))
select {
case r = <-c.ch:
wait = false
case <-timeout:
timedout = true
}
}
}
if timedout {
cancelIoEx(f.handle, &c.o)
}
if wait {
r = <-c.ch
}
err = r.err
if err == syscall.ERROR_OPERATION_ABORTED {
if f.closing {
err = ErrFileClosed
} else if timedout {
err = ErrTimeout
}
}
f.wg.Done()
return int(r.bytes), err
}
}
// Read reads from a file handle.
func (f *win32File) Read(b []byte) (int, error) {
c, err := f.prepareIo()
if err != nil {
return 0, err
}
var bytes uint32
err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
n, err := f.asyncIo(c, f.readDeadline, bytes, err)
// Handle EOF conditions.
if err == nil && n == 0 && len(b) != 0 {
return 0, io.EOF
} else if err == syscall.ERROR_BROKEN_PIPE {
return 0, io.EOF
} else {
return n, err
}
}
// Write writes to a file handle.
func (f *win32File) Write(b []byte) (int, error) {
c, err := f.prepareIo()
if err != nil {
return 0, err
}
var bytes uint32
err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
return f.asyncIo(c, f.writeDeadline, bytes, err)
}
func (f *win32File) SetReadDeadline(t time.Time) error {
f.readDeadline = t
return nil
}
func (f *win32File) SetWriteDeadline(t time.Time) error {
f.writeDeadline = t
return nil
}

View File

@ -1,56 +0,0 @@
// +build windows
package winio
import (
"os"
"syscall"
"unsafe"
)
//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx
//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle
const (
fileBasicInfo = 0
fileIDInfo = 0x12
)
// FileBasicInfo contains file access time and file attributes information.
type FileBasicInfo struct {
CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
FileAttributes uintptr // includes padding
}
// GetFileBasicInfo retrieves times and attributes for a file.
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
bi := &FileBasicInfo{}
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
}
return bi, nil
}
// SetFileBasicInfo sets times and attributes for a file.
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
}
return nil
}
// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
// unique on a system.
type FileIDInfo struct {
VolumeSerialNumber uint64
FileID [16]byte
}
// GetFileID retrieves the unique (volume, file ID) pair for a file.
func GetFileID(f *os.File) (*FileIDInfo, error) {
fileID := &FileIDInfo{}
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
}
return fileID, nil
}

View File

@ -1,400 +0,0 @@
// +build windows
package winio
import (
"errors"
"io"
"net"
"os"
"syscall"
"time"
"unsafe"
)
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
//sys createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
//sys waitNamedPipe(name string, timeout uint32) (err error) = WaitNamedPipeW
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
type securityAttributes struct {
Length uint32
SecurityDescriptor *byte
InheritHandle uint32
}
const (
cERROR_PIPE_BUSY = syscall.Errno(231)
cERROR_PIPE_CONNECTED = syscall.Errno(535)
cERROR_SEM_TIMEOUT = syscall.Errno(121)
cPIPE_ACCESS_DUPLEX = 0x3
cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000
cSECURITY_SQOS_PRESENT = 0x100000
cSECURITY_ANONYMOUS = 0
cPIPE_REJECT_REMOTE_CLIENTS = 0x8
cPIPE_UNLIMITED_INSTANCES = 255
cNMPWAIT_USE_DEFAULT_WAIT = 0
cNMPWAIT_NOWAIT = 1
cPIPE_TYPE_MESSAGE = 4
cPIPE_READMODE_MESSAGE = 2
)
var (
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
// This error should match net.errClosing since docker takes a dependency on its text.
ErrPipeListenerClosed = errors.New("use of closed network connection")
errPipeWriteClosed = errors.New("pipe has been closed for write")
)
type win32Pipe struct {
*win32File
path string
}
type win32MessageBytePipe struct {
win32Pipe
writeClosed bool
readEOF bool
}
type pipeAddress string
func (f *win32Pipe) LocalAddr() net.Addr {
return pipeAddress(f.path)
}
func (f *win32Pipe) RemoteAddr() net.Addr {
return pipeAddress(f.path)
}
func (f *win32Pipe) SetDeadline(t time.Time) error {
f.SetReadDeadline(t)
f.SetWriteDeadline(t)
return nil
}
// CloseWrite closes the write side of a message pipe in byte mode.
func (f *win32MessageBytePipe) CloseWrite() error {
if f.writeClosed {
return errPipeWriteClosed
}
_, err := f.win32File.Write(nil)
if err != nil {
return err
}
f.writeClosed = true
return nil
}
// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since
// they are used to implement CloseWrite().
func (f *win32MessageBytePipe) Write(b []byte) (int, error) {
if f.writeClosed {
return 0, errPipeWriteClosed
}
if len(b) == 0 {
return 0, nil
}
return f.win32File.Write(b)
}
// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message
// mode pipe will return io.EOF, as will all subsequent reads.
func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
if f.readEOF {
return 0, io.EOF
}
n, err := f.win32File.Read(b)
if err == io.EOF {
// If this was the result of a zero-byte read, then
// it is possible that the read was due to a zero-size
// message. Since we are simulating CloseWrite with a
// zero-byte message, ensure that all future Read() calls
// also return EOF.
f.readEOF = true
}
return n, err
}
func (s pipeAddress) Network() string {
return "pipe"
}
func (s pipeAddress) String() string {
return string(s)
}
// DialPipe connects to a named pipe by path, timing out if the connection
// takes longer than the specified duration. If timeout is nil, then the timeout
// is the default timeout established by the pipe server.
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
var absTimeout time.Time
if timeout != nil {
absTimeout = time.Now().Add(*timeout)
}
var err error
var h syscall.Handle
for {
h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
if err != cERROR_PIPE_BUSY {
break
}
now := time.Now()
var ms uint32
if absTimeout.IsZero() {
ms = cNMPWAIT_USE_DEFAULT_WAIT
} else if now.After(absTimeout) {
ms = cNMPWAIT_NOWAIT
} else {
ms = uint32(absTimeout.Sub(now).Nanoseconds() / 1000 / 1000)
}
err = waitNamedPipe(path, ms)
if err != nil {
if err == cERROR_SEM_TIMEOUT {
return nil, ErrTimeout
}
break
}
}
if err != nil {
return nil, &os.PathError{Op: "open", Path: path, Err: err}
}
var flags uint32
err = getNamedPipeInfo(h, &flags, nil, nil, nil)
if err != nil {
return nil, err
}
var state uint32
err = getNamedPipeHandleState(h, &state, nil, nil, nil, nil, 0)
if err != nil {
return nil, err
}
if state&cPIPE_READMODE_MESSAGE != 0 {
return nil, &os.PathError{Op: "open", Path: path, Err: errors.New("message readmode pipes not supported")}
}
f, err := makeWin32File(h)
if err != nil {
syscall.Close(h)
return nil, err
}
// If the pipe is in message mode, return a message byte pipe, which
// supports CloseWrite().
if flags&cPIPE_TYPE_MESSAGE != 0 {
return &win32MessageBytePipe{
win32Pipe: win32Pipe{win32File: f, path: path},
}, nil
}
return &win32Pipe{win32File: f, path: path}, nil
}
type acceptResponse struct {
f *win32File
err error
}
type win32PipeListener struct {
firstHandle syscall.Handle
path string
securityDescriptor []byte
config PipeConfig
acceptCh chan (chan acceptResponse)
closeCh chan int
doneCh chan int
}
func makeServerPipeHandle(path string, securityDescriptor []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED
if first {
flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE
}
var mode uint32 = cPIPE_REJECT_REMOTE_CLIENTS
if c.MessageMode {
mode |= cPIPE_TYPE_MESSAGE
}
var sa securityAttributes
sa.Length = uint32(unsafe.Sizeof(sa))
if securityDescriptor != nil {
sa.SecurityDescriptor = &securityDescriptor[0]
}
h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, &sa)
if err != nil {
return 0, &os.PathError{Op: "open", Path: path, Err: err}
}
return h, nil
}
func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false)
if err != nil {
return nil, err
}
f, err := makeWin32File(h)
if err != nil {
syscall.Close(h)
return nil, err
}
return f, nil
}
func (l *win32PipeListener) listenerRoutine() {
closed := false
for !closed {
select {
case <-l.closeCh:
closed = true
case responseCh := <-l.acceptCh:
p, err := l.makeServerPipe()
if err == nil {
// Wait for the client to connect.
ch := make(chan error)
go func() {
ch <- connectPipe(p)
}()
select {
case err = <-ch:
if err != nil {
p.Close()
p = nil
}
case <-l.closeCh:
// Abort the connect request by closing the handle.
p.Close()
p = nil
err = <-ch
if err == nil || err == ErrFileClosed {
err = ErrPipeListenerClosed
}
closed = true
}
}
responseCh <- acceptResponse{p, err}
}
}
syscall.Close(l.firstHandle)
l.firstHandle = 0
// Notify Close() and Accept() callers that the handle has been closed.
close(l.doneCh)
}
// PipeConfig contain configuration for the pipe listener.
type PipeConfig struct {
// SecurityDescriptor contains a Windows security descriptor in SDDL format.
SecurityDescriptor string
// MessageMode determines whether the pipe is in byte or message mode. In either
// case the pipe is read in byte mode by default. The only practical difference in
// this implementation is that CloseWrite() is only supported for message mode pipes;
// CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only
// transferred to the reader (and returned as io.EOF in this implementation)
// when the pipe is in message mode.
MessageMode bool
// InputBufferSize specifies the size the input buffer, in bytes.
InputBufferSize int32
// OutputBufferSize specifies the size the input buffer, in bytes.
OutputBufferSize int32
}
// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe.
// The pipe must not already exist.
func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
var (
sd []byte
err error
)
if c == nil {
c = &PipeConfig{}
}
if c.SecurityDescriptor != "" {
sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor)
if err != nil {
return nil, err
}
}
h, err := makeServerPipeHandle(path, sd, c, true)
if err != nil {
return nil, err
}
// Immediately open and then close a client handle so that the named pipe is
// created but not currently accepting connections.
h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
if err != nil {
syscall.Close(h)
return nil, err
}
syscall.Close(h2)
l := &win32PipeListener{
firstHandle: h,
path: path,
securityDescriptor: sd,
config: *c,
acceptCh: make(chan (chan acceptResponse)),
closeCh: make(chan int),
doneCh: make(chan int),
}
go l.listenerRoutine()
return l, nil
}
func connectPipe(p *win32File) error {
c, err := p.prepareIo()
if err != nil {
return err
}
err = connectNamedPipe(p.handle, &c.o)
_, err = p.asyncIo(c, time.Time{}, 0, err)
if err != nil && err != cERROR_PIPE_CONNECTED {
return err
}
return nil
}
func (l *win32PipeListener) Accept() (net.Conn, error) {
ch := make(chan acceptResponse)
select {
case l.acceptCh <- ch:
response := <-ch
err := response.err
if err != nil {
return nil, err
}
if l.config.MessageMode {
return &win32MessageBytePipe{
win32Pipe: win32Pipe{win32File: response.f, path: l.path},
}, nil
}
return &win32Pipe{win32File: response.f, path: l.path}, nil
case <-l.doneCh:
return nil, ErrPipeListenerClosed
}
}
func (l *win32PipeListener) Close() error {
select {
case l.closeCh <- 1:
<-l.doneCh
case <-l.doneCh:
}
return nil
}
func (l *win32PipeListener) Addr() net.Addr {
return pipeAddress(l.path)
}

View File

@ -1,202 +0,0 @@
// +build windows
package winio
import (
"bytes"
"encoding/binary"
"fmt"
"runtime"
"sync"
"syscall"
"unicode/utf16"
"golang.org/x/sys/windows"
)
//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
//sys revertToSelf() (err error) = advapi32.RevertToSelf
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
const (
SE_PRIVILEGE_ENABLED = 2
ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
SeBackupPrivilege = "SeBackupPrivilege"
SeRestorePrivilege = "SeRestorePrivilege"
)
const (
securityAnonymous = iota
securityIdentification
securityImpersonation
securityDelegation
)
var (
privNames = make(map[string]uint64)
privNameMutex sync.Mutex
)
// PrivilegeError represents an error enabling privileges.
type PrivilegeError struct {
privileges []uint64
}
func (e *PrivilegeError) Error() string {
s := ""
if len(e.privileges) > 1 {
s = "Could not enable privileges "
} else {
s = "Could not enable privilege "
}
for i, p := range e.privileges {
if i != 0 {
s += ", "
}
s += `"`
s += getPrivilegeName(p)
s += `"`
}
return s
}
// RunWithPrivilege enables a single privilege for a function call.
func RunWithPrivilege(name string, fn func() error) error {
return RunWithPrivileges([]string{name}, fn)
}
// RunWithPrivileges enables privileges for a function call.
func RunWithPrivileges(names []string, fn func() error) error {
privileges, err := mapPrivileges(names)
if err != nil {
return err
}
runtime.LockOSThread()
defer runtime.UnlockOSThread()
token, err := newThreadToken()
if err != nil {
return err
}
defer releaseThreadToken(token)
err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED)
if err != nil {
return err
}
return fn()
}
func mapPrivileges(names []string) ([]uint64, error) {
var privileges []uint64
privNameMutex.Lock()
defer privNameMutex.Unlock()
for _, name := range names {
p, ok := privNames[name]
if !ok {
err := lookupPrivilegeValue("", name, &p)
if err != nil {
return nil, err
}
privNames[name] = p
}
privileges = append(privileges, p)
}
return privileges, nil
}
// EnableProcessPrivileges enables privileges globally for the process.
func EnableProcessPrivileges(names []string) error {
return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED)
}
// DisableProcessPrivileges disables privileges globally for the process.
func DisableProcessPrivileges(names []string) error {
return enableDisableProcessPrivilege(names, 0)
}
func enableDisableProcessPrivilege(names []string, action uint32) error {
privileges, err := mapPrivileges(names)
if err != nil {
return err
}
p, _ := windows.GetCurrentProcess()
var token windows.Token
err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
if err != nil {
return err
}
defer token.Close()
return adjustPrivileges(token, privileges, action)
}
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
var b bytes.Buffer
binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
for _, p := range privileges {
binary.Write(&b, binary.LittleEndian, p)
binary.Write(&b, binary.LittleEndian, action)
}
prevState := make([]byte, b.Len())
reqSize := uint32(0)
success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize)
if !success {
return err
}
if err == ERROR_NOT_ALL_ASSIGNED {
return &PrivilegeError{privileges}
}
return nil
}
func getPrivilegeName(luid uint64) string {
var nameBuffer [256]uint16
bufSize := uint32(len(nameBuffer))
err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize)
if err != nil {
return fmt.Sprintf("<unknown privilege %d>", luid)
}
var displayNameBuffer [256]uint16
displayBufSize := uint32(len(displayNameBuffer))
var langID uint32
err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID)
if err != nil {
return fmt.Sprintf("<unknown privilege %s>", string(utf16.Decode(nameBuffer[:bufSize])))
}
return string(utf16.Decode(displayNameBuffer[:displayBufSize]))
}
func newThreadToken() (windows.Token, error) {
err := impersonateSelf(securityImpersonation)
if err != nil {
return 0, err
}
var token windows.Token
err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
if err != nil {
rerr := revertToSelf()
if rerr != nil {
panic(rerr)
}
return 0, err
}
return token, nil
}
func releaseThreadToken(h windows.Token) {
err := revertToSelf()
if err != nil {
panic(err)
}
h.Close()
}

View File

@ -1,128 +0,0 @@
package winio
import (
"bytes"
"encoding/binary"
"fmt"
"strings"
"unicode/utf16"
"unsafe"
)
const (
reparseTagMountPoint = 0xA0000003
reparseTagSymlink = 0xA000000C
)
type reparseDataBuffer struct {
ReparseTag uint32
ReparseDataLength uint16
Reserved uint16
SubstituteNameOffset uint16
SubstituteNameLength uint16
PrintNameOffset uint16
PrintNameLength uint16
}
// ReparsePoint describes a Win32 symlink or mount point.
type ReparsePoint struct {
Target string
IsMountPoint bool
}
// UnsupportedReparsePointError is returned when trying to decode a non-symlink or
// mount point reparse point.
type UnsupportedReparsePointError struct {
Tag uint32
}
func (e *UnsupportedReparsePointError) Error() string {
return fmt.Sprintf("unsupported reparse point %x", e.Tag)
}
// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink
// or a mount point.
func DecodeReparsePoint(b []byte) (*ReparsePoint, error) {
tag := binary.LittleEndian.Uint32(b[0:4])
return DecodeReparsePointData(tag, b[8:])
}
func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) {
isMountPoint := false
switch tag {
case reparseTagMountPoint:
isMountPoint = true
case reparseTagSymlink:
default:
return nil, &UnsupportedReparsePointError{tag}
}
nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6])
if !isMountPoint {
nameOffset += 4
}
nameLength := binary.LittleEndian.Uint16(b[6:8])
name := make([]uint16, nameLength/2)
err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name)
if err != nil {
return nil, err
}
return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil
}
func isDriveLetter(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}
// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or
// mount point.
func EncodeReparsePoint(rp *ReparsePoint) []byte {
// Generate an NT path and determine if this is a relative path.
var ntTarget string
relative := false
if strings.HasPrefix(rp.Target, `\\?\`) {
ntTarget = `\??\` + rp.Target[4:]
} else if strings.HasPrefix(rp.Target, `\\`) {
ntTarget = `\??\UNC\` + rp.Target[2:]
} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' {
ntTarget = `\??\` + rp.Target
} else {
ntTarget = rp.Target
relative = true
}
// The paths must be NUL-terminated even though they are counted strings.
target16 := utf16.Encode([]rune(rp.Target + "\x00"))
ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00"))
size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8
size += len(ntTarget16)*2 + len(target16)*2
tag := uint32(reparseTagMountPoint)
if !rp.IsMountPoint {
tag = reparseTagSymlink
size += 4 // Add room for symlink flags
}
data := reparseDataBuffer{
ReparseTag: tag,
ReparseDataLength: uint16(size),
SubstituteNameOffset: 0,
SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2),
PrintNameOffset: uint16(len(ntTarget16) * 2),
PrintNameLength: uint16((len(target16) - 1) * 2),
}
var b bytes.Buffer
binary.Write(&b, binary.LittleEndian, &data)
if !rp.IsMountPoint {
flags := uint32(0)
if relative {
flags |= 1
}
binary.Write(&b, binary.LittleEndian, flags)
}
binary.Write(&b, binary.LittleEndian, ntTarget16)
binary.Write(&b, binary.LittleEndian, target16)
return b.Bytes()
}

View File

@ -1,98 +0,0 @@
// +build windows
package winio
import (
"syscall"
"unsafe"
)
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
//sys localFree(mem uintptr) = LocalFree
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
const (
cERROR_NONE_MAPPED = syscall.Errno(1332)
)
type AccountLookupError struct {
Name string
Err error
}
func (e *AccountLookupError) Error() string {
if e.Name == "" {
return "lookup account: empty account name specified"
}
var s string
switch e.Err {
case cERROR_NONE_MAPPED:
s = "not found"
default:
s = e.Err.Error()
}
return "lookup account " + e.Name + ": " + s
}
type SddlConversionError struct {
Sddl string
Err error
}
func (e *SddlConversionError) Error() string {
return "convert " + e.Sddl + ": " + e.Err.Error()
}
// LookupSidByName looks up the SID of an account by name
func LookupSidByName(name string) (sid string, err error) {
if name == "" {
return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
}
var sidSize, sidNameUse, refDomainSize uint32
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
return "", &AccountLookupError{name, err}
}
sidBuffer := make([]byte, sidSize)
refDomainBuffer := make([]uint16, refDomainSize)
err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
if err != nil {
return "", &AccountLookupError{name, err}
}
var strBuffer *uint16
err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
if err != nil {
return "", &AccountLookupError{name, err}
}
sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
localFree(uintptr(unsafe.Pointer(strBuffer)))
return sid, nil
}
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
var sdBuffer uintptr
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
if err != nil {
return nil, &SddlConversionError{sddl, err}
}
defer localFree(sdBuffer)
sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
return sd, nil
}
func SecurityDescriptorToSddl(sd []byte) (string, error) {
var sddl *uint16
// The returned string length seems to including an aribtrary number of terminating NULs.
// Don't use it.
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
if err != nil {
return "", err
}
defer localFree(uintptr(unsafe.Pointer(sddl)))
return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
}

View File

@ -1,3 +0,0 @@
package winio
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go

View File

@ -1,496 +0,0 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
package winio
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modwinmm = windows.NewLazySystemDLL("winmm.dll")
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
proctimeBeginPeriod = modwinmm.NewProc("timeBeginPeriod")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procCreateFileW = modkernel32.NewProc("CreateFileW")
procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW")
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
procLocalFree = modkernel32.NewProc("LocalFree")
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
procBackupRead = modkernel32.NewProc("BackupRead")
procBackupWrite = modkernel32.NewProc("BackupWrite")
)
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
newport = syscall.Handle(r0)
if newport == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func timeBeginPeriod(period uint32) (n int32) {
r0, _, _ := syscall.Syscall(proctimeBeginPeriod.Addr(), 1, uintptr(period), 0, 0)
n = int32(r0)
return
}
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
}
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _createFile(name *uint16, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func waitNamedPipe(name string, timeout uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _waitNamedPipe(_p0, timeout)
}
func _waitNamedPipe(name *uint16, timeout uint32) (err error) {
r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(accountName)
if err != nil {
return
}
return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse)
}
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func convertSidToStringSid(sid *byte, str **uint16) (err error) {
r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(str)
if err != nil {
return
}
return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
}
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func localFree(mem uintptr) {
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
return
}
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
len = uint32(r0)
return
}
func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
var _p0 uint32
if releaseAll {
_p0 = 1
} else {
_p0 = 0
}
r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
success = r0 != 0
if true {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func impersonateSelf(level uint32) (err error) {
r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func revertToSelf() (err error) {
r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
var _p0 uint32
if openAsSelf {
_p0 = 1
} else {
_p0 = 0
}
r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getCurrentThread() (h syscall.Handle) {
r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
h = syscall.Handle(r0)
return
}
func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(systemName)
if err != nil {
return
}
var _p1 *uint16
_p1, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _lookupPrivilegeValue(_p0, _p1, luid)
}
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(systemName)
if err != nil {
return
}
return _lookupPrivilegeName(_p0, luid, buffer, size)
}
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(systemName)
if err != nil {
return
}
return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
}
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
var _p0 *byte
if len(b) > 0 {
_p0 = &b[0]
}
var _p1 uint32
if abort {
_p1 = 1
} else {
_p1 = 0
}
var _p2 uint32
if processSecurity {
_p2 = 1
} else {
_p2 = 0
}
r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
var _p0 *byte
if len(b) > 0 {
_p0 = &b[0]
}
var _p1 uint32
if abort {
_p1 = 1
} else {
_p1 = 0
}
var _p2 uint32
if processSecurity {
_p2 = 1
} else {
_p2 = 0
}
r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}

View File

@ -29,13 +29,18 @@ import _ "github.com/gogo/protobuf/gogoproto"
import google_protobuf1 "github.com/gogo/protobuf/types"
import google_protobuf2 "github.com/golang/protobuf/ptypes/empty"
import google_protobuf3 "github.com/gogo/protobuf/types"
import _ "github.com/gogo/protobuf/types"
import _ "github.com/containerd/containerd/api/types/descriptor"
import time "time"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
@ -46,6 +51,7 @@ import io "io"
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
var _ = time.Kitchen
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
@ -81,6 +87,8 @@ type Container struct {
//
// This field may be updated.
RootFS string `protobuf:"bytes,7,opt,name=rootfs,proto3" json:"rootfs,omitempty"`
CreatedAt time.Time `protobuf:"bytes,8,opt,name=created_at,json=createdAt,stdtime" json:"created_at"`
UpdatedAt time.Time `protobuf:"bytes,9,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"`
}
func (m *Container) Reset() { *m = Container{} }
@ -457,6 +465,22 @@ func (m *Container) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintContainers(dAtA, i, uint64(len(m.RootFS)))
i += copy(dAtA[i:], m.RootFS)
}
dAtA[i] = 0x42
i++
i = encodeVarintContainers(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)))
n2, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
if err != nil {
return 0, err
}
i += n2
dAtA[i] = 0x4a
i++
i = encodeVarintContainers(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)))
n3, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
if err != nil {
return 0, err
}
i += n3
return i, nil
}
@ -502,11 +526,11 @@ func (m *GetContainerResponse) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size()))
n2, err := m.Container.MarshalTo(dAtA[i:])
n4, err := m.Container.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n2
i += n4
return i, nil
}
@ -582,11 +606,11 @@ func (m *CreateContainerRequest) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size()))
n3, err := m.Container.MarshalTo(dAtA[i:])
n5, err := m.Container.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n3
i += n5
return i, nil
}
@ -608,11 +632,11 @@ func (m *CreateContainerResponse) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size()))
n4, err := m.Container.MarshalTo(dAtA[i:])
n6, err := m.Container.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n4
i += n6
return i, nil
}
@ -634,20 +658,20 @@ func (m *UpdateContainerRequest) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size()))
n5, err := m.Container.MarshalTo(dAtA[i:])
n7, err := m.Container.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n5
i += n7
if m.UpdateMask != nil {
dAtA[i] = 0x12
i++
i = encodeVarintContainers(dAtA, i, uint64(m.UpdateMask.Size()))
n6, err := m.UpdateMask.MarshalTo(dAtA[i:])
n8, err := m.UpdateMask.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n6
i += n8
}
return i, nil
}
@ -670,11 +694,11 @@ func (m *UpdateContainerResponse) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size()))
n7, err := m.Container.MarshalTo(dAtA[i:])
n9, err := m.Container.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n7
i += n9
return i, nil
}
@ -760,6 +784,10 @@ func (m *Container) Size() (n int) {
if l > 0 {
n += 1 + l + sovContainers(uint64(l))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)
n += 1 + l + sovContainers(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
n += 1 + l + sovContainers(uint64(l))
return n
}
@ -883,6 +911,8 @@ func (this *Container) String() string {
`Runtime:` + fmt.Sprintf("%v", this.Runtime) + `,`,
`Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "google_protobuf1.Any", 1) + `,`,
`RootFS:` + fmt.Sprintf("%v", this.RootFS) + `,`,
`CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf4.Timestamp", 1), `&`, ``, 1) + `,`,
`UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf4.Timestamp", 1), `&`, ``, 1) + `,`,
`}`,
}, "")
return s
@ -1280,6 +1310,66 @@ func (m *Container) Unmarshal(dAtA []byte) error {
}
m.RootFS = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowContainers
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthContainers
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 9:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field UpdatedAt", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowContainers
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthContainers
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipContainers(dAtA[iNdEx:])
@ -2162,45 +2252,48 @@ func init() {
}
var fileDescriptorContainers = []byte{
// 625 bytes of a gzipped FileDescriptorProto
// 680 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xcd, 0x6e, 0xd3, 0x40,
0x10, 0xae, 0x9d, 0xe0, 0x2a, 0x13, 0x21, 0xa1, 0x25, 0x18, 0x63, 0x24, 0x37, 0x32, 0x3f, 0xca,
0x05, 0x1b, 0xc2, 0x85, 0x9f, 0x0a, 0x89, 0xfe, 0xaa, 0x52, 0xe1, 0xe0, 0x02, 0xe5, 0x86, 0x9c,
0x78, 0x63, 0x56, 0x75, 0xbc, 0xc6, 0xbb, 0xae, 0x94, 0x1b, 0xef, 0xc0, 0x8d, 0x67, 0xe0, 0x41,
0x7a, 0xe4, 0xc8, 0xa9, 0xa2, 0x7e, 0x12, 0xe4, 0xb5, 0x53, 0xa7, 0xb6, 0x43, 0x91, 0xe8, 0x6d,
0xc6, 0xf3, 0xcd, 0xd7, 0xf9, 0x66, 0xbe, 0x6d, 0x60, 0xcf, 0x27, 0xfc, 0x73, 0x32, 0xb2, 0xc6,
0x74, 0x6a, 0x8f, 0x69, 0xc8, 0x5d, 0x12, 0xe2, 0xd8, 0x5b, 0x0c, 0xdd, 0x88, 0xd8, 0x0c, 0xc7,
0xc7, 0x64, 0x8c, 0x59, 0xf9, 0x7d, 0x31, 0xb4, 0xa2, 0x98, 0x72, 0x8a, 0xae, 0x97, 0x4d, 0xd6,
0xf1, 0x13, 0xbd, 0xe7, 0x53, 0x9f, 0x8a, 0x8a, 0x9d, 0x45, 0x39, 0x48, 0xbf, 0xe3, 0x53, 0xea,
0x07, 0xd8, 0x16, 0xd9, 0x28, 0x99, 0xd8, 0x6e, 0x38, 0x2b, 0x4a, 0x77, 0xab, 0x25, 0x3c, 0x8d,
0xf8, 0xbc, 0xd8, 0xaf, 0x16, 0x27, 0x04, 0x07, 0xde, 0xa7, 0xa9, 0xcb, 0x8e, 0x0a, 0xc4, 0xce,
0x3f, 0x29, 0xe1, 0xb3, 0x08, 0x33, 0xdb, 0xc3, 0x6c, 0x1c, 0x93, 0x88, 0xd3, 0x78, 0x21, 0xcc,
0x79, 0xcc, 0xef, 0x32, 0x74, 0x36, 0xe7, 0x4d, 0x48, 0x05, 0x99, 0x78, 0x9a, 0xd4, 0x97, 0x06,
0x9d, 0x0d, 0x25, 0x3d, 0x5d, 0x93, 0xf7, 0xb6, 0x1c, 0x99, 0x78, 0x68, 0x1d, 0x94, 0xc0, 0x1d,
0xe1, 0x80, 0x69, 0x72, 0xbf, 0x35, 0xe8, 0x0e, 0xef, 0x5b, 0x17, 0xd4, 0x5b, 0xe7, 0x0c, 0xd6,
0xbe, 0x80, 0x6d, 0x87, 0x3c, 0x9e, 0x39, 0x45, 0x0f, 0xea, 0xc1, 0x35, 0x32, 0x75, 0x7d, 0xac,
0xb5, 0x32, 0x62, 0x27, 0x4f, 0x90, 0x06, 0xab, 0x71, 0x12, 0x72, 0x32, 0xc5, 0x5a, 0x5b, 0x7c,
0x9f, 0xa7, 0x68, 0x00, 0x6d, 0x16, 0xe1, 0xb1, 0xa6, 0xf4, 0xa5, 0x41, 0x77, 0xd8, 0xb3, 0xf2,
0x65, 0x58, 0xf3, 0x65, 0x58, 0xaf, 0xc3, 0x99, 0x23, 0x10, 0xc8, 0x04, 0x25, 0xa6, 0x94, 0x4f,
0x98, 0xb6, 0x2a, 0x66, 0x86, 0xf4, 0x74, 0x4d, 0x71, 0x28, 0xe5, 0x3b, 0x07, 0x4e, 0x51, 0xd1,
0x9f, 0x43, 0x77, 0x61, 0x28, 0x74, 0x03, 0x5a, 0x47, 0x78, 0x96, 0x6b, 0x74, 0xb2, 0x30, 0x1b,
0xef, 0xd8, 0x0d, 0x12, 0xac, 0xc9, 0xf9, 0x78, 0x22, 0x79, 0x21, 0x3f, 0x93, 0xcc, 0x47, 0x70,
0x73, 0x17, 0xf3, 0x73, 0x71, 0x0e, 0xfe, 0x92, 0x60, 0xc6, 0x97, 0x6d, 0xc9, 0x7c, 0x07, 0xbd,
0x8b, 0x70, 0x16, 0xd1, 0x90, 0x61, 0xb4, 0x0e, 0x9d, 0xf3, 0x75, 0x89, 0xb6, 0xee, 0x50, 0x5b,
0xb6, 0xc0, 0x8d, 0xf6, 0xc9, 0xe9, 0xda, 0x8a, 0x53, 0x36, 0x98, 0x36, 0xdc, 0xda, 0x27, 0xac,
0xa4, 0x65, 0xe5, 0x18, 0xca, 0x84, 0x04, 0xbc, 0xe0, 0xec, 0x38, 0x45, 0x66, 0x7e, 0x04, 0xb5,
0xda, 0x50, 0x0c, 0xf2, 0x0a, 0xa0, 0xf4, 0xb1, 0x26, 0x89, 0x53, 0x5e, 0x36, 0xc9, 0x42, 0x87,
0xf9, 0x01, 0xd4, 0xcd, 0x18, 0xbb, 0x1c, 0xd7, 0x56, 0xf2, 0x7f, 0x12, 0x0f, 0xe1, 0x76, 0x8d,
0xf7, 0x4a, 0x76, 0xf7, 0x4d, 0x02, 0xf5, 0x7d, 0xe4, 0x5d, 0xf9, 0xc4, 0xe8, 0x25, 0x74, 0x13,
0xc1, 0x2b, 0xde, 0xa4, 0x70, 0x4e, 0x77, 0xa8, 0xd7, 0x9c, 0xba, 0x93, 0x3d, 0xdb, 0x37, 0x2e,
0x3b, 0x72, 0x20, 0x87, 0x67, 0x71, 0x26, 0xb7, 0x36, 0xd4, 0x95, 0xc8, 0x7d, 0x0c, 0xea, 0x16,
0x0e, 0x70, 0x83, 0xda, 0x25, 0x96, 0x1d, 0xfe, 0x68, 0x01, 0x94, 0x46, 0x41, 0x6f, 0xa1, 0xb5,
0x8b, 0x39, 0x32, 0x2b, 0x7f, 0xb2, 0xe1, 0x11, 0xe8, 0xf7, 0xfe, 0x8a, 0x29, 0xe4, 0x1c, 0x40,
0x3b, 0xb3, 0x22, 0xaa, 0xfe, 0xbf, 0x68, 0x34, 0xb4, 0xfe, 0xe0, 0x12, 0x54, 0x41, 0x7a, 0x08,
0x4a, 0xee, 0x16, 0x54, 0x6d, 0x68, 0x36, 0xa7, 0xfe, 0xf0, 0x32, 0x58, 0x49, 0x9c, 0xdf, 0xa5,
0x46, 0xdc, 0xec, 0xa1, 0x1a, 0xf1, 0xb2, 0xab, 0xee, 0x82, 0x92, 0xdf, 0xa5, 0x46, 0xdc, 0x7c,
0x2e, 0x5d, 0xad, 0x39, 0x69, 0x3b, 0xfb, 0x75, 0xd8, 0xd0, 0x4e, 0xce, 0x8c, 0x95, 0x5f, 0x67,
0xc6, 0xca, 0xd7, 0xd4, 0x90, 0x4e, 0x52, 0x43, 0xfa, 0x99, 0x1a, 0xd2, 0xef, 0xd4, 0x90, 0x46,
0x8a, 0x40, 0x3e, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0x7b, 0xcd, 0xee, 0x1b, 0xe2, 0x06, 0x00,
0x00,
0x10, 0xae, 0x93, 0xe0, 0x36, 0x13, 0x21, 0xa1, 0x25, 0x04, 0x63, 0xa4, 0x24, 0x32, 0x3f, 0xca,
0x05, 0x1b, 0xc2, 0x85, 0x9f, 0x0a, 0xa9, 0xe9, 0x9f, 0x2a, 0x15, 0x0e, 0x6e, 0xa1, 0xdc, 0x2a,
0x27, 0xde, 0x04, 0xab, 0x8e, 0xd7, 0x78, 0x37, 0x95, 0x72, 0xe3, 0x11, 0x90, 0x78, 0x05, 0x8e,
0x3c, 0x48, 0x8f, 0x1c, 0x39, 0x15, 0x9a, 0x27, 0x41, 0xbb, 0x5e, 0xd7, 0xa9, 0xed, 0x50, 0x10,
0xbd, 0xcd, 0x78, 0xbe, 0xf9, 0x32, 0xf3, 0xcd, 0x67, 0x07, 0x76, 0x46, 0x1e, 0xfb, 0x30, 0xe9,
0x9b, 0x03, 0x32, 0xb6, 0x06, 0x24, 0x60, 0x8e, 0x17, 0xe0, 0xc8, 0x9d, 0x0f, 0x9d, 0xd0, 0xb3,
0x28, 0x8e, 0x8e, 0xbd, 0x01, 0xa6, 0xe9, 0xf3, 0xf9, 0xd0, 0x0c, 0x23, 0xc2, 0x08, 0xba, 0x9e,
0x36, 0x99, 0xc7, 0x4f, 0xf4, 0xfa, 0x88, 0x8c, 0x88, 0xa8, 0x58, 0x3c, 0x8a, 0x41, 0xfa, 0x9d,
0x11, 0x21, 0x23, 0x1f, 0x5b, 0x22, 0xeb, 0x4f, 0x86, 0x96, 0x13, 0x4c, 0x65, 0xe9, 0x6e, 0xb6,
0x84, 0xc7, 0x21, 0x4b, 0x8a, 0xed, 0x6c, 0x71, 0xe8, 0x61, 0xdf, 0x3d, 0x1c, 0x3b, 0xf4, 0x48,
0x22, 0x5a, 0x59, 0x04, 0xf3, 0xc6, 0x98, 0x32, 0x67, 0x1c, 0x4a, 0xc0, 0xd6, 0x5f, 0xad, 0xca,
0xa6, 0x21, 0xa6, 0x96, 0x8b, 0xe9, 0x20, 0xf2, 0x42, 0x46, 0xa2, 0xb9, 0x30, 0xe6, 0x31, 0xbe,
0x96, 0xa1, 0xba, 0x9e, 0x34, 0xa1, 0x06, 0x94, 0x3c, 0x57, 0x53, 0xda, 0x4a, 0xa7, 0xda, 0x53,
0x67, 0xa7, 0xad, 0xd2, 0xce, 0x86, 0x5d, 0xf2, 0x5c, 0xb4, 0x0a, 0xaa, 0xef, 0xf4, 0xb1, 0x4f,
0xb5, 0x52, 0xbb, 0xdc, 0xa9, 0x75, 0xef, 0x9b, 0x17, 0xe4, 0x31, 0xcf, 0x19, 0xcc, 0x5d, 0x01,
0xdb, 0x0c, 0x58, 0x34, 0xb5, 0x65, 0x0f, 0xaa, 0xc3, 0x35, 0x6f, 0xec, 0x8c, 0xb0, 0x56, 0xe6,
0xc4, 0x76, 0x9c, 0x20, 0x0d, 0x96, 0xa3, 0x49, 0xc0, 0xf7, 0xd2, 0x2a, 0xe2, 0x79, 0x92, 0xa2,
0x0e, 0x54, 0x68, 0x88, 0x07, 0x9a, 0xda, 0x56, 0x3a, 0xb5, 0x6e, 0xdd, 0x8c, 0xb5, 0x30, 0x13,
0x2d, 0xcc, 0xb5, 0x60, 0x6a, 0x0b, 0x04, 0x32, 0x40, 0x8d, 0x08, 0x61, 0x43, 0xaa, 0x2d, 0x8b,
0x99, 0x61, 0x76, 0xda, 0x52, 0x6d, 0x42, 0xd8, 0xd6, 0x9e, 0x2d, 0x2b, 0x68, 0x1d, 0x60, 0x10,
0x61, 0x87, 0x61, 0xf7, 0xd0, 0x61, 0xda, 0x8a, 0xe0, 0xd4, 0x73, 0x9c, 0xfb, 0x89, 0xbe, 0xbd,
0x95, 0x93, 0xd3, 0xd6, 0xd2, 0xe7, 0x9f, 0x2d, 0xc5, 0xae, 0xca, 0xbe, 0x35, 0xc6, 0x49, 0x26,
0xa1, 0x9b, 0x90, 0x54, 0xff, 0x85, 0x44, 0xf6, 0xad, 0x31, 0xfd, 0x39, 0xd4, 0xe6, 0xe4, 0x41,
0x37, 0xa0, 0x7c, 0x84, 0xa7, 0xb1, 0xda, 0x36, 0x0f, 0xb9, 0x50, 0xc7, 0x8e, 0x3f, 0xc1, 0x5a,
0x29, 0x16, 0x4a, 0x24, 0x2f, 0x4a, 0xcf, 0x14, 0xe3, 0x11, 0xdc, 0xdc, 0xc6, 0xec, 0x5c, 0x66,
0x1b, 0x7f, 0x9c, 0x60, 0xca, 0x16, 0xdd, 0xcb, 0xd8, 0x87, 0xfa, 0x45, 0x38, 0x0d, 0x49, 0x40,
0x31, 0x5a, 0x85, 0xea, 0xf9, 0xe1, 0x44, 0x5b, 0xad, 0xab, 0x2d, 0x3a, 0x65, 0xaf, 0xc2, 0x77,
0xb0, 0xd3, 0x06, 0xc3, 0x82, 0x5b, 0xbb, 0x1e, 0x4d, 0x69, 0x69, 0x3a, 0x86, 0x3a, 0xf4, 0x7c,
0x26, 0x39, 0xab, 0xb6, 0xcc, 0x8c, 0xf7, 0xd0, 0xc8, 0x36, 0xc8, 0x41, 0x5e, 0x01, 0xa4, 0xaf,
0x9c, 0xa6, 0x08, 0x53, 0x5d, 0x36, 0xc9, 0x5c, 0x87, 0xf1, 0x0e, 0x1a, 0xeb, 0xe2, 0x38, 0x39,
0x49, 0xfe, 0x6f, 0xc5, 0x03, 0xb8, 0x9d, 0xe3, 0xbd, 0x12, 0xed, 0xbe, 0x28, 0xd0, 0x78, 0x2b,
0x9c, 0x70, 0xb5, 0x13, 0xa3, 0x97, 0x50, 0x8b, 0x1d, 0x26, 0x3e, 0x1f, 0xc2, 0x39, 0x45, 0xd6,
0xdc, 0xe2, 0x5f, 0x98, 0xd7, 0x0e, 0x3d, 0xb2, 0xa5, 0x91, 0x79, 0xcc, 0xd7, 0xcd, 0x0d, 0x75,
0x25, 0xeb, 0x3e, 0x86, 0xc6, 0x06, 0xf6, 0x71, 0xc1, 0xb6, 0x0b, 0x2c, 0xdb, 0xfd, 0x56, 0x06,
0x48, 0x8d, 0x82, 0xde, 0x40, 0x79, 0x1b, 0x33, 0x64, 0x64, 0x7e, 0xb2, 0xe0, 0x25, 0xd0, 0xef,
0xfd, 0x11, 0x23, 0xd7, 0xd9, 0x83, 0x0a, 0xb7, 0x22, 0xca, 0x7e, 0xb9, 0x0a, 0x0d, 0xad, 0x3f,
0xb8, 0x04, 0x25, 0x49, 0x0f, 0x40, 0x8d, 0xdd, 0x82, 0xb2, 0x0d, 0xc5, 0xe6, 0xd4, 0x1f, 0x5e,
0x06, 0x4b, 0x89, 0xe3, 0xbb, 0xe4, 0x88, 0x8b, 0x3d, 0x94, 0x23, 0x5e, 0x74, 0xd5, 0x6d, 0x50,
0xe3, 0xbb, 0xe4, 0x88, 0x8b, 0xcf, 0xa5, 0x37, 0x72, 0x4e, 0xda, 0xe4, 0x7f, 0x64, 0x3d, 0xed,
0xe4, 0xac, 0xb9, 0xf4, 0xe3, 0xac, 0xb9, 0xf4, 0x69, 0xd6, 0x54, 0x4e, 0x66, 0x4d, 0xe5, 0xfb,
0xac, 0xa9, 0xfc, 0x9a, 0x35, 0x95, 0xbe, 0x2a, 0x90, 0x4f, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff,
0xc1, 0x18, 0xeb, 0x02, 0x8d, 0x07, 0x00, 0x00,
}

View File

@ -6,6 +6,7 @@ import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";
import "github.com/containerd/containerd/api/types/descriptor/descriptor.proto";
// Containers provides metadata storage for containers used in the execution
@ -65,6 +66,9 @@ message Container {
//
// This field may be updated.
string rootfs = 7 [(gogoproto.customname) = "RootFS"];
google.protobuf.Timestamp created_at = 8 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
google.protobuf.Timestamp updated_at = 9 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
}
message GetContainerRequest {

View File

@ -14,6 +14,7 @@
StartRequest
DeleteRequest
DeleteResponse
DeleteProcessRequest
InfoRequest
InfoResponse
ListRequest
@ -133,13 +134,22 @@ func (m *DeleteResponse) Reset() { *m = DeleteResponse{} }
func (*DeleteResponse) ProtoMessage() {}
func (*DeleteResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{4} }
type DeleteProcessRequest struct {
ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"`
}
func (m *DeleteProcessRequest) Reset() { *m = DeleteProcessRequest{} }
func (*DeleteProcessRequest) ProtoMessage() {}
func (*DeleteProcessRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{5} }
type InfoRequest struct {
ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
}
func (m *InfoRequest) Reset() { *m = InfoRequest{} }
func (*InfoRequest) ProtoMessage() {}
func (*InfoRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{5} }
func (*InfoRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{6} }
type InfoResponse struct {
Task *containerd_v1_types2.Task `protobuf:"bytes,1,opt,name=task" json:"task,omitempty"`
@ -147,14 +157,14 @@ type InfoResponse struct {
func (m *InfoResponse) Reset() { *m = InfoResponse{} }
func (*InfoResponse) ProtoMessage() {}
func (*InfoResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{6} }
func (*InfoResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{7} }
type ListRequest struct {
}
func (m *ListRequest) Reset() { *m = ListRequest{} }
func (*ListRequest) ProtoMessage() {}
func (*ListRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{7} }
func (*ListRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{8} }
type ListResponse struct {
Tasks []*containerd_v1_types2.Task `protobuf:"bytes,1,rep,name=tasks" json:"tasks,omitempty"`
@ -162,7 +172,7 @@ type ListResponse struct {
func (m *ListResponse) Reset() { *m = ListResponse{} }
func (*ListResponse) ProtoMessage() {}
func (*ListResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{8} }
func (*ListResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{9} }
type KillRequest struct {
ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
@ -175,7 +185,7 @@ type KillRequest struct {
func (m *KillRequest) Reset() { *m = KillRequest{} }
func (*KillRequest) ProtoMessage() {}
func (*KillRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{9} }
func (*KillRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{10} }
type isKillRequest_PidOrAll interface {
isKillRequest_PidOrAll()
@ -287,7 +297,7 @@ type EventsRequest struct {
func (m *EventsRequest) Reset() { *m = EventsRequest{} }
func (*EventsRequest) ProtoMessage() {}
func (*EventsRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{10} }
func (*EventsRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{11} }
type ExecRequest struct {
// ContainerID specifies the container in which to exec the process.
@ -304,7 +314,7 @@ type ExecRequest struct {
func (m *ExecRequest) Reset() { *m = ExecRequest{} }
func (*ExecRequest) ProtoMessage() {}
func (*ExecRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{11} }
func (*ExecRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{12} }
type ExecResponse struct {
Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"`
@ -312,7 +322,7 @@ type ExecResponse struct {
func (m *ExecResponse) Reset() { *m = ExecResponse{} }
func (*ExecResponse) ProtoMessage() {}
func (*ExecResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{12} }
func (*ExecResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{13} }
type PtyRequest struct {
ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
@ -323,7 +333,7 @@ type PtyRequest struct {
func (m *PtyRequest) Reset() { *m = PtyRequest{} }
func (*PtyRequest) ProtoMessage() {}
func (*PtyRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{13} }
func (*PtyRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{14} }
type CloseStdinRequest struct {
ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
@ -332,7 +342,7 @@ type CloseStdinRequest struct {
func (m *CloseStdinRequest) Reset() { *m = CloseStdinRequest{} }
func (*CloseStdinRequest) ProtoMessage() {}
func (*CloseStdinRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{14} }
func (*CloseStdinRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{15} }
type PauseRequest struct {
ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
@ -340,7 +350,7 @@ type PauseRequest struct {
func (m *PauseRequest) Reset() { *m = PauseRequest{} }
func (*PauseRequest) ProtoMessage() {}
func (*PauseRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{15} }
func (*PauseRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{16} }
type ResumeRequest struct {
ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
@ -348,7 +358,7 @@ type ResumeRequest struct {
func (m *ResumeRequest) Reset() { *m = ResumeRequest{} }
func (*ResumeRequest) ProtoMessage() {}
func (*ResumeRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{16} }
func (*ResumeRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{17} }
type ProcessesRequest struct {
ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
@ -356,7 +366,7 @@ type ProcessesRequest struct {
func (m *ProcessesRequest) Reset() { *m = ProcessesRequest{} }
func (*ProcessesRequest) ProtoMessage() {}
func (*ProcessesRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{17} }
func (*ProcessesRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{18} }
type ProcessesResponse struct {
Processes []*containerd_v1_types2.Process `protobuf:"bytes,1,rep,name=processes" json:"processes,omitempty"`
@ -364,7 +374,7 @@ type ProcessesResponse struct {
func (m *ProcessesResponse) Reset() { *m = ProcessesResponse{} }
func (*ProcessesResponse) ProtoMessage() {}
func (*ProcessesResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{18} }
func (*ProcessesResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{19} }
type CheckpointRequest struct {
ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
@ -379,7 +389,7 @@ type CheckpointRequest struct {
func (m *CheckpointRequest) Reset() { *m = CheckpointRequest{} }
func (*CheckpointRequest) ProtoMessage() {}
func (*CheckpointRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{19} }
func (*CheckpointRequest) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{20} }
type CheckpointResponse struct {
Descriptors []*containerd_v1_types1.Descriptor `protobuf:"bytes,1,rep,name=descriptors" json:"descriptors,omitempty"`
@ -387,7 +397,7 @@ type CheckpointResponse struct {
func (m *CheckpointResponse) Reset() { *m = CheckpointResponse{} }
func (*CheckpointResponse) ProtoMessage() {}
func (*CheckpointResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{20} }
func (*CheckpointResponse) Descriptor() ([]byte, []int) { return fileDescriptorExecution, []int{21} }
func init() {
proto.RegisterType((*CreateRequest)(nil), "containerd.v1.services.execution.CreateRequest")
@ -395,6 +405,7 @@ func init() {
proto.RegisterType((*StartRequest)(nil), "containerd.v1.services.execution.StartRequest")
proto.RegisterType((*DeleteRequest)(nil), "containerd.v1.services.execution.DeleteRequest")
proto.RegisterType((*DeleteResponse)(nil), "containerd.v1.services.execution.DeleteResponse")
proto.RegisterType((*DeleteProcessRequest)(nil), "containerd.v1.services.execution.DeleteProcessRequest")
proto.RegisterType((*InfoRequest)(nil), "containerd.v1.services.execution.InfoRequest")
proto.RegisterType((*InfoResponse)(nil), "containerd.v1.services.execution.InfoResponse")
proto.RegisterType((*ListRequest)(nil), "containerd.v1.services.execution.ListRequest")
@ -427,6 +438,7 @@ type TasksClient interface {
Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error)
Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error)
Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error)
DeleteProcess(ctx context.Context, in *DeleteProcessRequest, opts ...grpc.CallOption) (*DeleteResponse, error)
Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error)
List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error)
Kill(ctx context.Context, in *KillRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error)
@ -475,6 +487,15 @@ func (c *tasksClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grp
return out, nil
}
func (c *tasksClient) DeleteProcess(ctx context.Context, in *DeleteProcessRequest, opts ...grpc.CallOption) (*DeleteResponse, error) {
out := new(DeleteResponse)
err := grpc.Invoke(ctx, "/containerd.v1.services.execution.Tasks/DeleteProcess", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tasksClient) Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error) {
out := new(InfoResponse)
err := grpc.Invoke(ctx, "/containerd.v1.services.execution.Tasks/Info", in, out, c.cc, opts...)
@ -603,6 +624,7 @@ type TasksServer interface {
Create(context.Context, *CreateRequest) (*CreateResponse, error)
Start(context.Context, *StartRequest) (*google_protobuf.Empty, error)
Delete(context.Context, *DeleteRequest) (*DeleteResponse, error)
DeleteProcess(context.Context, *DeleteProcessRequest) (*DeleteResponse, error)
Info(context.Context, *InfoRequest) (*InfoResponse, error)
List(context.Context, *ListRequest) (*ListResponse, error)
Kill(context.Context, *KillRequest) (*google_protobuf.Empty, error)
@ -674,6 +696,24 @@ func _Tasks_Delete_Handler(srv interface{}, ctx context.Context, dec func(interf
return interceptor(ctx, in, info, handler)
}
func _Tasks_DeleteProcess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteProcessRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TasksServer).DeleteProcess(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/containerd.v1.services.execution.Tasks/DeleteProcess",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TasksServer).DeleteProcess(ctx, req.(*DeleteProcessRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Tasks_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(InfoRequest)
if err := dec(in); err != nil {
@ -891,6 +931,10 @@ var _Tasks_serviceDesc = grpc.ServiceDesc{
MethodName: "Delete",
Handler: _Tasks_Delete_Handler,
},
{
MethodName: "DeleteProcess",
Handler: _Tasks_DeleteProcess_Handler,
},
{
MethodName: "Info",
Handler: _Tasks_Info_Handler,
@ -1130,6 +1174,35 @@ func (m *DeleteResponse) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *DeleteProcessRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *DeleteProcessRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.ContainerID) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintExecution(dAtA, i, uint64(len(m.ContainerID)))
i += copy(dAtA[i:], m.ContainerID)
}
if m.Pid != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintExecution(dAtA, i, uint64(m.Pid))
}
return i, nil
}
func (m *InfoRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@ -1793,6 +1866,19 @@ func (m *DeleteResponse) Size() (n int) {
return n
}
func (m *DeleteProcessRequest) Size() (n int) {
var l int
_ = l
l = len(m.ContainerID)
if l > 0 {
n += 1 + l + sovExecution(uint64(l))
}
if m.Pid != 0 {
n += 1 + sovExecution(uint64(m.Pid))
}
return n
}
func (m *InfoRequest) Size() (n int) {
var l int
_ = l
@ -2096,6 +2182,17 @@ func (this *DeleteResponse) String() string {
}, "")
return s
}
func (this *DeleteProcessRequest) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&DeleteProcessRequest{`,
`ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`,
`Pid:` + fmt.Sprintf("%v", this.Pid) + `,`,
`}`,
}, "")
return s
}
func (this *InfoRequest) String() string {
if this == nil {
return "nil"
@ -2934,6 +3031,104 @@ func (m *DeleteResponse) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *DeleteProcessRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowExecution
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: DeleteProcessRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: DeleteProcessRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ContainerID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowExecution
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthExecution
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ContainerID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Pid", wireType)
}
m.Pid = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowExecution
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Pid |= (uint32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipExecution(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthExecution
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *InfoRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@ -4684,81 +4879,83 @@ func init() {
}
var fileDescriptorExecution = []byte{
// 1209 bytes of a gzipped FileDescriptorProto
// 1242 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x6e, 0xdb, 0xc6,
0x13, 0x37, 0xad, 0x8f, 0xbf, 0x34, 0x94, 0x12, 0x7b, 0x11, 0x04, 0x8a, 0xf2, 0xaf, 0x24, 0x10,
0x28, 0xa0, 0x16, 0x09, 0x95, 0xca, 0x3d, 0x05, 0x2d, 0x02, 0xcb, 0x76, 0x5a, 0x23, 0x49, 0xed,
0xd2, 0x6e, 0x83, 0x9c, 0x04, 0x9a, 0x5c, 0xcb, 0x0b, 0x51, 0x5c, 0x96, 0xbb, 0xf2, 0xc7, 0x2d,
0x6f, 0xd0, 0x9e, 0xfb, 0x04, 0x7d, 0x14, 0xa3, 0x40, 0x81, 0x1e, 0x8b, 0x1e, 0xdc, 0xc6, 0x4f,
0xd1, 0x63, 0xb1, 0xcb, 0x25, 0x45, 0x29, 0x56, 0x45, 0x57, 0xbd, 0x48, 0xbb, 0xc3, 0x99, 0xdf,
0xce, 0xc7, 0xce, 0xfc, 0x16, 0xbe, 0x18, 0x10, 0x7e, 0x32, 0x3e, 0x32, 0x1d, 0x3a, 0xea, 0x38,
0xd4, 0xe7, 0x36, 0xf1, 0x71, 0xe8, 0xa6, 0x97, 0x76, 0x40, 0x3a, 0x0c, 0x87, 0xa7, 0xc4, 0xc1,
0xac, 0x83, 0xcf, 0xb1, 0x33, 0xe6, 0x84, 0xfa, 0x93, 0x95, 0x19, 0x84, 0x94, 0x53, 0xd4, 0x9a,
0x98, 0x98, 0xa7, 0x9f, 0x98, 0xb1, 0x85, 0x99, 0xe8, 0xd5, 0x1f, 0x0e, 0x28, 0x1d, 0x78, 0xb8,
0x23, 0xf5, 0x8f, 0xc6, 0xc7, 0x1d, 0x3c, 0x0a, 0xf8, 0x45, 0x64, 0x5e, 0x7f, 0x30, 0xfb, 0xd1,
0xf6, 0xe3, 0x4f, 0xf7, 0x06, 0x74, 0x40, 0xe5, 0xb2, 0x23, 0x56, 0x4a, 0xfa, 0x59, 0x26, 0xc7,
0xf9, 0x45, 0x80, 0x59, 0x67, 0x44, 0xc7, 0x3e, 0x8f, 0x7e, 0x95, 0xf5, 0xf3, 0x5b, 0x58, 0xbb,
0x98, 0x39, 0x21, 0x09, 0x38, 0x0d, 0x53, 0x4b, 0x85, 0xf3, 0xf4, 0x16, 0x38, 0xdc, 0x66, 0x43,
0xf9, 0xa3, 0x6c, 0x9b, 0xb3, 0x21, 0x73, 0x32, 0xc2, 0x8c, 0xdb, 0xa3, 0x20, 0x52, 0x30, 0x7e,
0x5c, 0x85, 0xea, 0x56, 0x88, 0x6d, 0x8e, 0x2d, 0xfc, 0xdd, 0x18, 0x33, 0x8e, 0xba, 0x50, 0x49,
0xa0, 0xfb, 0xc4, 0xad, 0xad, 0xb6, 0xb4, 0x76, 0xb9, 0x77, 0xf7, 0xfa, 0xaa, 0xa9, 0x6f, 0xc5,
0xf2, 0xdd, 0x6d, 0x4b, 0x4f, 0x94, 0x76, 0x5d, 0xd4, 0x85, 0x62, 0x48, 0x29, 0x3f, 0x66, 0xb5,
0x5c, 0x2b, 0xd7, 0xd6, 0xbb, 0x75, 0x73, 0xba, 0x52, 0xd2, 0x39, 0xf3, 0x95, 0x48, 0x8e, 0xa5,
0x34, 0xd1, 0x3d, 0x28, 0x30, 0xee, 0x12, 0xbf, 0x56, 0x10, 0x07, 0x58, 0xd1, 0x06, 0xdd, 0x87,
0x22, 0xe3, 0x2e, 0x1d, 0xf3, 0x5a, 0x51, 0x8a, 0xd5, 0x4e, 0xc9, 0x71, 0x18, 0xd6, 0xfe, 0x97,
0xc8, 0x71, 0x18, 0xa2, 0x3a, 0x94, 0x38, 0x0e, 0x47, 0xc4, 0xb7, 0xbd, 0x5a, 0xa9, 0xa5, 0xb5,
0x4b, 0x56, 0xb2, 0x47, 0xcf, 0x00, 0x9c, 0x13, 0xec, 0x0c, 0x03, 0x4a, 0x7c, 0x5e, 0x2b, 0xb7,
0xb4, 0xb6, 0xde, 0x6d, 0xde, 0xe8, 0xd9, 0x76, 0x92, 0x73, 0x2b, 0x65, 0x62, 0x7c, 0x0b, 0x77,
0xe2, 0xdc, 0xb0, 0x80, 0xfa, 0x0c, 0xff, 0xab, 0xe4, 0xac, 0x41, 0x2e, 0x20, 0x6e, 0x2d, 0xd7,
0xd2, 0xda, 0x55, 0x4b, 0x2c, 0x8d, 0x1e, 0x54, 0x0e, 0xb8, 0x1d, 0xf2, 0x79, 0x29, 0xd7, 0x16,
0xa3, 0x1a, 0x5b, 0x50, 0xdd, 0xc6, 0x1e, 0x9e, 0x5f, 0xb7, 0x2c, 0x20, 0x3f, 0x69, 0x70, 0x27,
0x46, 0x99, 0x13, 0x61, 0x06, 0x18, 0xd4, 0x04, 0x1d, 0x9f, 0x13, 0xde, 0x67, 0xdc, 0xe6, 0x63,
0x26, 0x93, 0x52, 0xb5, 0x40, 0x88, 0x0e, 0xa4, 0x04, 0x6d, 0x42, 0x59, 0xec, 0xb0, 0xdb, 0xb7,
0xb9, 0x4c, 0x84, 0xb8, 0x22, 0xd1, 0xd5, 0x34, 0xe3, 0xab, 0x69, 0x1e, 0xc6, 0x57, 0xb3, 0x57,
0xba, 0xbc, 0x6a, 0xae, 0xfc, 0xf0, 0x47, 0x53, 0xb3, 0x4a, 0x91, 0xd9, 0x26, 0x37, 0x36, 0x41,
0xdf, 0xf5, 0x8f, 0xe9, 0x32, 0xd1, 0x7e, 0x0e, 0x95, 0x08, 0x42, 0x85, 0xfa, 0x18, 0xf2, 0xa2,
0x55, 0xa4, 0xad, 0xde, 0x7d, 0x70, 0xe3, 0xcd, 0x38, 0xb4, 0xd9, 0xd0, 0x92, 0x6a, 0x46, 0x15,
0xf4, 0x97, 0x84, 0xc5, 0x45, 0x33, 0x9e, 0x41, 0x25, 0xda, 0x2a, 0xb4, 0x0e, 0x14, 0x84, 0x1a,
0xab, 0x69, 0xb2, 0x05, 0xfe, 0x01, 0x2e, 0xd2, 0x33, 0xbe, 0xd7, 0x40, 0x7f, 0x41, 0x3c, 0x6f,
0x89, 0x90, 0x64, 0x5b, 0x90, 0x81, 0xb8, 0xfc, 0x51, 0xd2, 0xd5, 0x0e, 0x21, 0xc8, 0xd9, 0x9e,
0x27, 0x53, 0x5d, 0xfa, 0x72, 0xc5, 0x12, 0x1b, 0x21, 0x13, 0xf7, 0x30, 0x2f, 0x14, 0x85, 0x2c,
0x20, 0x6e, 0xaf, 0x02, 0x10, 0x10, 0xb7, 0x4f, 0xc3, 0xbe, 0xed, 0x79, 0xc6, 0x5d, 0xa8, 0xee,
0x9c, 0x62, 0x9f, 0xb3, 0x38, 0xc6, 0x5f, 0x34, 0xd0, 0x77, 0xce, 0xb1, 0xb3, 0x8c, 0x8b, 0xe9,
0x0e, 0x5d, 0x9d, 0xe9, 0xd0, 0x64, 0x06, 0xe4, 0x6e, 0x9e, 0x01, 0xf9, 0x39, 0x33, 0xa0, 0x30,
0x35, 0x03, 0xda, 0x90, 0x67, 0x01, 0x76, 0xe4, 0xc4, 0xd0, 0xbb, 0xf7, 0xde, 0xbb, 0x58, 0x9b,
0xfe, 0x85, 0x25, 0x35, 0x8c, 0x16, 0x54, 0xa2, 0x70, 0x54, 0xcd, 0x54, 0x6b, 0x6a, 0x93, 0xd6,
0x7c, 0xab, 0x01, 0xec, 0xf3, 0x8b, 0x65, 0x02, 0x56, 0xa0, 0xab, 0x09, 0xa8, 0x08, 0xf3, 0x8c,
0xb8, 0xfc, 0x44, 0xcd, 0x80, 0x68, 0x23, 0xc2, 0x39, 0xc1, 0x64, 0x70, 0x12, 0x85, 0x59, 0xb5,
0xd4, 0xce, 0x78, 0x03, 0xeb, 0x5b, 0x1e, 0x65, 0xf8, 0x40, 0x24, 0xe3, 0x3f, 0x75, 0x44, 0x0c,
0x9e, 0x7d, 0x7b, 0xcc, 0xf0, 0x92, 0x83, 0xc7, 0xc2, 0x6c, 0x3c, 0x5a, 0x0a, 0xe4, 0x39, 0xac,
0xed, 0x87, 0xd4, 0xc1, 0x8c, 0x61, 0xb6, 0x0c, 0xce, 0x1e, 0xac, 0xa7, 0x70, 0x54, 0x55, 0x9f,
0x42, 0x39, 0x88, 0x85, 0xaa, 0x1b, 0xff, 0x7f, 0x63, 0x37, 0x2a, 0x53, 0x6b, 0xa2, 0x6e, 0xfc,
0xb5, 0x0a, 0xeb, 0x5b, 0x09, 0x03, 0x2c, 0x93, 0xfd, 0x87, 0x50, 0xb6, 0x3d, 0x8f, 0x9e, 0xf5,
0xb9, 0x13, 0xc4, 0x17, 0x5f, 0x0a, 0x0e, 0x9d, 0x00, 0x3d, 0x02, 0x14, 0x7d, 0x1c, 0xfb, 0xe4,
0xbc, 0xcf, 0xa8, 0x33, 0xc4, 0x9c, 0x45, 0xed, 0x6a, 0xad, 0xc9, 0x2f, 0xdf, 0xf8, 0xe4, 0xfc,
0x20, 0x92, 0xa3, 0x0f, 0xe1, 0x8e, 0x82, 0x8a, 0x1b, 0x29, 0x2f, 0x35, 0xab, 0x11, 0x5e, 0xdc,
0x4d, 0x1f, 0x00, 0x1c, 0x13, 0x0f, 0xf7, 0x3d, 0xea, 0x0c, 0x99, 0xec, 0x91, 0x92, 0x55, 0x16,
0x92, 0x97, 0x42, 0x80, 0x3e, 0x82, 0x35, 0xf9, 0x1a, 0xea, 0xfb, 0xf6, 0x08, 0xb3, 0xc0, 0x76,
0x30, 0xab, 0x15, 0x5b, 0xb9, 0x76, 0xd9, 0xba, 0x2b, 0xe5, 0x5f, 0x25, 0x62, 0xd4, 0x87, 0xf5,
0xc0, 0x0e, 0xb1, 0xcf, 0xfb, 0x29, 0x02, 0x95, 0xc4, 0xdb, 0xeb, 0x8a, 0xd9, 0xfc, 0xfb, 0x55,
0xf3, 0xe3, 0xd4, 0xab, 0x84, 0x06, 0xd8, 0x4f, 0x42, 0x67, 0x9d, 0x01, 0x7d, 0xec, 0x92, 0x01,
0x66, 0xdc, 0xdc, 0x96, 0x7f, 0xd6, 0x5a, 0x04, 0x36, 0xc9, 0x2b, 0x42, 0x90, 0x17, 0x93, 0x5d,
0x51, 0xb6, 0x5c, 0x1b, 0xaf, 0x01, 0xa5, 0x33, 0xaf, 0x8a, 0xb9, 0x09, 0xfa, 0xe4, 0x45, 0x14,
0x97, 0x73, 0x21, 0x8b, 0xa7, 0x6d, 0xba, 0x3f, 0x03, 0x14, 0xc4, 0xe0, 0x65, 0x68, 0x08, 0xc5,
0x88, 0xd0, 0x51, 0xc7, 0x5c, 0xf4, 0x96, 0x34, 0xa7, 0x9e, 0x45, 0xf5, 0x27, 0xd9, 0x0d, 0x94,
0xe7, 0x7b, 0x50, 0x90, 0x2c, 0x8f, 0xcc, 0xc5, 0xa6, 0xe9, 0xe7, 0x40, 0xfd, 0xfe, 0x7b, 0x13,
0x6c, 0x47, 0xd4, 0x47, 0x78, 0x1f, 0x91, 0x75, 0x16, 0xef, 0xa7, 0x1e, 0x07, 0x59, 0xbc, 0x9f,
0x79, 0x07, 0x60, 0xc8, 0x0b, 0xb2, 0x44, 0x8f, 0x17, 0x5b, 0xa6, 0x78, 0xb9, 0x6e, 0x66, 0x55,
0x9f, 0x1c, 0x23, 0x58, 0x34, 0xcb, 0x31, 0x29, 0xf2, 0xcd, 0x72, 0xcc, 0x14, 0x39, 0xbf, 0x82,
0xbc, 0xa0, 0xda, 0x2c, 0xc7, 0xa4, 0x28, 0x79, 0x6e, 0x25, 0x5e, 0x43, 0x31, 0x22, 0xca, 0x2c,
0x95, 0x98, 0xa2, 0xd4, 0xfa, 0xcd, 0x4f, 0x63, 0xa9, 0xf3, 0x44, 0x13, 0xe9, 0x10, 0x04, 0x95,
0xc5, 0xcf, 0x14, 0x2f, 0x67, 0x49, 0xc7, 0x14, 0xef, 0xbd, 0x80, 0xdc, 0x3e, 0xbf, 0x40, 0x8f,
0x16, 0x9b, 0x4d, 0xb8, 0x70, 0x6e, 0x32, 0xde, 0x00, 0x4c, 0xf8, 0x0a, 0x6d, 0x64, 0xe8, 0x93,
0x59, 0x76, 0x9b, 0x0b, 0xbd, 0x07, 0x05, 0xc9, 0x57, 0x59, 0x5a, 0x28, 0x4d, 0x6c, 0x73, 0x01,
0xbf, 0x86, 0x62, 0x44, 0x5e, 0x59, 0x0a, 0x37, 0x45, 0x73, 0x73, 0x21, 0x39, 0x94, 0x13, 0x0a,
0x42, 0xdd, 0x0c, 0x7e, 0xce, 0xf0, 0x5e, 0x7d, 0xe3, 0x56, 0x36, 0xaa, 0x82, 0x67, 0x00, 0xa9,
0x71, 0x9a, 0x25, 0xe9, 0xb3, 0xa4, 0x56, 0xff, 0xf4, 0x76, 0x46, 0xd1, 0xc1, 0xbd, 0xda, 0xe5,
0xbb, 0xc6, 0xca, 0x6f, 0xef, 0x1a, 0x2b, 0x6f, 0xaf, 0x1b, 0xda, 0xe5, 0x75, 0x43, 0xfb, 0xf5,
0xba, 0xa1, 0xfd, 0x79, 0xdd, 0xd0, 0x8e, 0x8a, 0x32, 0x31, 0x1b, 0x7f, 0x07, 0x00, 0x00, 0xff,
0xff, 0x7f, 0x76, 0x43, 0x00, 0xef, 0x0f, 0x00, 0x00,
0x13, 0x37, 0xad, 0x8f, 0xbf, 0x34, 0x94, 0x12, 0x7b, 0x61, 0x04, 0x8a, 0xf2, 0xaf, 0x24, 0x10,
0x28, 0xa0, 0x16, 0x09, 0x95, 0x2a, 0x45, 0x0f, 0x41, 0x8b, 0xc0, 0xb2, 0x9d, 0xd6, 0x48, 0x52,
0xbb, 0xb4, 0xdb, 0x20, 0x40, 0x01, 0x81, 0x26, 0xd7, 0xf2, 0x42, 0x14, 0x97, 0xe5, 0xae, 0x6c,
0xeb, 0x96, 0x37, 0x68, 0xcf, 0x7d, 0x82, 0xbe, 0x48, 0x01, 0x5f, 0x0a, 0xf4, 0x58, 0xf4, 0xe0,
0x36, 0x7e, 0x8a, 0x1e, 0x8b, 0xdd, 0x25, 0x25, 0x4a, 0xb1, 0x2a, 0x3a, 0xca, 0x45, 0xda, 0x1d,
0xce, 0xcc, 0xee, 0xfe, 0xe6, 0xe3, 0x37, 0xf0, 0x65, 0x8f, 0xf0, 0x93, 0xe1, 0x91, 0xe9, 0xd0,
0x41, 0xcb, 0xa1, 0x3e, 0xb7, 0x89, 0x8f, 0x43, 0x37, 0xb9, 0xb4, 0x03, 0xd2, 0x62, 0x38, 0x3c,
0x25, 0x0e, 0x66, 0x2d, 0x7c, 0x8e, 0x9d, 0x21, 0x27, 0xd4, 0x9f, 0xac, 0xcc, 0x20, 0xa4, 0x9c,
0xa2, 0xc6, 0xc4, 0xc4, 0x3c, 0xfd, 0xc4, 0x8c, 0x2d, 0xcc, 0xb1, 0x5e, 0xf5, 0x5e, 0x8f, 0xd2,
0x9e, 0x87, 0x5b, 0x52, 0xff, 0x68, 0x78, 0xdc, 0xc2, 0x83, 0x80, 0x8f, 0x94, 0x79, 0xf5, 0xee,
0xec, 0x47, 0xdb, 0x8f, 0x3f, 0x6d, 0xf4, 0x68, 0x8f, 0xca, 0x65, 0x4b, 0xac, 0x22, 0xe9, 0xe7,
0xa9, 0x2e, 0xce, 0x47, 0x01, 0x66, 0xad, 0x01, 0x1d, 0xfa, 0x5c, 0xfd, 0x46, 0xd6, 0x4f, 0x6f,
0x60, 0xed, 0x62, 0xe6, 0x84, 0x24, 0xe0, 0x34, 0x4c, 0x2c, 0x23, 0x3f, 0x8f, 0x6f, 0xe0, 0x87,
0xdb, 0xac, 0x2f, 0x7f, 0x22, 0xdb, 0xfa, 0xec, 0x93, 0x39, 0x19, 0x60, 0xc6, 0xed, 0x41, 0xa0,
0x14, 0x8c, 0x9f, 0x57, 0xa1, 0xbc, 0x15, 0x62, 0x9b, 0x63, 0x0b, 0xff, 0x30, 0xc4, 0x8c, 0xa3,
0x36, 0x94, 0xc6, 0xae, 0xbb, 0xc4, 0xad, 0xac, 0x36, 0xb4, 0x66, 0xb1, 0x73, 0xfb, 0xea, 0xb2,
0xae, 0x6f, 0xc5, 0xf2, 0xdd, 0x6d, 0x4b, 0x1f, 0x2b, 0xed, 0xba, 0xa8, 0x0d, 0xf9, 0x90, 0x52,
0x7e, 0xcc, 0x2a, 0x99, 0x46, 0xa6, 0xa9, 0xb7, 0xab, 0xe6, 0x74, 0xa4, 0xe4, 0xe5, 0xcc, 0x17,
0x02, 0x1c, 0x2b, 0xd2, 0x44, 0x1b, 0x90, 0x63, 0xdc, 0x25, 0x7e, 0x25, 0x27, 0x0e, 0xb0, 0xd4,
0x06, 0xdd, 0x81, 0x3c, 0xe3, 0x2e, 0x1d, 0xf2, 0x4a, 0x5e, 0x8a, 0xa3, 0x5d, 0x24, 0xc7, 0x61,
0x58, 0xf9, 0xdf, 0x58, 0x8e, 0xc3, 0x10, 0x55, 0xa1, 0xc0, 0x71, 0x38, 0x20, 0xbe, 0xed, 0x55,
0x0a, 0x0d, 0xad, 0x59, 0xb0, 0xc6, 0x7b, 0xf4, 0x04, 0xc0, 0x39, 0xc1, 0x4e, 0x3f, 0xa0, 0xc4,
0xe7, 0x95, 0x62, 0x43, 0x6b, 0xea, 0xed, 0xfa, 0xb5, 0x37, 0xdb, 0x1e, 0x63, 0x6e, 0x25, 0x4c,
0x8c, 0xef, 0xe0, 0x56, 0x8c, 0x0d, 0x0b, 0xa8, 0xcf, 0xf0, 0x3b, 0x81, 0xb3, 0x06, 0x99, 0x80,
0xb8, 0x95, 0x4c, 0x43, 0x6b, 0x96, 0x2d, 0xb1, 0x34, 0x3a, 0x50, 0x3a, 0xe0, 0x76, 0xc8, 0xe7,
0x41, 0xae, 0x2d, 0xf6, 0x6a, 0x6c, 0x41, 0x79, 0x1b, 0x7b, 0x78, 0x7e, 0xdc, 0xd2, 0x38, 0xf9,
0x45, 0x83, 0x5b, 0xb1, 0x97, 0x39, 0x2f, 0x4c, 0xe1, 0x06, 0xd5, 0x41, 0xc7, 0xe7, 0x84, 0x77,
0x19, 0xb7, 0xf9, 0x90, 0x49, 0x50, 0xca, 0x16, 0x08, 0xd1, 0x81, 0x94, 0xa0, 0x4d, 0x28, 0x8a,
0x1d, 0x76, 0xbb, 0x36, 0x97, 0x40, 0x88, 0x14, 0x51, 0xa9, 0x69, 0xc6, 0xa9, 0x69, 0x1e, 0xc6,
0xa9, 0xd9, 0x29, 0x5c, 0x5c, 0xd6, 0x57, 0x7e, 0xfa, 0xab, 0xae, 0x59, 0x05, 0x65, 0xb6, 0xc9,
0x8d, 0xef, 0x61, 0x43, 0xdd, 0x74, 0x3f, 0xa4, 0x0e, 0x66, 0x6c, 0x89, 0x67, 0xc7, 0x11, 0x59,
0x9d, 0x44, 0x64, 0x13, 0xf4, 0x5d, 0xff, 0x98, 0x2e, 0x83, 0xe5, 0x17, 0x50, 0x52, 0x2e, 0x22,
0x20, 0x1f, 0x40, 0x56, 0x14, 0xa2, 0xb4, 0xd5, 0xdb, 0x77, 0xaf, 0xcd, 0xbb, 0x43, 0x9b, 0xf5,
0x2d, 0xa9, 0x66, 0x94, 0x41, 0x7f, 0x4e, 0x58, 0x9c, 0x12, 0xc6, 0x13, 0x28, 0xa9, 0x6d, 0xe4,
0xad, 0x05, 0x39, 0xa1, 0xc6, 0x2a, 0x9a, 0x2c, 0xb0, 0xff, 0x70, 0xa7, 0xf4, 0x8c, 0x1f, 0x35,
0xd0, 0x9f, 0x11, 0xcf, 0x5b, 0x06, 0x27, 0x51, 0x74, 0xa4, 0x27, 0x4a, 0x4b, 0x41, 0x15, 0xed,
0x10, 0x82, 0x8c, 0xed, 0x79, 0x32, 0x90, 0x85, 0xaf, 0x56, 0x2c, 0xb1, 0x11, 0x32, 0x81, 0x69,
0x56, 0x28, 0x0a, 0x59, 0x40, 0xdc, 0x4e, 0x09, 0x20, 0x20, 0x6e, 0x97, 0x86, 0x5d, 0xdb, 0xf3,
0x8c, 0xdb, 0x50, 0xde, 0x39, 0xc5, 0x3e, 0x8f, 0x43, 0x67, 0xfc, 0xa6, 0x81, 0xbe, 0x73, 0x8e,
0x9d, 0x65, 0xae, 0x98, 0xac, 0xff, 0xd5, 0x99, 0xfa, 0x1f, 0x77, 0x98, 0xcc, 0xf5, 0x1d, 0x26,
0x3b, 0xa7, 0xc3, 0xe4, 0xa6, 0x3a, 0x4c, 0x13, 0xb2, 0x2c, 0xc0, 0x8e, 0xec, 0x47, 0x7a, 0x7b,
0xe3, 0xad, 0xb4, 0xdd, 0xf4, 0x47, 0x96, 0xd4, 0x30, 0x1a, 0x50, 0x52, 0xcf, 0x89, 0x62, 0x16,
0xa5, 0x99, 0x36, 0x49, 0xb3, 0xd7, 0x1a, 0xc0, 0x3e, 0x1f, 0xbd, 0xd7, 0xdc, 0x15, 0xcf, 0x3c,
0x23, 0x2e, 0x3f, 0x89, 0x3a, 0x8c, 0xda, 0x88, 0xe7, 0x9c, 0x60, 0xd2, 0x3b, 0x51, 0xcf, 0x2c,
0x5b, 0xd1, 0xce, 0x78, 0x05, 0xeb, 0x5b, 0x1e, 0x65, 0xf8, 0x40, 0x80, 0xf1, 0x7e, 0x8b, 0xa8,
0x03, 0xa5, 0x7d, 0x7b, 0xc8, 0xf0, 0x92, 0x6d, 0xcd, 0xc2, 0x6c, 0x38, 0x58, 0xca, 0xc9, 0x53,
0x58, 0x8b, 0xba, 0x04, 0x5e, 0xa6, 0x4f, 0x18, 0x7b, 0xb0, 0x9e, 0xf0, 0x13, 0x45, 0xf5, 0x31,
0x14, 0x83, 0x58, 0x18, 0x55, 0xe3, 0xff, 0xaf, 0xad, 0xc6, 0xb8, 0x51, 0x4d, 0xd4, 0x8d, 0x7f,
0x56, 0x61, 0x7d, 0x6b, 0xcc, 0x2f, 0xcb, 0xa0, 0x7f, 0x0f, 0x8a, 0xb6, 0xe7, 0xd1, 0xb3, 0x2e,
0x77, 0x82, 0x38, 0xf1, 0xa5, 0xe0, 0xd0, 0x09, 0xd0, 0x7d, 0x40, 0xea, 0xe3, 0xd0, 0x27, 0xe7,
0x5d, 0x46, 0x9d, 0x3e, 0xe6, 0x4c, 0x95, 0xab, 0xb5, 0x26, 0xbf, 0x7c, 0xeb, 0x93, 0xf3, 0x03,
0x25, 0x47, 0x1f, 0xc2, 0xad, 0xc8, 0x55, 0x5c, 0x48, 0x59, 0xa9, 0x59, 0x56, 0xfe, 0xe2, 0x6a,
0xfa, 0x00, 0xe0, 0x98, 0x78, 0xb8, 0xeb, 0x51, 0xa7, 0xcf, 0x64, 0x8d, 0x14, 0xac, 0xa2, 0x90,
0x3c, 0x17, 0x02, 0xf4, 0x11, 0xac, 0xc9, 0x59, 0xab, 0xeb, 0xdb, 0x03, 0xcc, 0x02, 0xdb, 0xc1,
0xac, 0x92, 0x6f, 0x64, 0x9a, 0x45, 0xeb, 0xb6, 0x94, 0x7f, 0x3d, 0x16, 0xa3, 0x2e, 0xac, 0x07,
0x76, 0x88, 0x7d, 0xde, 0x4d, 0xd0, 0xb3, 0xa4, 0xf5, 0x4e, 0x5b, 0x74, 0xfe, 0x3f, 0x2f, 0xeb,
0x1f, 0x27, 0x66, 0x1e, 0x1a, 0x60, 0x7f, 0xfc, 0x74, 0xd6, 0xea, 0xd1, 0x07, 0x2e, 0xe9, 0x61,
0xc6, 0xcd, 0x6d, 0xf9, 0x67, 0xad, 0x29, 0x67, 0x13, 0x5c, 0x11, 0x82, 0xac, 0xe0, 0x8d, 0x68,
0x20, 0x90, 0x6b, 0xe3, 0x25, 0xa0, 0x24, 0xf2, 0x51, 0x30, 0x37, 0x41, 0x9f, 0xcc, 0x5b, 0x71,
0x38, 0x17, 0xce, 0x08, 0x49, 0x9b, 0xf6, 0xaf, 0x3a, 0xe4, 0x44, 0xe3, 0x65, 0xa8, 0x0f, 0x79,
0x35, 0x2e, 0xa0, 0x96, 0xb9, 0x68, 0x52, 0x35, 0xa7, 0x86, 0xae, 0xea, 0xc3, 0xf4, 0x06, 0xd1,
0xcd, 0xf7, 0x20, 0x27, 0x67, 0x08, 0x64, 0x2e, 0x36, 0x4d, 0x0e, 0x1b, 0xd5, 0x3b, 0x6f, 0x75,
0xb0, 0x1d, 0x11, 0x1f, 0x71, 0x7b, 0x45, 0xb0, 0x69, 0x6e, 0x3f, 0x35, 0x7a, 0xa4, 0xb9, 0xfd,
0xcc, 0x94, 0x31, 0x8a, 0xa7, 0x97, 0xa8, 0x48, 0xd0, 0x67, 0x69, 0x5d, 0x4c, 0xd3, 0xff, 0x3b,
0x1c, 0x8d, 0x21, 0x2b, 0x78, 0x1a, 0x3d, 0x58, 0x6c, 0x99, 0x18, 0x09, 0xaa, 0x66, 0x5a, 0xf5,
0xc9, 0x31, 0x82, 0xc0, 0xd3, 0x1c, 0x93, 0xe0, 0xfd, 0x34, 0xc7, 0x4c, 0xcd, 0x05, 0x2f, 0x20,
0x2b, 0x58, 0x3e, 0xcd, 0x31, 0x89, 0x69, 0x60, 0x6e, 0x12, 0xbc, 0x84, 0xbc, 0xe2, 0xe8, 0x34,
0x49, 0x30, 0xc5, 0xe6, 0xd5, 0xeb, 0x67, 0x7e, 0xa9, 0xf3, 0x50, 0x13, 0x70, 0x08, 0x6e, 0x4c,
0x73, 0xcf, 0xc4, 0x48, 0x90, 0x06, 0x8e, 0x29, 0xca, 0x7d, 0x06, 0x99, 0x7d, 0x3e, 0x42, 0xf7,
0x17, 0x9b, 0x4d, 0x68, 0x78, 0x2e, 0x18, 0xaf, 0x00, 0x26, 0x54, 0x89, 0x1e, 0xa5, 0x28, 0xd1,
0x59, 0x62, 0x9d, 0xeb, 0x7a, 0x0f, 0x72, 0x92, 0x2a, 0xd3, 0x54, 0x6f, 0x92, 0x53, 0xe7, 0x3a,
0xfc, 0x06, 0xf2, 0x8a, 0x37, 0xd3, 0x04, 0x6e, 0x8a, 0x61, 0xe7, 0xba, 0xe4, 0x50, 0x1c, 0xb3,
0x1f, 0x6a, 0xa7, 0xb8, 0xe7, 0x0c, 0xe5, 0x56, 0x1f, 0xdd, 0xc8, 0x26, 0x8a, 0xe0, 0x19, 0x40,
0xa2, 0x93, 0xa7, 0x01, 0x7d, 0x96, 0x4f, 0xab, 0x9f, 0xde, 0xcc, 0x48, 0x1d, 0xdc, 0xa9, 0x5c,
0xbc, 0xa9, 0xad, 0xfc, 0xf1, 0xa6, 0xb6, 0xf2, 0xfa, 0xaa, 0xa6, 0x5d, 0x5c, 0xd5, 0xb4, 0xdf,
0xaf, 0x6a, 0xda, 0xdf, 0x57, 0x35, 0xed, 0x28, 0x2f, 0x81, 0x79, 0xf4, 0x6f, 0x00, 0x00, 0x00,
0xff, 0xff, 0x46, 0xa7, 0x8c, 0x94, 0xc8, 0x10, 0x00, 0x00,
}

View File

@ -14,6 +14,7 @@ service Tasks {
rpc Create(CreateRequest) returns (CreateResponse);
rpc Start(StartRequest) returns (google.protobuf.Empty);
rpc Delete(DeleteRequest) returns (DeleteResponse);
rpc DeleteProcess(DeleteProcessRequest) returns (DeleteResponse);
rpc Info(InfoRequest) returns (InfoResponse);
rpc List(ListRequest) returns (ListResponse);
rpc Kill(KillRequest) returns (google.protobuf.Empty);
@ -81,6 +82,11 @@ message DeleteResponse {
google.protobuf.Timestamp exited_at = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
}
message DeleteProcessRequest {
string container_id = 1;
uint32 pid = 2;
}
message InfoRequest {
string container_id = 1;
}

View File

@ -113,6 +113,10 @@ type Task struct {
Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"`
Status Status `protobuf:"varint,4,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"`
Spec *google_protobuf1.Any `protobuf:"bytes,5,opt,name=spec" json:"spec,omitempty"`
Stdin string `protobuf:"bytes,6,opt,name=stdin,proto3" json:"stdin,omitempty"`
Stdout string `protobuf:"bytes,7,opt,name=stdout,proto3" json:"stdout,omitempty"`
Stderr string `protobuf:"bytes,8,opt,name=stderr,proto3" json:"stderr,omitempty"`
Terminal bool `protobuf:"varint,9,opt,name=terminal,proto3" json:"terminal,omitempty"`
}
func (m *Task) Reset() { *m = Task{} }
@ -129,6 +133,9 @@ type Process struct {
ExitStatus uint32 `protobuf:"varint,7,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"`
Status Status `protobuf:"varint,8,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"`
RuntimeData *google_protobuf1.Any `protobuf:"bytes,9,opt,name=runtime_data,json=runtimeData" json:"runtime_data,omitempty"`
Stdin string `protobuf:"bytes,10,opt,name=stdin,proto3" json:"stdin,omitempty"`
Stdout string `protobuf:"bytes,11,opt,name=stdout,proto3" json:"stdout,omitempty"`
Stderr string `protobuf:"bytes,12,opt,name=stderr,proto3" json:"stderr,omitempty"`
}
func (m *Process) Reset() { *m = Process{} }
@ -212,6 +219,34 @@ func (m *Task) MarshalTo(dAtA []byte) (int, error) {
}
i += n1
}
if len(m.Stdin) > 0 {
dAtA[i] = 0x32
i++
i = encodeVarintTask(dAtA, i, uint64(len(m.Stdin)))
i += copy(dAtA[i:], m.Stdin)
}
if len(m.Stdout) > 0 {
dAtA[i] = 0x3a
i++
i = encodeVarintTask(dAtA, i, uint64(len(m.Stdout)))
i += copy(dAtA[i:], m.Stdout)
}
if len(m.Stderr) > 0 {
dAtA[i] = 0x42
i++
i = encodeVarintTask(dAtA, i, uint64(len(m.Stderr)))
i += copy(dAtA[i:], m.Stderr)
}
if m.Terminal {
dAtA[i] = 0x48
i++
if m.Terminal {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
return i, nil
}
@ -311,6 +346,24 @@ func (m *Process) MarshalTo(dAtA []byte) (int, error) {
}
i += n3
}
if len(m.Stdin) > 0 {
dAtA[i] = 0x52
i++
i = encodeVarintTask(dAtA, i, uint64(len(m.Stdin)))
i += copy(dAtA[i:], m.Stdin)
}
if len(m.Stdout) > 0 {
dAtA[i] = 0x5a
i++
i = encodeVarintTask(dAtA, i, uint64(len(m.Stdout)))
i += copy(dAtA[i:], m.Stdout)
}
if len(m.Stderr) > 0 {
dAtA[i] = 0x62
i++
i = encodeVarintTask(dAtA, i, uint64(len(m.Stderr)))
i += copy(dAtA[i:], m.Stderr)
}
return i, nil
}
@ -454,6 +507,21 @@ func (m *Task) Size() (n int) {
l = m.Spec.Size()
n += 1 + l + sovTask(uint64(l))
}
l = len(m.Stdin)
if l > 0 {
n += 1 + l + sovTask(uint64(l))
}
l = len(m.Stdout)
if l > 0 {
n += 1 + l + sovTask(uint64(l))
}
l = len(m.Stderr)
if l > 0 {
n += 1 + l + sovTask(uint64(l))
}
if m.Terminal {
n += 2
}
return n
}
@ -496,6 +564,18 @@ func (m *Process) Size() (n int) {
l = m.RuntimeData.Size()
n += 1 + l + sovTask(uint64(l))
}
l = len(m.Stdin)
if l > 0 {
n += 1 + l + sovTask(uint64(l))
}
l = len(m.Stdout)
if l > 0 {
n += 1 + l + sovTask(uint64(l))
}
l = len(m.Stderr)
if l > 0 {
n += 1 + l + sovTask(uint64(l))
}
return n
}
@ -562,6 +642,10 @@ func (this *Task) String() string {
`Pid:` + fmt.Sprintf("%v", this.Pid) + `,`,
`Status:` + fmt.Sprintf("%v", this.Status) + `,`,
`Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "google_protobuf1.Any", 1) + `,`,
`Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`,
`Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`,
`Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`,
`Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`,
`}`,
}, "")
return s
@ -580,6 +664,9 @@ func (this *Process) String() string {
`ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`,
`Status:` + fmt.Sprintf("%v", this.Status) + `,`,
`RuntimeData:` + strings.Replace(fmt.Sprintf("%v", this.RuntimeData), "Any", "google_protobuf1.Any", 1) + `,`,
`Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`,
`Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`,
`Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`,
`}`,
}, "")
return s
@ -776,6 +863,113 @@ func (m *Task) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Stdin", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTask
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthTask
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Stdin = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 7:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Stdout", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTask
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthTask
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Stdout = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Stderr", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTask
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthTask
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Stderr = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 9:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Terminal", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTask
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Terminal = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipTask(dAtA[iNdEx:])
@ -1056,6 +1250,93 @@ func (m *Process) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 10:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Stdin", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTask
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthTask
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Stdin = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 11:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Stdout", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTask
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthTask
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Stdout = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 12:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Stderr", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTask
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthTask
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Stderr = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTask(dAtA[iNdEx:])
@ -1503,50 +1784,54 @@ func init() {
}
var fileDescriptorTask = []byte{
// 718 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xbf, 0x6f, 0xf3, 0x44,
0x18, 0xce, 0x39, 0xce, 0xaf, 0x4b, 0x93, 0xcf, 0x1c, 0x9f, 0x90, 0xbf, 0x80, 0x1c, 0x2b, 0x42,
0x22, 0x42, 0xc2, 0x11, 0xe9, 0x00, 0x62, 0x4b, 0x63, 0xab, 0x8a, 0x10, 0x49, 0xb8, 0x38, 0xa2,
0x5b, 0x74, 0xcd, 0x1d, 0xe6, 0xd4, 0xc6, 0xb6, 0xec, 0x73, 0x4b, 0x36, 0x46, 0xd4, 0x89, 0x7f,
0xa0, 0x0b, 0xb0, 0xb2, 0x32, 0xb0, 0xb2, 0x74, 0x64, 0x64, 0x2a, 0x34, 0x7f, 0x09, 0xf2, 0xd9,
0xf9, 0xa1, 0x36, 0x20, 0x16, 0xeb, 0xbd, 0xf7, 0x79, 0xee, 0xbd, 0xe7, 0x79, 0xee, 0x0c, 0x3f,
0xf3, 0xb8, 0xf8, 0x26, 0xb9, 0xb4, 0x96, 0xc1, 0xaa, 0xb7, 0x0c, 0x7c, 0x41, 0xb8, 0xcf, 0x22,
0x7a, 0x58, 0x92, 0x90, 0xf7, 0xc4, 0x3a, 0x64, 0x71, 0x4f, 0x90, 0xf8, 0x4a, 0x7e, 0xac, 0x30,
0x0a, 0x44, 0x80, 0xde, 0xde, 0xb3, 0xac, 0x9b, 0x8f, 0x2d, 0x49, 0x6a, 0xbd, 0xf6, 0x02, 0x2f,
0x90, 0x78, 0x2f, 0xad, 0x32, 0x6a, 0xeb, 0x8d, 0x17, 0x04, 0xde, 0x35, 0xeb, 0xc9, 0xd5, 0x65,
0xf2, 0x75, 0x8f, 0xf8, 0xeb, 0x1c, 0x6a, 0x3f, 0x87, 0x04, 0x5f, 0xb1, 0x58, 0x90, 0x55, 0x98,
0x11, 0x3a, 0xbf, 0x03, 0xa8, 0xba, 0x24, 0xbe, 0x42, 0xef, 0x40, 0x85, 0x53, 0x1d, 0x98, 0xa0,
0x5b, 0x3b, 0x2b, 0x6f, 0x1e, 0xdb, 0xca, 0xc8, 0xc6, 0x0a, 0xa7, 0xa8, 0x0f, 0x4f, 0x76, 0x4a,
0x16, 0x9c, 0xea, 0x8a, 0x64, 0xbc, 0xda, 0x3c, 0xb6, 0xeb, 0xc3, 0x6d, 0x7f, 0x64, 0xe3, 0xfa,
0x8e, 0x34, 0xa2, 0x48, 0x83, 0xc5, 0x90, 0x53, 0xbd, 0x68, 0x82, 0x6e, 0x03, 0xa7, 0x25, 0x3a,
0x85, 0xe5, 0x58, 0x10, 0x91, 0xc4, 0xba, 0x6a, 0x82, 0x6e, 0xb3, 0xff, 0xae, 0x75, 0xc4, 0x9e,
0x35, 0x93, 0x14, 0x9c, 0x53, 0x51, 0x17, 0xaa, 0x71, 0xc8, 0x96, 0x7a, 0xc9, 0x04, 0xdd, 0x7a,
0xff, 0xb5, 0x95, 0x79, 0xb1, 0xb6, 0x5e, 0xac, 0x81, 0xbf, 0xc6, 0x92, 0xd1, 0xf9, 0x45, 0x81,
0x95, 0x69, 0x14, 0x2c, 0x59, 0x1c, 0x6f, 0x0f, 0x07, 0xfb, 0xc3, 0x11, 0x54, 0x49, 0xe4, 0xc5,
0xba, 0x62, 0x16, 0xbb, 0x35, 0x2c, 0xeb, 0x94, 0xc5, 0xfc, 0x1b, 0xbd, 0x28, 0x5b, 0x69, 0x89,
0x3e, 0x82, 0x6a, 0x12, 0xb3, 0x48, 0x0a, 0xac, 0xf7, 0xdf, 0x1c, 0x15, 0x38, 0x8f, 0x59, 0x84,
0x25, 0x2d, 0x1d, 0xb0, 0xbc, 0xa5, 0x52, 0x5b, 0x0d, 0xa7, 0x25, 0x6a, 0xc1, 0xaa, 0x60, 0xd1,
0x8a, 0xfb, 0xe4, 0x5a, 0x2f, 0x9b, 0xa0, 0x5b, 0xc5, 0xbb, 0x35, 0x6a, 0xc3, 0x3a, 0xfb, 0x96,
0x8b, 0x45, 0x1e, 0x42, 0x45, 0x8a, 0x83, 0x69, 0x2b, 0xf3, 0x7c, 0x10, 0x50, 0xf5, 0xff, 0x07,
0xf4, 0x09, 0x3c, 0x89, 0x12, 0x3f, 0xbd, 0xd2, 0x05, 0x25, 0x82, 0xe8, 0xb5, 0xff, 0x08, 0xaa,
0x9e, 0x33, 0x6d, 0x22, 0x48, 0x67, 0x06, 0xd5, 0x79, 0x6e, 0x22, 0xd9, 0x67, 0x95, 0x70, 0x79,
0x75, 0x5e, 0x7e, 0xcb, 0x0d, 0x9c, 0x96, 0xe8, 0x03, 0xf8, 0x8a, 0x50, 0xca, 0x05, 0x0f, 0x7c,
0x72, 0xbd, 0xf0, 0x38, 0x8d, 0x65, 0x6a, 0x0d, 0xdc, 0xdc, 0xb7, 0xcf, 0x39, 0x8d, 0x3b, 0x3f,
0x2a, 0xb0, 0xe4, 0xdc, 0x30, 0x5f, 0xfc, 0xeb, 0x5b, 0xfa, 0x14, 0xaa, 0xa9, 0x0f, 0x39, 0xbd,
0xd9, 0x7f, 0xff, 0xa8, 0x45, 0x39, 0x21, 0xfb, 0xba, 0xeb, 0x90, 0x61, 0xb9, 0xe3, 0xc8, 0x8b,
0x7a, 0x96, 0xa8, 0xfa, 0x22, 0xd1, 0x01, 0xac, 0xa5, 0x2b, 0x46, 0x17, 0x44, 0xe4, 0x4f, 0xa8,
0xf5, 0x22, 0x19, 0x77, 0xfb, 0x3b, 0x9c, 0x55, 0x1f, 0x1e, 0xdb, 0x85, 0x1f, 0xfe, 0x6a, 0x03,
0x5c, 0xcd, 0xb6, 0x0d, 0x44, 0xe7, 0x4b, 0x58, 0xdb, 0x09, 0x41, 0x55, 0xa8, 0x3a, 0x17, 0x23,
0x57, 0x2b, 0xa0, 0x0a, 0x2c, 0x4e, 0x26, 0x5f, 0x68, 0x00, 0x41, 0x58, 0x1e, 0x62, 0x67, 0xe0,
0x3a, 0x9a, 0x82, 0x6a, 0xb0, 0x34, 0x73, 0x07, 0xd8, 0xd5, 0x8a, 0xa8, 0x09, 0xa1, 0x73, 0xe1,
0x0c, 0x17, 0x03, 0xdb, 0x76, 0x6c, 0x4d, 0x4d, 0x69, 0xd3, 0xc1, 0x7c, 0xe6, 0xd8, 0x5a, 0xe9,
0xc3, 0x5f, 0x01, 0x2c, 0xe7, 0x02, 0x0d, 0x58, 0x99, 0x8f, 0x3f, 0x1f, 0x4f, 0xbe, 0x1a, 0x6b,
0x85, 0xd6, 0x5b, 0x77, 0xf7, 0x66, 0x23, 0x03, 0xe6, 0xfe, 0x95, 0x1f, 0xdc, 0xfa, 0x29, 0x9e,
0x4d, 0xb7, 0x35, 0x70, 0x88, 0x0f, 0x23, 0x46, 0x04, 0xa3, 0x29, 0x8e, 0xe7, 0xe3, 0xf1, 0x68,
0x7c, 0xae, 0x29, 0x87, 0x38, 0x4e, 0x7c, 0x9f, 0xfb, 0x5e, 0x8a, 0xcf, 0xdc, 0xc9, 0x74, 0xea,
0xd8, 0x5a, 0xf1, 0x10, 0x9f, 0x89, 0x20, 0x0c, 0x19, 0x45, 0xef, 0xed, 0x64, 0xa9, 0x2d, 0xed,
0xee, 0xde, 0x3c, 0xc9, 0xe0, 0x29, 0x49, 0x62, 0x46, 0x5b, 0xcd, 0xef, 0x7f, 0x32, 0x0a, 0xbf,
0xfd, 0x6c, 0xe4, 0x6a, 0xcf, 0xf4, 0x87, 0x27, 0xa3, 0xf0, 0xe7, 0x93, 0x51, 0xf8, 0x6e, 0x63,
0x80, 0x87, 0x8d, 0x01, 0xfe, 0xd8, 0x18, 0xe0, 0xef, 0x8d, 0x01, 0x2e, 0xcb, 0x32, 0xcd, 0xd3,
0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x51, 0xea, 0x99, 0x62, 0xee, 0x04, 0x00, 0x00,
// 775 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x4d, 0x6f, 0xe3, 0x44,
0x18, 0x8e, 0x1d, 0xe7, 0x6b, 0xd2, 0x66, 0xcd, 0x50, 0xad, 0xbc, 0x01, 0x39, 0x56, 0x84, 0x44,
0x84, 0x84, 0x23, 0xb2, 0x07, 0x10, 0xb7, 0xb4, 0xb6, 0x56, 0x11, 0x22, 0x0d, 0x13, 0x47, 0xec,
0x2d, 0x9a, 0x66, 0x06, 0x33, 0x6a, 0x3b, 0xb6, 0x3c, 0xe3, 0x2e, 0xbd, 0x71, 0x44, 0x7b, 0xe2,
0x0f, 0xec, 0x85, 0x8f, 0xbf, 0xc0, 0x81, 0x5f, 0xd0, 0x23, 0x47, 0x4e, 0x85, 0xcd, 0x5f, 0xe0,
0x0f, 0xa0, 0x19, 0xbb, 0x49, 0x76, 0x9b, 0x4a, 0x7b, 0xb1, 0xde, 0x79, 0x9f, 0x67, 0x26, 0xcf,
0xfb, 0x3c, 0x6f, 0xc0, 0x97, 0x31, 0x93, 0xdf, 0xe7, 0x67, 0xfe, 0x2a, 0xb9, 0x1c, 0xae, 0x12,
0x2e, 0x31, 0xe3, 0x34, 0x23, 0xbb, 0x25, 0x4e, 0xd9, 0x50, 0x5e, 0xa7, 0x54, 0x0c, 0x25, 0x16,
0xe7, 0xfa, 0xe3, 0xa7, 0x59, 0x22, 0x13, 0xf8, 0xfe, 0x96, 0xe5, 0x5f, 0x7d, 0xe6, 0x6b, 0x52,
0xf7, 0x28, 0x4e, 0xe2, 0x44, 0xe3, 0x43, 0x55, 0x15, 0xd4, 0xee, 0x93, 0x38, 0x49, 0xe2, 0x0b,
0x3a, 0xd4, 0xa7, 0xb3, 0xfc, 0xbb, 0x21, 0xe6, 0xd7, 0x25, 0xd4, 0x7b, 0x1b, 0x92, 0xec, 0x92,
0x0a, 0x89, 0x2f, 0xd3, 0x82, 0xd0, 0xff, 0xdd, 0x04, 0x56, 0x84, 0xc5, 0x39, 0x7c, 0x0c, 0x4c,
0x46, 0x1c, 0xc3, 0x33, 0x06, 0xad, 0xe3, 0xfa, 0xfa, 0xb6, 0x67, 0x4e, 0x02, 0x64, 0x32, 0x02,
0x47, 0xe0, 0x60, 0xa3, 0x64, 0xc9, 0x88, 0x63, 0x6a, 0xc6, 0xa3, 0xf5, 0x6d, 0xaf, 0x7d, 0x72,
0xd7, 0x9f, 0x04, 0xa8, 0xbd, 0x21, 0x4d, 0x08, 0xb4, 0x41, 0x35, 0x65, 0xc4, 0xa9, 0x7a, 0xc6,
0xe0, 0x10, 0xa9, 0x12, 0x3e, 0x05, 0x75, 0x21, 0xb1, 0xcc, 0x85, 0x63, 0x79, 0xc6, 0xa0, 0x33,
0xfa, 0xc0, 0xdf, 0x33, 0x9e, 0x3f, 0xd7, 0x14, 0x54, 0x52, 0xe1, 0x00, 0x58, 0x22, 0xa5, 0x2b,
0xa7, 0xe6, 0x19, 0x83, 0xf6, 0xe8, 0xc8, 0x2f, 0x66, 0xf1, 0xef, 0x66, 0xf1, 0xc7, 0xfc, 0x1a,
0x69, 0x06, 0x3c, 0x02, 0x35, 0x21, 0x09, 0xe3, 0x4e, 0x5d, 0xa9, 0x43, 0xc5, 0x01, 0x3e, 0x56,
0x3f, 0x4a, 0x92, 0x5c, 0x3a, 0x0d, 0xdd, 0x2e, 0x4f, 0x65, 0x9f, 0x66, 0x99, 0xd3, 0xdc, 0xf4,
0x69, 0x96, 0xc1, 0x2e, 0x68, 0x4a, 0x9a, 0x5d, 0x32, 0x8e, 0x2f, 0x9c, 0x96, 0x67, 0x0c, 0x9a,
0x68, 0x73, 0xee, 0xff, 0x67, 0x82, 0xc6, 0x2c, 0x4b, 0x56, 0x54, 0x88, 0xbb, 0xf1, 0x8c, 0xed,
0x78, 0x10, 0x58, 0x38, 0x8b, 0x85, 0x63, 0x7a, 0xd5, 0x41, 0x0b, 0xe9, 0x5a, 0xb1, 0x28, 0xbf,
0x72, 0xaa, 0xba, 0xa5, 0x4a, 0xf8, 0x29, 0xb0, 0x72, 0x41, 0x33, 0x6d, 0x41, 0x7b, 0xf4, 0x64,
0xaf, 0x05, 0x0b, 0x41, 0x33, 0xa4, 0x69, 0xea, 0x81, 0xd5, 0x0b, 0xa2, 0xa7, 0x6f, 0x21, 0x55,
0xbe, 0x21, 0xb0, 0xfe, 0xa6, 0x40, 0xd8, 0x03, 0x6d, 0xfa, 0x03, 0x93, 0xcb, 0xd2, 0xe6, 0x86,
0x16, 0x07, 0x54, 0xab, 0x70, 0x75, 0x27, 0x82, 0xe6, 0xbb, 0x47, 0xf0, 0x39, 0x38, 0xc8, 0x72,
0xae, 0x96, 0x66, 0x49, 0xb0, 0xc4, 0xda, 0x96, 0x87, 0xa2, 0x68, 0x97, 0xcc, 0x00, 0x4b, 0xbc,
0x4d, 0x04, 0xec, 0x4f, 0xa4, 0xfd, 0x40, 0x22, 0x07, 0xbb, 0x89, 0xf4, 0xe7, 0xc0, 0x5a, 0x94,
0x56, 0xe4, 0x5b, 0xc7, 0x73, 0xa6, 0x57, 0x2c, 0x2e, 0xb7, 0xf1, 0x10, 0xa9, 0x12, 0x7e, 0x0c,
0x1e, 0x61, 0x42, 0x98, 0x64, 0x09, 0xc7, 0x17, 0xcb, 0x98, 0x11, 0xa1, 0xbd, 0x3f, 0x44, 0x9d,
0x6d, 0xfb, 0x19, 0x23, 0xa2, 0xff, 0x8b, 0x09, 0x6a, 0xe1, 0x15, 0xe5, 0xf2, 0xc1, 0x9d, 0xff,
0x02, 0x58, 0xca, 0x0d, 0xfd, 0x7a, 0x67, 0xf4, 0xd1, 0x5e, 0xa3, 0xf4, 0x0b, 0xc5, 0x37, 0xba,
0x4e, 0x29, 0xd2, 0x37, 0xf6, 0x6c, 0xfe, 0x5b, 0xb9, 0x58, 0xf7, 0x72, 0x19, 0x83, 0x96, 0x3a,
0x51, 0xb2, 0xc4, 0xb2, 0x5c, 0xf5, 0xee, 0x3d, 0x7f, 0xa3, 0xbb, 0xbf, 0xed, 0x71, 0xf3, 0xe6,
0xb6, 0x57, 0xf9, 0xf9, 0x9f, 0x9e, 0x81, 0x9a, 0xc5, 0xb5, 0xb1, 0xec, 0x7f, 0x03, 0x5a, 0x1b,
0x21, 0xb0, 0x09, 0xac, 0xf0, 0xf9, 0x24, 0xb2, 0x2b, 0xb0, 0x01, 0xaa, 0xa7, 0xa7, 0x5f, 0xdb,
0x06, 0x04, 0xa0, 0x7e, 0x82, 0xc2, 0x71, 0x14, 0xda, 0x26, 0x6c, 0x81, 0xda, 0x3c, 0x1a, 0xa3,
0xc8, 0xae, 0xc2, 0x0e, 0x00, 0xe1, 0xf3, 0xf0, 0x64, 0x39, 0x0e, 0x82, 0x30, 0xb0, 0x2d, 0x45,
0x9b, 0x8d, 0x17, 0xf3, 0x30, 0xb0, 0x6b, 0x9f, 0xfc, 0x61, 0x80, 0x7a, 0x29, 0xd0, 0x05, 0x8d,
0xc5, 0xf4, 0xab, 0xe9, 0xe9, 0xb7, 0x53, 0xbb, 0xd2, 0x7d, 0xef, 0xe5, 0x2b, 0xef, 0xb0, 0x00,
0x16, 0xfc, 0x9c, 0x27, 0x2f, 0xb8, 0xc2, 0x8b, 0xd7, 0x03, 0xdb, 0xd8, 0xc5, 0x4f, 0x32, 0x8a,
0x25, 0x25, 0x0a, 0x47, 0x8b, 0xe9, 0x74, 0x32, 0x7d, 0x66, 0x9b, 0xbb, 0x38, 0xca, 0x39, 0x67,
0x3c, 0x56, 0xf8, 0x3c, 0x3a, 0x9d, 0xcd, 0xc2, 0xc0, 0xae, 0xee, 0xe2, 0x73, 0x99, 0xa4, 0x29,
0x25, 0xf0, 0xc3, 0x8d, 0x2c, 0xab, 0x6b, 0xbf, 0x7c, 0xe5, 0x1d, 0x14, 0xf0, 0x0c, 0xe7, 0x82,
0x92, 0x6e, 0xe7, 0xa7, 0x5f, 0xdd, 0xca, 0x9f, 0xbf, 0xb9, 0xa5, 0xda, 0x63, 0xe7, 0xe6, 0xb5,
0x5b, 0xf9, 0xfb, 0xb5, 0x5b, 0xf9, 0x71, 0xed, 0x1a, 0x37, 0x6b, 0xd7, 0xf8, 0x6b, 0xed, 0x1a,
0xff, 0xae, 0x5d, 0xe3, 0xac, 0xae, 0xdd, 0x7c, 0xfa, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x48,
0xcc, 0xfd, 0x9a, 0x96, 0x05, 0x00, 0x00,
}

View File

@ -23,6 +23,10 @@ message Task {
uint32 pid = 3;
Status status = 4;
google.protobuf.Any spec = 5;
string stdin = 6;
string stdout = 7;
string stderr = 8;
bool terminal = 9;
}
message Process {
@ -35,6 +39,9 @@ message Process {
uint32 exit_status = 7;
Status status = 8;
google.protobuf.Any runtime_data = 9;
string stdin = 10;
string stdout = 11;
string stderr = 12;
}
message User {

View File

@ -1,125 +0,0 @@
package compression
import (
"bufio"
"bytes"
"compress/gzip"
"fmt"
"io"
"sync"
)
type (
// Compression is the state represents if compressed or not.
Compression int
)
const (
// Uncompressed represents the uncompressed.
Uncompressed Compression = iota
// Gzip is gzip compression algorithm.
Gzip
)
var (
bufioReader32KPool = &sync.Pool{
New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) },
}
)
type readCloserWrapper struct {
io.Reader
closer func() error
}
func (r *readCloserWrapper) Close() error {
if r.closer != nil {
return r.closer()
}
return nil
}
type writeCloserWrapper struct {
io.Writer
closer func() error
}
func (w *writeCloserWrapper) Close() error {
if w.closer != nil {
w.closer()
}
return nil
}
// DetectCompression detects the compression algorithm of the source.
func DetectCompression(source []byte) Compression {
for compression, m := range map[Compression][]byte{
Gzip: {0x1F, 0x8B, 0x08},
} {
if len(source) < len(m) {
// Len too short
continue
}
if bytes.Equal(m, source[:len(m)]) {
return compression
}
}
return Uncompressed
}
// DecompressStream decompresses the archive and returns a ReaderCloser with the decompressed archive.
func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
buf := bufioReader32KPool.Get().(*bufio.Reader)
buf.Reset(archive)
bs, err := buf.Peek(10)
if err != nil && err != io.EOF {
// Note: we'll ignore any io.EOF error because there are some odd
// cases where the layer.tar file will be empty (zero bytes) and
// that results in an io.EOF from the Peek() call. So, in those
// cases we'll just treat it as a non-compressed stream and
// that means just create an empty layer.
// See Issue docker/docker#18170
return nil, err
}
closer := func() error {
buf.Reset(nil)
bufioReader32KPool.Put(buf)
return nil
}
switch compression := DetectCompression(bs); compression {
case Uncompressed:
readBufWrapper := &readCloserWrapper{buf, closer}
return readBufWrapper, nil
case Gzip:
gzReader, err := gzip.NewReader(buf)
if err != nil {
return nil, err
}
readBufWrapper := &readCloserWrapper{gzReader, closer}
return readBufWrapper, nil
default:
return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension())
}
}
// CompressStream compresseses the dest with specified compression algorithm.
func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) {
switch compression {
case Uncompressed:
return &writeCloserWrapper{dest, nil}, nil
case Gzip:
return gzip.NewWriter(dest), nil
default:
return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension())
}
}
// Extension returns the extension of a file that uses the specified compression algorithm.
func (compression *Compression) Extension() string {
switch *compression {
case Gzip:
return "gz"
}
return ""
}

View File

@ -1,528 +0,0 @@
package archive
import (
"archive/tar"
"context"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"syscall"
"time"
"github.com/containerd/containerd/fs"
"github.com/containerd/containerd/log"
"github.com/pkg/errors"
)
var (
bufferPool = &sync.Pool{
New: func() interface{} {
return make([]byte, 32*1024)
},
}
breakoutError = errors.New("file name outside of root")
)
// Diff returns a tar stream of the computed filesystem
// difference between the provided directories.
//
// Produces a tar using OCI style file markers for deletions. Deleted
// files will be prepended with the prefix ".wh.". This style is
// based off AUFS whiteouts.
// See https://github.com/opencontainers/image-spec/blob/master/layer.md
func Diff(ctx context.Context, a, b string) io.ReadCloser {
r, w := io.Pipe()
go func() {
err := WriteDiff(ctx, w, a, b)
if err = w.CloseWithError(err); err != nil {
log.G(ctx).WithError(err).Debugf("closing tar pipe failed")
}
}()
return r
}
// WriteDiff writes a tar stream of the computed difference between the
// provided directories.
//
// Produces a tar using OCI style file markers for deletions. Deleted
// files will be prepended with the prefix ".wh.". This style is
// based off AUFS whiteouts.
// See https://github.com/opencontainers/image-spec/blob/master/layer.md
func WriteDiff(ctx context.Context, w io.Writer, a, b string) error {
cw := newChangeWriter(w, b)
err := fs.Changes(ctx, a, b, cw.HandleChange)
if err != nil {
return errors.Wrap(err, "failed to create diff tar stream")
}
return cw.Close()
}
const (
// whiteoutPrefix prefix means file is a whiteout. If this is followed by a
// filename this means that file has been removed from the base layer.
// See https://github.com/opencontainers/image-spec/blob/master/layer.md#whiteouts
whiteoutPrefix = ".wh."
// whiteoutMetaPrefix prefix means whiteout has a special meaning and is not
// for removing an actual file. Normally these files are excluded from exported
// archives.
whiteoutMetaPrefix = whiteoutPrefix + whiteoutPrefix
// whiteoutLinkDir is a directory AUFS uses for storing hardlink links to other
// layers. Normally these should not go into exported archives and all changed
// hardlinks should be copied to the top layer.
whiteoutLinkDir = whiteoutMetaPrefix + "plnk"
// whiteoutOpaqueDir file means directory has been made opaque - meaning
// readdir calls to this directory do not follow to lower layers.
whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq"
)
// Apply applies a tar stream of an OCI style diff tar.
// See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets
func Apply(ctx context.Context, root string, r io.Reader) (int64, error) {
root = filepath.Clean(root)
fn := prepareApply()
defer fn()
var (
tr = tar.NewReader(r)
size int64
dirs []*tar.Header
// Used for handling opaque directory markers which
// may occur out of order
unpackedPaths = make(map[string]struct{})
// Used for aufs plink directory
aufsTempdir = ""
aufsHardlinks = make(map[string]*tar.Header)
)
// Iterate through the files in the archive.
for {
hdr, err := tr.Next()
if err == io.EOF {
// end of tar archive
break
}
if err != nil {
return 0, err
}
size += hdr.Size
// Normalize name, for safety and for a simple is-root check
hdr.Name = filepath.Clean(hdr.Name)
if skipFile(hdr) {
log.G(ctx).Warnf("file %q ignored: archive may not be supported on system", hdr.Name)
continue
}
// Note as these operations are platform specific, so must the slash be.
if !strings.HasSuffix(hdr.Name, string(os.PathSeparator)) {
// Not the root directory, ensure that the parent directory exists.
// This happened in some tests where an image had a tarfile without any
// parent directories.
parent := filepath.Dir(hdr.Name)
parentPath := filepath.Join(root, parent)
if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
err = mkdirAll(parentPath, 0600)
if err != nil {
return 0, err
}
}
}
// Skip AUFS metadata dirs
if strings.HasPrefix(hdr.Name, whiteoutMetaPrefix) {
// Regular files inside /.wh..wh.plnk can be used as hardlink targets
// We don't want this directory, but we need the files in them so that
// such hardlinks can be resolved.
if strings.HasPrefix(hdr.Name, whiteoutLinkDir) && hdr.Typeflag == tar.TypeReg {
basename := filepath.Base(hdr.Name)
aufsHardlinks[basename] = hdr
if aufsTempdir == "" {
if aufsTempdir, err = ioutil.TempDir("", "dockerplnk"); err != nil {
return 0, err
}
defer os.RemoveAll(aufsTempdir)
}
if err := createTarFile(ctx, filepath.Join(aufsTempdir, basename), root, hdr, tr); err != nil {
return 0, err
}
}
if hdr.Name != whiteoutOpaqueDir {
continue
}
}
path := filepath.Join(root, hdr.Name)
rel, err := filepath.Rel(root, path)
if err != nil {
return 0, err
}
// Note as these operations are platform specific, so must the slash be.
if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
return 0, errors.Wrapf(breakoutError, "%q is outside of %q", hdr.Name, root)
}
base := filepath.Base(path)
if strings.HasPrefix(base, whiteoutPrefix) {
dir := filepath.Dir(path)
if base == whiteoutOpaqueDir {
_, err := os.Lstat(dir)
if err != nil {
return 0, err
}
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
if os.IsNotExist(err) {
err = nil // parent was deleted
}
return err
}
if path == dir {
return nil
}
if _, exists := unpackedPaths[path]; !exists {
err := os.RemoveAll(path)
return err
}
return nil
})
if err != nil {
return 0, err
}
continue
}
originalBase := base[len(whiteoutPrefix):]
originalPath := filepath.Join(dir, originalBase)
if err := os.RemoveAll(originalPath); err != nil {
return 0, err
}
continue
}
// If path exits we almost always just want to remove and replace it.
// The only exception is when it is a directory *and* the file from
// the layer is also a directory. Then we want to merge them (i.e.
// just apply the metadata from the layer).
if fi, err := os.Lstat(path); err == nil {
if !(fi.IsDir() && hdr.Typeflag == tar.TypeDir) {
if err := os.RemoveAll(path); err != nil {
return 0, err
}
}
}
srcData := io.Reader(tr)
srcHdr := hdr
// Hard links into /.wh..wh.plnk don't work, as we don't extract that directory, so
// we manually retarget these into the temporary files we extracted them into
if hdr.Typeflag == tar.TypeLink && strings.HasPrefix(filepath.Clean(hdr.Linkname), whiteoutLinkDir) {
linkBasename := filepath.Base(hdr.Linkname)
srcHdr = aufsHardlinks[linkBasename]
if srcHdr == nil {
return 0, fmt.Errorf("Invalid aufs hardlink")
}
tmpFile, err := os.Open(filepath.Join(aufsTempdir, linkBasename))
if err != nil {
return 0, err
}
defer tmpFile.Close()
srcData = tmpFile
}
if err := createTarFile(ctx, path, root, srcHdr, srcData); err != nil {
return 0, err
}
// Directory mtimes must be handled at the end to avoid further
// file creation in them to modify the directory mtime
if hdr.Typeflag == tar.TypeDir {
dirs = append(dirs, hdr)
}
unpackedPaths[path] = struct{}{}
}
for _, hdr := range dirs {
path := filepath.Join(root, hdr.Name)
if err := chtimes(path, boundTime(latestTime(hdr.AccessTime, hdr.ModTime)), boundTime(hdr.ModTime)); err != nil {
return 0, err
}
}
return size, nil
}
type changeWriter struct {
tw *tar.Writer
source string
whiteoutT time.Time
inodeSrc map[uint64]string
inodeRefs map[uint64][]string
}
func newChangeWriter(w io.Writer, source string) *changeWriter {
return &changeWriter{
tw: tar.NewWriter(w),
source: source,
whiteoutT: time.Now(),
inodeSrc: map[uint64]string{},
inodeRefs: map[uint64][]string{},
}
}
func (cw *changeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, err error) error {
if err != nil {
return err
}
if k == fs.ChangeKindDelete {
whiteOutDir := filepath.Dir(p)
whiteOutBase := filepath.Base(p)
whiteOut := filepath.Join(whiteOutDir, whiteoutPrefix+whiteOutBase)
hdr := &tar.Header{
Name: whiteOut[1:],
Size: 0,
ModTime: cw.whiteoutT,
AccessTime: cw.whiteoutT,
ChangeTime: cw.whiteoutT,
}
if err := cw.tw.WriteHeader(hdr); err != nil {
errors.Wrap(err, "failed to write whiteout header")
}
} else {
var (
link string
err error
source = filepath.Join(cw.source, p)
)
if f.Mode()&os.ModeSymlink != 0 {
if link, err = os.Readlink(source); err != nil {
return err
}
}
hdr, err := tar.FileInfoHeader(f, link)
if err != nil {
return err
}
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
name := p
if strings.HasPrefix(name, string(filepath.Separator)) {
name, err = filepath.Rel(string(filepath.Separator), name)
if err != nil {
return errors.Wrap(err, "failed to make path relative")
}
}
name, err = tarName(name)
if err != nil {
return errors.Wrap(err, "cannot canonicalize path")
}
// suffix with '/' for directories
if f.IsDir() && !strings.HasSuffix(name, "/") {
name += "/"
}
hdr.Name = name
if err := setHeaderForSpecialDevice(hdr, name, f); err != nil {
return errors.Wrap(err, "failed to set device headers")
}
// additionalLinks stores file names which must be linked to
// this file when this file is added
var additionalLinks []string
inode, isHardlink := fs.GetLinkInfo(f)
if isHardlink {
// If the inode has a source, always link to it
if source, ok := cw.inodeSrc[inode]; ok {
hdr.Typeflag = tar.TypeLink
hdr.Linkname = source
hdr.Size = 0
} else {
if k == fs.ChangeKindUnmodified {
cw.inodeRefs[inode] = append(cw.inodeRefs[inode], name)
return nil
}
cw.inodeSrc[inode] = name
additionalLinks = cw.inodeRefs[inode]
delete(cw.inodeRefs, inode)
}
} else if k == fs.ChangeKindUnmodified {
// Nothing to write to diff
return nil
}
if capability, err := getxattr(source, "security.capability"); err != nil {
return errors.Wrap(err, "failed to get capabilities xattr")
} else if capability != nil {
hdr.Xattrs = map[string]string{
"security.capability": string(capability),
}
}
if err := cw.tw.WriteHeader(hdr); err != nil {
return errors.Wrap(err, "failed to write file header")
}
if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 {
file, err := open(source)
if err != nil {
return errors.Wrapf(err, "failed to open path: %v", source)
}
defer file.Close()
buf := bufferPool.Get().([]byte)
n, err := io.CopyBuffer(cw.tw, file, buf)
bufferPool.Put(buf)
if err != nil {
return errors.Wrap(err, "failed to copy")
}
if n != hdr.Size {
return errors.New("short write copying file")
}
}
if additionalLinks != nil {
source = hdr.Name
for _, extra := range additionalLinks {
hdr.Name = extra
hdr.Typeflag = tar.TypeLink
hdr.Linkname = source
hdr.Size = 0
if err := cw.tw.WriteHeader(hdr); err != nil {
return errors.Wrap(err, "failed to write file header")
}
}
}
}
return nil
}
func (cw *changeWriter) Close() error {
if err := cw.tw.Close(); err != nil {
return errors.Wrap(err, "failed to close tar writer")
}
return nil
}
func createTarFile(ctx context.Context, path, extractDir string, hdr *tar.Header, reader io.Reader) error {
// hdr.Mode is in linux format, which we can use for syscalls,
// but for os.Foo() calls we need the mode converted to os.FileMode,
// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
hdrInfo := hdr.FileInfo()
switch hdr.Typeflag {
case tar.TypeDir:
// Create directory unless it exists as a directory already.
// In that case we just want to merge the two
if fi, err := os.Lstat(path); !(err == nil && fi.IsDir()) {
if err := os.Mkdir(path, hdrInfo.Mode()); err != nil {
return err
}
}
case tar.TypeReg, tar.TypeRegA:
file, err := openFile(path, os.O_CREATE|os.O_WRONLY, hdrInfo.Mode())
if err != nil {
return err
}
buf := bufferPool.Get().([]byte)
_, err = io.CopyBuffer(file, reader, buf)
if err1 := file.Close(); err == nil {
err = err1
}
if err != nil {
return err
}
case tar.TypeBlock, tar.TypeChar:
// Handle this is an OS-specific way
if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
return err
}
case tar.TypeFifo:
// Handle this is an OS-specific way
if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
return err
}
case tar.TypeLink:
targetPath := filepath.Join(extractDir, hdr.Linkname)
// check for hardlink breakout
if !strings.HasPrefix(targetPath, extractDir) {
return errors.Wrapf(breakoutError, "invalid hardlink %q -> %q", targetPath, hdr.Linkname)
}
if err := os.Link(targetPath, path); err != nil {
return err
}
case tar.TypeSymlink:
// path -> hdr.Linkname = targetPath
// e.g. /extractDir/path/to/symlink -> ../2/file = /extractDir/path/2/file
targetPath := filepath.Join(filepath.Dir(path), hdr.Linkname)
// the reason we don't need to check symlinks in the path (with FollowSymlinkInScope) is because
// that symlink would first have to be created, which would be caught earlier, at this very check:
if !strings.HasPrefix(targetPath, extractDir) {
return errors.Wrapf(breakoutError, "invalid symlink %q -> %q", path, hdr.Linkname)
}
if err := os.Symlink(hdr.Linkname, path); err != nil {
return err
}
case tar.TypeXGlobalHeader:
log.G(ctx).Debug("PAX Global Extended Headers found and ignored")
return nil
default:
return errors.Errorf("unhandled tar header type %d\n", hdr.Typeflag)
}
// Lchown is not supported on Windows.
if runtime.GOOS != "windows" {
if err := os.Lchown(path, hdr.Uid, hdr.Gid); err != nil {
return err
}
}
for key, value := range hdr.Xattrs {
if err := setxattr(path, key, value); err != nil {
if errors.Cause(err) == syscall.ENOTSUP {
log.G(ctx).WithError(err).Warnf("ignored xattr %s in archive", key)
continue
}
return err
}
}
// There is no LChmod, so ignore mode for symlink. Also, this
// must happen after chown, as that can modify the file mode
if err := handleLChmod(hdr, path, hdrInfo); err != nil {
return err
}
if err := chtimes(path, boundTime(latestTime(hdr.AccessTime, hdr.ModTime)), boundTime(hdr.ModTime)); err != nil {
return err
}
return nil
}

View File

@ -1,133 +0,0 @@
// +build !windows
package archive
import (
"archive/tar"
"os"
"sync"
"syscall"
"github.com/containerd/continuity/sysx"
"github.com/opencontainers/runc/libcontainer/system"
"github.com/pkg/errors"
)
func tarName(p string) (string, error) {
return p, nil
}
func chmodTarEntry(perm os.FileMode) os.FileMode {
return perm
}
func setHeaderForSpecialDevice(hdr *tar.Header, name string, fi os.FileInfo) error {
s, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return errors.New("unsupported stat type")
}
// Currently go does not fill in the major/minors
if s.Mode&syscall.S_IFBLK != 0 ||
s.Mode&syscall.S_IFCHR != 0 {
hdr.Devmajor = int64(major(uint64(s.Rdev)))
hdr.Devminor = int64(minor(uint64(s.Rdev)))
}
return nil
}
func major(device uint64) uint64 {
return (device >> 8) & 0xfff
}
func minor(device uint64) uint64 {
return (device & 0xff) | ((device >> 12) & 0xfff00)
}
func mkdev(major int64, minor int64) uint32 {
return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
}
func open(p string) (*os.File, error) {
return os.Open(p)
}
func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
return os.OpenFile(name, flag, perm)
}
func mkdirAll(path string, perm os.FileMode) error {
return os.MkdirAll(path, perm)
}
func prepareApply() func() {
// Unset unmask before doing an apply operation,
// restore unmask when complete
oldmask := syscall.Umask(0)
return func() {
syscall.Umask(oldmask)
}
}
func skipFile(*tar.Header) bool {
return false
}
var (
inUserNS bool
nsOnce sync.Once
)
func setInUserNS() {
inUserNS = system.RunningInUserNS()
}
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
// createTarFile to handle the following types of header: Block; Char; Fifo
func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
nsOnce.Do(setInUserNS)
if inUserNS {
// cannot create a device if running in user namespace
return nil
}
mode := uint32(hdr.Mode & 07777)
switch hdr.Typeflag {
case tar.TypeBlock:
mode |= syscall.S_IFBLK
case tar.TypeChar:
mode |= syscall.S_IFCHR
case tar.TypeFifo:
mode |= syscall.S_IFIFO
}
return syscall.Mknod(path, mode, int(mkdev(hdr.Devmajor, hdr.Devminor)))
}
func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
if hdr.Typeflag == tar.TypeLink {
if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
return err
}
}
} else if hdr.Typeflag != tar.TypeSymlink {
if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
return err
}
}
return nil
}
func getxattr(path, attr string) ([]byte, error) {
b, err := sysx.LGetxattr(path, attr)
if err == syscall.ENOTSUP || err == sysx.ENODATA {
return nil, nil
}
return b, err
}
func setxattr(path, key, value string) error {
return sysx.LSetxattr(path, key, []byte(value), 0)
}

View File

@ -1,104 +0,0 @@
package archive
import (
"archive/tar"
"errors"
"fmt"
"os"
"strings"
"github.com/containerd/containerd/sys"
)
// tarName returns platform-specific filepath
// to canonical posix-style path for tar archival. p is relative
// path.
func tarName(p string) (string, error) {
// windows: convert windows style relative path with backslashes
// into forward slashes. Since windows does not allow '/' or '\'
// in file names, it is mostly safe to replace however we must
// check just in case
if strings.Contains(p, "/") {
return "", fmt.Errorf("Windows path contains forward slash: %s", p)
}
return strings.Replace(p, string(os.PathSeparator), "/", -1), nil
}
// chmodTarEntry is used to adjust the file permissions used in tar header based
// on the platform the archival is done.
func chmodTarEntry(perm os.FileMode) os.FileMode {
perm &= 0755
// Add the x bit: make everything +x from windows
perm |= 0111
return perm
}
func setHeaderForSpecialDevice(*tar.Header, string, os.FileInfo) error {
// do nothing. no notion of Rdev, Inode, Nlink in stat on Windows
return nil
}
func open(p string) (*os.File, error) {
// We use sys.OpenSequential to ensure we use sequential file
// access on Windows to avoid depleting the standby list.
return sys.OpenSequential(p)
}
func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
// Source is regular file. We use sys.OpenFileSequential to use sequential
// file access to avoid depleting the standby list on Windows.
return sys.OpenFileSequential(name, flag, perm)
}
func mkdirAll(path string, perm os.FileMode) error {
return sys.MkdirAll(path, perm)
}
func prepareApply() func() {
// No umask or filesystem changes needed before apply
return func() {}
}
func skipFile(hdr *tar.Header) bool {
// Windows does not support filenames with colons in them. Ignore
// these files. This is not a problem though (although it might
// appear that it is). Let's suppose a client is running docker pull.
// The daemon it points to is Windows. Would it make sense for the
// client to be doing a docker pull Ubuntu for example (which has files
// with colons in the name under /usr/share/man/man3)? No, absolutely
// not as it would really only make sense that they were pulling a
// Windows image. However, for development, it is necessary to be able
// to pull Linux images which are in the repository.
//
// TODO Windows. Once the registry is aware of what images are Windows-
// specific or Linux-specific, this warning should be changed to an error
// to cater for the situation where someone does manage to upload a Linux
// image but have it tagged as Windows inadvertently.
if strings.Contains(hdr.Name, ":") {
return true
}
return false
}
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
// createTarFile to handle the following types of header: Block; Char; Fifo
func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
return nil
}
func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
return nil
}
func getxattr(path, attr string) ([]byte, error) {
return nil, nil
}
func setxattr(path, key, value string) error {
// Return not support error, do not wrap underlying not supported
// since xattrs should not exist in windows diff archives
return errors.New("xattrs not supported on Windows")
}

View File

@ -1,38 +0,0 @@
package archive
import (
"syscall"
"time"
"unsafe"
)
var (
minTime = time.Unix(0, 0)
maxTime time.Time
)
func init() {
if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 {
// This is a 64 bit timespec
// os.Chtimes limits time to the following
maxTime = time.Unix(0, 1<<63-1)
} else {
// This is a 32 bit timespec
maxTime = time.Unix(1<<31-1, 0)
}
}
func boundTime(t time.Time) time.Time {
if t.Before(minTime) || t.After(maxTime) {
return minTime
}
return t
}
func latestTime(t1, t2 time.Time) time.Time {
if t1.Before(t2) {
return t2
}
return t1
}

View File

@ -1,14 +0,0 @@
package archive
import (
"time"
"github.com/pkg/errors"
)
// as at MacOS 10.12 there is apparently no way to set timestamps
// with nanosecond precision. We could fall back to utimes/lutimes
// and lose the precision as a temporary workaround.
func chtimes(path string, atime, mtime time.Time) error {
return errors.New("OSX missing UtimesNanoAt")
}

View File

@ -1,23 +0,0 @@
// +build linux freebsd
package archive
import (
"time"
"golang.org/x/sys/unix"
"github.com/pkg/errors"
)
func chtimes(path string, atime, mtime time.Time) error {
var utimes [2]unix.Timespec
utimes[0] = unix.NsecToTimespec(atime.UnixNano())
utimes[1] = unix.NsecToTimespec(mtime.UnixNano())
if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil {
return errors.Wrap(err, "failed call to UtimesNanoAt")
}
return nil
}

View File

@ -1,25 +0,0 @@
package archive
import (
"syscall"
"time"
)
// chtimes will set the create time on a file using the given modtime.
// This requires calling SetFileTime and explicitly including the create time.
func chtimes(path string, atime, mtime time.Time) error {
ctimespec := syscall.NsecToTimespec(mtime.UnixNano())
pathp, e := syscall.UTF16PtrFromString(path)
if e != nil {
return e
}
h, e := syscall.CreateFile(pathp,
syscall.FILE_WRITE_ATTRIBUTES, syscall.FILE_SHARE_WRITE, nil,
syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
if e != nil {
return e
}
defer syscall.Close(h)
c := syscall.NsecToFiletime(syscall.TimespecToNsec(ctimespec))
return syscall.SetFileTime(h, &c, nil, nil)
}

View File

@ -1,6 +1,9 @@
package containers
import "context"
import (
"context"
"time"
)
// Container represents the set of data pinned by a container. Unless otherwise
// noted, the resources here are considered in use by the container.
@ -13,6 +16,8 @@ type Container struct {
Runtime string
Spec []byte
RootFS string
CreatedAt time.Time
UpdatedAt time.Time
}
type Store interface {

View File

@ -21,6 +21,12 @@ var (
// Use IsExists(err) to detect this condition.
ErrExists = errors.New("content: exists")
// ErrLocked is returned when content is actively being uploaded, this
// indicates that another process is attempting to upload the same content.
//
// Use IsLocked(err) to detect this condition.
ErrLocked = errors.New("content: locked")
bufPool = sync.Pool{
New: func() interface{} {
return make([]byte, 1<<20)
@ -30,6 +36,7 @@ var (
type Provider interface {
Reader(ctx context.Context, dgst digest.Digest) (io.ReadCloser, error)
ReaderAt(ctx context.Context, dgst digest.Digest) (io.ReaderAt, error)
}
type Ingester interface {
@ -107,3 +114,7 @@ func IsNotFound(err error) bool {
func IsExists(err error) bool {
return errors.Cause(err) == ErrExists
}
func IsLocked(err error) bool {
return errors.Cause(err) == ErrLocked
}

View File

@ -3,54 +3,35 @@ package content
import (
"sync"
"github.com/nightlyone/lockfile"
"github.com/pkg/errors"
)
// In addition to providing inter-process locks for content ingest, we also
// define a global in process lock to prevent two goroutines writing to the
// same file.
//
// This is pretty unsophisticated for now. In the future, we'd probably like to
// have more information about who is holding which locks, as well as better
// error reporting.
// Handles locking references
// TODO: use boltdb for lock status
var (
errLocked = errors.New("key is locked")
// locks lets us lock in process, as well as output of process.
locks = map[lockfile.Lockfile]struct{}{}
// locks lets us lock in process
locks = map[string]struct{}{}
locksMu sync.Mutex
)
func tryLock(lock lockfile.Lockfile) error {
func tryLock(ref string) error {
locksMu.Lock()
defer locksMu.Unlock()
if _, ok := locks[lock]; ok {
return errLocked
if _, ok := locks[ref]; ok {
return errors.Wrapf(ErrLocked, "key %s is locked", ref)
}
if err := lock.TryLock(); err != nil {
if errors.Cause(err) == lockfile.ErrBusy {
return errLocked
}
return errors.Wrapf(err, "lock.TryLock() encountered an error")
}
locks[lock] = struct{}{}
locks[ref] = struct{}{}
return nil
}
func unlock(lock lockfile.Lockfile) error {
func unlock(ref string) {
locksMu.Lock()
defer locksMu.Unlock()
if _, ok := locks[lock]; !ok {
return nil
if _, ok := locks[ref]; ok {
delete(locks, ref)
}
delete(locks, lock)
return lock.Unlock()
}

View File

@ -0,0 +1,26 @@
package content
import (
"io"
"os"
)
// readerat implements io.ReaderAt in a completely stateless manner by opening
// the referenced file for each call to ReadAt.
type readerAt struct {
f string
}
func (ra readerAt) ReadAt(p []byte, offset int64) (int, error) {
fp, err := os.Open(ra.f)
if err != nil {
return 0, err
}
defer fp.Close()
if _, err := fp.Seek(offset, io.SeekStart); err != nil {
return 0, err
}
return fp.Read(p)
}

View File

@ -12,7 +12,6 @@ import (
"time"
"github.com/containerd/containerd/log"
"github.com/nightlyone/lockfile"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
@ -58,11 +57,7 @@ func (s *store) info(dgst digest.Digest, fi os.FileInfo) Info {
}
}
// Open returns an io.ReadCloser for the blob.
//
// TODO(stevvooe): This would work much better as an io.ReaderAt in practice.
// Right now, we are doing type assertion to tease that out, but it won't scale
// well.
// Reader returns an io.ReadCloser for the blob.
func (s *store) Reader(ctx context.Context, dgst digest.Digest) (io.ReadCloser, error) {
fp, err := os.Open(s.blobPath(dgst))
if err != nil {
@ -75,6 +70,11 @@ func (s *store) Reader(ctx context.Context, dgst digest.Digest) (io.ReadCloser,
return fp, nil
}
// ReaderAt returns an io.ReaderAt for the blob.
func (s *store) ReaderAt(ctx context.Context, dgst digest.Digest) (io.ReaderAt, error) {
return readerAt{f: s.blobPath(dgst)}, nil
}
// Delete removes a blob by its digest.
//
// While this is safe to do concurrently, safe exist-removal logic must hold
@ -230,19 +230,12 @@ func (s *store) Writer(ctx context.Context, ref string, total int64, expected di
// TODO(stevvooe): Need to actually store and handle expected here. We have
// code in the service that shouldn't be dealing with this.
path, refp, data, lock, err := s.ingestPaths(ref)
if err != nil {
return nil, err
}
path, refp, data := s.ingestPaths(ref)
if err := tryLock(lock); err != nil {
if !os.IsNotExist(errors.Cause(err)) {
if err := tryLock(ref); err != nil {
return nil, errors.Wrapf(err, "locking %v failed", ref)
}
// if it doesn't exist, we'll make it so below!
}
var (
digester = digest.Canonical.Digester()
offset int64
@ -314,7 +307,6 @@ func (s *store) Writer(ctx context.Context, ref string, total int64, expected di
return &writer{
s: s,
fp: fp,
lock: lock,
ref: ref,
path: path,
offset: offset,
@ -349,25 +341,18 @@ func (s *store) ingestRoot(ref string) string {
return filepath.Join(s.root, "ingest", dgst.Hex())
}
// ingestPaths are returned, including the lockfile. The paths are the following:
// ingestPaths are returned. The paths are the following:
//
// - root: entire ingest directory
// - ref: name of the starting ref, must be unique
// - data: file where data is written
// - lock: lock file location
//
func (s *store) ingestPaths(ref string) (string, string, string, lockfile.Lockfile, error) {
func (s *store) ingestPaths(ref string) (string, string, string) {
var (
fp = s.ingestRoot(ref)
rp = filepath.Join(fp, "ref")
lp = filepath.Join(fp, "lock")
dp = filepath.Join(fp, "data")
)
lock, err := lockfile.New(lp)
if err != nil {
return "", "", "", "", errors.Wrapf(err, "error creating lockfile %v", lp)
}
return fp, rp, dp, lock, nil
return fp, rp, dp
}

View File

@ -5,8 +5,6 @@ import (
"path/filepath"
"time"
"github.com/containerd/containerd/log"
"github.com/nightlyone/lockfile"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
@ -15,7 +13,6 @@ import (
type writer struct {
s *store
fp *os.File // opened data file
lock lockfile.Lockfile
path string // path to writer dir
ref string // ref key
offset int64
@ -107,8 +104,9 @@ func (w *writer) Commit(size int64, expected digest.Digest) error {
return err
}
unlock(w.lock)
unlock(w.ref)
w.fp = nil
return nil
}
@ -122,9 +120,7 @@ func (w *writer) Commit(size int64, expected digest.Digest) error {
// To abandon a transaction completely, first call close then `Store.Remove` to
// clean up the associated resources.
func (cw *writer) Close() (err error) {
if err := unlock(cw.lock); err != nil {
log.L.Debug("unlock failed: %v", err)
}
unlock(cw.ref)
if cw.fp != nil {
cw.fp.Sync()

View File

@ -1,120 +0,0 @@
package fs
import (
"io/ioutil"
"os"
"path/filepath"
"sync"
"github.com/pkg/errors"
)
var (
bufferPool = &sync.Pool{
New: func() interface{} {
return make([]byte, 32*1024)
},
}
)
// CopyDir copies the directory from src to dst.
// Most efficient copy of files is attempted.
func CopyDir(dst, src string) error {
inodes := map[uint64]string{}
return copyDirectory(dst, src, inodes)
}
func copyDirectory(dst, src string, inodes map[uint64]string) error {
stat, err := os.Stat(src)
if err != nil {
return errors.Wrapf(err, "failed to stat %s", src)
}
if !stat.IsDir() {
return errors.Errorf("source is not directory")
}
if st, err := os.Stat(dst); err != nil {
if err := os.Mkdir(dst, stat.Mode()); err != nil {
return errors.Wrapf(err, "failed to mkdir %s", dst)
}
} else if !st.IsDir() {
return errors.Errorf("cannot copy to non-directory: %s", dst)
} else {
if err := os.Chmod(dst, stat.Mode()); err != nil {
return errors.Wrapf(err, "failed to chmod on %s", dst)
}
}
fis, err := ioutil.ReadDir(src)
if err != nil {
return errors.Wrapf(err, "failed to read %s", src)
}
if err := copyFileInfo(stat, dst); err != nil {
return errors.Wrapf(err, "failed to copy file info for %s", dst)
}
for _, fi := range fis {
source := filepath.Join(src, fi.Name())
target := filepath.Join(dst, fi.Name())
switch {
case fi.IsDir():
if err := copyDirectory(target, source, inodes); err != nil {
return err
}
continue
case (fi.Mode() & os.ModeType) == 0:
link, err := getLinkSource(target, fi, inodes)
if err != nil {
return errors.Wrap(err, "failed to get hardlink")
}
if link != "" {
if err := os.Link(link, target); err != nil {
return errors.Wrap(err, "failed to create hard link")
}
} else if err := copyFile(source, target); err != nil {
return errors.Wrap(err, "failed to copy files")
}
case (fi.Mode() & os.ModeSymlink) == os.ModeSymlink:
link, err := os.Readlink(source)
if err != nil {
return errors.Wrapf(err, "failed to read link: %s", source)
}
if err := os.Symlink(link, target); err != nil {
return errors.Wrapf(err, "failed to create symlink: %s", target)
}
case (fi.Mode() & os.ModeDevice) == os.ModeDevice:
if err := copyDevice(target, fi); err != nil {
return errors.Wrapf(err, "failed to create device")
}
default:
// TODO: Support pipes and sockets
return errors.Wrapf(err, "unsupported mode %s", fi.Mode())
}
if err := copyFileInfo(fi, target); err != nil {
return errors.Wrap(err, "failed to copy file info")
}
if err := copyXAttrs(target, source); err != nil {
return errors.Wrap(err, "failed to copy xattrs")
}
}
return nil
}
func copyFile(source, target string) error {
src, err := os.Open(source)
if err != nil {
return errors.Wrapf(err, "failed to open source %s", source)
}
defer src.Close()
tgt, err := os.Create(target)
if err != nil {
return errors.Wrapf(err, "failed to open target %s", target)
}
defer tgt.Close()
return copyFileContent(tgt, src)
}

View File

@ -1,82 +0,0 @@
package fs
import (
"io"
"os"
"syscall"
"github.com/containerd/continuity/sysx"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
)
func copyFileInfo(fi os.FileInfo, name string) error {
st := fi.Sys().(*syscall.Stat_t)
if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
return errors.Wrapf(err, "failed to chown %s", name)
}
if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
if err := os.Chmod(name, fi.Mode()); err != nil {
return errors.Wrapf(err, "failed to chmod %s", name)
}
}
timespec := []unix.Timespec{unix.Timespec(st.Atim), unix.Timespec(st.Mtim)}
if err := unix.UtimesNanoAt(unix.AT_FDCWD, name, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil {
return errors.Wrapf(err, "failed to utime %s", name)
}
return nil
}
func copyFileContent(dst, src *os.File) error {
st, err := src.Stat()
if err != nil {
return errors.Wrap(err, "unable to stat source")
}
n, err := sysx.CopyFileRange(src.Fd(), nil, dst.Fd(), nil, int(st.Size()), 0)
if err != nil {
if err != syscall.ENOSYS && err != syscall.EXDEV {
return errors.Wrap(err, "copy file range failed")
}
buf := bufferPool.Get().([]byte)
_, err = io.CopyBuffer(dst, src, buf)
bufferPool.Put(buf)
return err
}
if int64(n) != st.Size() {
return errors.Wrapf(err, "short copy: %d of %d", int64(n), st.Size())
}
return nil
}
func copyXAttrs(dst, src string) error {
xattrKeys, err := sysx.LListxattr(src)
if err != nil {
return errors.Wrapf(err, "failed to list xattrs on %s", src)
}
for _, xattr := range xattrKeys {
data, err := sysx.LGetxattr(src, xattr)
if err != nil {
return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src)
}
if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil {
return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst)
}
}
return nil
}
func copyDevice(dst string, fi os.FileInfo) error {
st, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return errors.New("unsupported stat type")
}
return syscall.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
}

View File

@ -1,65 +0,0 @@
// +build darwin freebsd
package fs
import (
"io"
"os"
"syscall"
"github.com/containerd/continuity/sysx"
"github.com/pkg/errors"
)
func copyFileInfo(fi os.FileInfo, name string) error {
st := fi.Sys().(*syscall.Stat_t)
if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
return errors.Wrapf(err, "failed to chown %s", name)
}
if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
if err := os.Chmod(name, fi.Mode()); err != nil {
return errors.Wrapf(err, "failed to chmod %s", name)
}
}
if err := syscall.UtimesNano(name, []syscall.Timespec{st.Atimespec, st.Mtimespec}); err != nil {
return errors.Wrapf(err, "failed to utime %s", name)
}
return nil
}
func copyFileContent(dst, src *os.File) error {
buf := bufferPool.Get().([]byte)
_, err := io.CopyBuffer(dst, src, buf)
bufferPool.Put(buf)
return err
}
func copyXAttrs(dst, src string) error {
xattrKeys, err := sysx.LListxattr(src)
if err != nil {
return errors.Wrapf(err, "failed to list xattrs on %s", src)
}
for _, xattr := range xattrKeys {
data, err := sysx.LGetxattr(src, xattr)
if err != nil {
return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src)
}
if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil {
return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst)
}
}
return nil
}
func copyDevice(dst string, fi os.FileInfo) error {
st, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return errors.New("unsupported stat type")
}
return syscall.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
}

View File

@ -1,33 +0,0 @@
package fs
import (
"io"
"os"
"github.com/pkg/errors"
)
func copyFileInfo(fi os.FileInfo, name string) error {
if err := os.Chmod(name, fi.Mode()); err != nil {
return errors.Wrapf(err, "failed to chmod %s", name)
}
// TODO: copy windows specific metadata
return nil
}
func copyFileContent(dst, src *os.File) error {
buf := bufferPool.Get().([]byte)
_, err := io.CopyBuffer(dst, src, buf)
bufferPool.Put(buf)
return err
}
func copyXAttrs(dst, src string) error {
return nil
}
func copyDevice(dst string, fi os.FileInfo) error {
return errors.New("device copy not supported")
}

View File

@ -1,310 +0,0 @@
package fs
import (
"context"
"os"
"path/filepath"
"strings"
"golang.org/x/sync/errgroup"
"github.com/Sirupsen/logrus"
)
// ChangeKind is the type of modification that
// a change is making.
type ChangeKind int
const (
// ChangeKindUnmodified represents an unmodified
// file
ChangeKindUnmodified = iota
// ChangeKindAdd represents an addition of
// a file
ChangeKindAdd
// ChangeKindModify represents a change to
// an existing file
ChangeKindModify
// ChangeKindDelete represents a delete of
// a file
ChangeKindDelete
)
func (k ChangeKind) String() string {
switch k {
case ChangeKindUnmodified:
return "unmodified"
case ChangeKindAdd:
return "add"
case ChangeKindModify:
return "modify"
case ChangeKindDelete:
return "delete"
default:
return ""
}
}
// Change represents single change between a diff and its parent.
type Change struct {
Kind ChangeKind
Path string
}
// ChangeFunc is the type of function called for each change
// computed during a directory changes calculation.
type ChangeFunc func(ChangeKind, string, os.FileInfo, error) error
// Changes computes changes between two directories calling the
// given change function for each computed change. The first
// directory is intended to the base directory and second
// directory the changed directory.
//
// The change callback is called by the order of path names and
// should be appliable in that order.
// Due to this apply ordering, the following is true
// - Removed directory trees only create a single change for the root
// directory removed. Remaining changes are implied.
// - A directory which is modified to become a file will not have
// delete entries for sub-path items, their removal is implied
// by the removal of the parent directory.
//
// Opaque directories will not be treated specially and each file
// removed from the base directory will show up as a removal.
//
// File content comparisons will be done on files which have timestamps
// which may have been truncated. If either of the files being compared
// has a zero value nanosecond value, each byte will be compared for
// differences. If 2 files have the same seconds value but different
// nanosecond values where one of those values is zero, the files will
// be considered unchanged if the content is the same. This behavior
// is to account for timestamp truncation during archiving.
func Changes(ctx context.Context, a, b string, changeFn ChangeFunc) error {
if a == "" {
logrus.Debugf("Using single walk diff for %s", b)
return addDirChanges(ctx, changeFn, b)
} else if diffOptions := detectDirDiff(b, a); diffOptions != nil {
logrus.Debugf("Using single walk diff for %s from %s", diffOptions.diffDir, a)
return diffDirChanges(ctx, changeFn, a, diffOptions)
}
logrus.Debugf("Using double walk diff for %s from %s", b, a)
return doubleWalkDiff(ctx, changeFn, a, b)
}
func addDirChanges(ctx context.Context, changeFn ChangeFunc, root string) error {
return filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
// Rebase path
path, err = filepath.Rel(root, path)
if err != nil {
return err
}
path = filepath.Join(string(os.PathSeparator), path)
// Skip root
if path == string(os.PathSeparator) {
return nil
}
return changeFn(ChangeKindAdd, path, f, nil)
})
}
// diffDirOptions is used when the diff can be directly calculated from
// a diff directory to its base, without walking both trees.
type diffDirOptions struct {
diffDir string
skipChange func(string) (bool, error)
deleteChange func(string, string, os.FileInfo) (string, error)
}
// diffDirChanges walks the diff directory and compares changes against the base.
func diffDirChanges(ctx context.Context, changeFn ChangeFunc, base string, o *diffDirOptions) error {
changedDirs := make(map[string]struct{})
return filepath.Walk(o.diffDir, func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
// Rebase path
path, err = filepath.Rel(o.diffDir, path)
if err != nil {
return err
}
path = filepath.Join(string(os.PathSeparator), path)
// Skip root
if path == string(os.PathSeparator) {
return nil
}
// TODO: handle opaqueness, start new double walker at this
// location to get deletes, and skip tree in single walker
if o.skipChange != nil {
if skip, err := o.skipChange(path); skip {
return err
}
}
var kind ChangeKind
deletedFile, err := o.deleteChange(o.diffDir, path, f)
if err != nil {
return err
}
// Find out what kind of modification happened
if deletedFile != "" {
path = deletedFile
kind = ChangeKindDelete
f = nil
} else {
// Otherwise, the file was added
kind = ChangeKindAdd
// ...Unless it already existed in a base, in which case, it's a modification
stat, err := os.Stat(filepath.Join(base, path))
if err != nil && !os.IsNotExist(err) {
return err
}
if err == nil {
// The file existed in the base, so that's a modification
// However, if it's a directory, maybe it wasn't actually modified.
// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
if stat.IsDir() && f.IsDir() {
if f.Size() == stat.Size() && f.Mode() == stat.Mode() && sameFsTime(f.ModTime(), stat.ModTime()) {
// Both directories are the same, don't record the change
return nil
}
}
kind = ChangeKindModify
}
}
// If /foo/bar/file.txt is modified, then /foo/bar must be part of the changed files.
// This block is here to ensure the change is recorded even if the
// modify time, mode and size of the parent directory in the rw and ro layers are all equal.
// Check https://github.com/docker/docker/pull/13590 for details.
if f.IsDir() {
changedDirs[path] = struct{}{}
}
if kind == ChangeKindAdd || kind == ChangeKindDelete {
parent := filepath.Dir(path)
if _, ok := changedDirs[parent]; !ok && parent != "/" {
pi, err := os.Stat(filepath.Join(o.diffDir, parent))
if err := changeFn(ChangeKindModify, parent, pi, err); err != nil {
return err
}
changedDirs[parent] = struct{}{}
}
}
return changeFn(kind, path, f, nil)
})
}
// doubleWalkDiff walks both directories to create a diff
func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err error) {
g, ctx := errgroup.WithContext(ctx)
var (
c1 = make(chan *currentPath)
c2 = make(chan *currentPath)
f1, f2 *currentPath
rmdir string
)
g.Go(func() error {
defer close(c1)
return pathWalk(ctx, a, c1)
})
g.Go(func() error {
defer close(c2)
return pathWalk(ctx, b, c2)
})
g.Go(func() error {
for c1 != nil || c2 != nil {
if f1 == nil && c1 != nil {
f1, err = nextPath(ctx, c1)
if err != nil {
return err
}
if f1 == nil {
c1 = nil
}
}
if f2 == nil && c2 != nil {
f2, err = nextPath(ctx, c2)
if err != nil {
return err
}
if f2 == nil {
c2 = nil
}
}
if f1 == nil && f2 == nil {
continue
}
var f os.FileInfo
k, p := pathChange(f1, f2)
switch k {
case ChangeKindAdd:
if rmdir != "" {
rmdir = ""
}
f = f2.f
f2 = nil
case ChangeKindDelete:
// Check if this file is already removed by being
// under of a removed directory
if rmdir != "" && strings.HasPrefix(f1.path, rmdir) {
f1 = nil
continue
} else if rmdir == "" && f1.f.IsDir() {
rmdir = f1.path + string(os.PathSeparator)
} else if rmdir != "" {
rmdir = ""
}
f1 = nil
case ChangeKindModify:
same, err := sameFile(f1, f2)
if err != nil {
return err
}
if f1.f.IsDir() && !f2.f.IsDir() {
rmdir = f1.path + string(os.PathSeparator)
} else if rmdir != "" {
rmdir = ""
}
f = f2.f
f1 = nil
f2 = nil
if same {
if !isLinked(f) {
continue
}
k = ChangeKindUnmodified
}
}
if err := changeFn(k, p, f, nil); err != nil {
return err
}
}
return nil
})
return g.Wait()
}

View File

@ -1,102 +0,0 @@
// +build !windows
package fs
import (
"bytes"
"os"
"path/filepath"
"strings"
"syscall"
"github.com/containerd/continuity/sysx"
"github.com/pkg/errors"
)
// whiteouts are files with a special meaning for the layered filesystem.
// Docker uses AUFS whiteout files inside exported archives. In other
// filesystems these files are generated/handled on tar creation/extraction.
// whiteoutPrefix prefix means file is a whiteout. If this is followed by a
// filename this means that file has been removed from the base layer.
const whiteoutPrefix = ".wh."
// whiteoutMetaPrefix prefix means whiteout has a special meaning and is not
// for removing an actual file. Normally these files are excluded from exported
// archives.
const whiteoutMetaPrefix = whiteoutPrefix + whiteoutPrefix
// whiteoutLinkDir is a directory AUFS uses for storing hardlink links to other
// layers. Normally these should not go into exported archives and all changed
// hardlinks should be copied to the top layer.
const whiteoutLinkDir = whiteoutMetaPrefix + "plnk"
// whiteoutOpaqueDir file means directory has been made opaque - meaning
// readdir calls to this directory do not follow to lower layers.
const whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq"
// detectDirDiff returns diff dir options if a directory could
// be found in the mount info for upper which is the direct
// diff with the provided lower directory
func detectDirDiff(upper, lower string) *diffDirOptions {
// TODO: get mount options for upper
// TODO: detect AUFS
// TODO: detect overlay
return nil
}
func aufsMetadataSkip(path string) (skip bool, err error) {
skip, err = filepath.Match(string(os.PathSeparator)+whiteoutMetaPrefix+"*", path)
if err != nil {
skip = true
}
return
}
func aufsDeletedFile(root, path string, fi os.FileInfo) (string, error) {
f := filepath.Base(path)
// If there is a whiteout, then the file was removed
if strings.HasPrefix(f, whiteoutPrefix) {
originalFile := f[len(whiteoutPrefix):]
return filepath.Join(filepath.Dir(path), originalFile), nil
}
return "", nil
}
// compareSysStat returns whether the stats are equivalent,
// whether the files are considered the same file, and
// an error
func compareSysStat(s1, s2 interface{}) (bool, error) {
ls1, ok := s1.(*syscall.Stat_t)
if !ok {
return false, nil
}
ls2, ok := s2.(*syscall.Stat_t)
if !ok {
return false, nil
}
return ls1.Mode == ls2.Mode && ls1.Uid == ls2.Uid && ls1.Gid == ls2.Gid && ls1.Rdev == ls2.Rdev, nil
}
func compareCapabilities(p1, p2 string) (bool, error) {
c1, err := sysx.LGetxattr(p1, "security.capability")
if err != nil && err != sysx.ENODATA {
return false, errors.Wrapf(err, "failed to get xattr for %s", p1)
}
c2, err := sysx.LGetxattr(p2, "security.capability")
if err != nil && err != sysx.ENODATA {
return false, errors.Wrapf(err, "failed to get xattr for %s", p2)
}
return bytes.Equal(c1, c2), nil
}
func isLinked(f os.FileInfo) bool {
s, ok := f.Sys().(*syscall.Stat_t)
if !ok {
return false
}
return !f.IsDir() && s.Nlink > 1
}

View File

@ -1,21 +0,0 @@
package fs
import "os"
func detectDirDiff(upper, lower string) *diffDirOptions {
return nil
}
func compareSysStat(s1, s2 interface{}) (bool, error) {
// TODO: Use windows specific sys type
return false, nil
}
func compareCapabilities(p1, p2 string) (bool, error) {
// TODO: Use windows equivalent
return true, nil
}
func isLinked(os.FileInfo) bool {
return false
}

View File

@ -1,87 +0,0 @@
// +build linux
package fs
import (
"fmt"
"io/ioutil"
"os"
"syscall"
"unsafe"
)
func locateDummyIfEmpty(path string) (string, error) {
children, err := ioutil.ReadDir(path)
if err != nil {
return "", err
}
if len(children) != 0 {
return "", nil
}
dummyFile, err := ioutil.TempFile(path, "fsutils-dummy")
if err != nil {
return "", err
}
name := dummyFile.Name()
err = dummyFile.Close()
return name, err
}
// SupportsDType returns whether the filesystem mounted on path supports d_type
func SupportsDType(path string) (bool, error) {
// locate dummy so that we have at least one dirent
dummy, err := locateDummyIfEmpty(path)
if err != nil {
return false, err
}
if dummy != "" {
defer os.Remove(dummy)
}
visited := 0
supportsDType := true
fn := func(ent *syscall.Dirent) bool {
visited++
if ent.Type == syscall.DT_UNKNOWN {
supportsDType = false
// stop iteration
return true
}
// continue iteration
return false
}
if err = iterateReadDir(path, fn); err != nil {
return false, err
}
if visited == 0 {
return false, fmt.Errorf("did not hit any dirent during iteration %s", path)
}
return supportsDType, nil
}
func iterateReadDir(path string, fn func(*syscall.Dirent) bool) error {
d, err := os.Open(path)
if err != nil {
return err
}
defer d.Close()
fd := int(d.Fd())
buf := make([]byte, 4096)
for {
nbytes, err := syscall.ReadDirent(fd, buf)
if err != nil {
return err
}
if nbytes == 0 {
break
}
for off := 0; off < nbytes; {
ent := (*syscall.Dirent)(unsafe.Pointer(&buf[off]))
if stop := fn(ent); stop {
return nil
}
off += int(ent.Reclen)
}
}
return nil
}

View File

@ -1,12 +0,0 @@
package fs
type Usage struct {
Inodes int64
Size int64
}
// DiskUsage counts the number of inodes and disk usage for the resources under
// path.
func DiskUsage(roots ...string) (Usage, error) {
return diskUsage(roots...)
}

View File

@ -1,42 +0,0 @@
// +build !windows
package fs
import (
"os"
"path/filepath"
"syscall"
)
func diskUsage(roots ...string) (Usage, error) {
type inode struct {
// TODO(stevvooe): Can probably reduce memory usage by not tracking
// device, but we can leave this right for now.
dev, ino uint64
}
var (
size int64
inodes = map[inode]struct{}{} // expensive!
)
for _, root := range roots {
if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil {
return err
}
stat := fi.Sys().(*syscall.Stat_t)
inodes[inode{dev: uint64(stat.Dev), ino: uint64(stat.Ino)}] = struct{}{}
size += fi.Size()
return nil
}); err != nil {
return Usage{}, err
}
}
return Usage{
Inodes: int64(len(inodes)),
Size: size,
}, nil
}

View File

@ -1,33 +0,0 @@
// +build windows
package fs
import (
"os"
"path/filepath"
)
func diskUsage(roots ...string) (Usage, error) {
var (
size int64
)
// TODO(stevvooe): Support inodes (or equivalent) for windows.
for _, root := range roots {
if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil {
return err
}
size += fi.Size()
return nil
}); err != nil {
return Usage{}, err
}
}
return Usage{
Size: size,
}, nil
}

View File

@ -1,27 +0,0 @@
package fs
import "os"
// GetLinkID returns an identifier representing the node a hardlink is pointing
// to. If the file is not hard linked then 0 will be returned.
func GetLinkInfo(fi os.FileInfo) (uint64, bool) {
return getLinkInfo(fi)
}
// getLinkSource returns a path for the given name and
// file info to its link source in the provided inode
// map. If the given file name is not in the map and
// has other links, it is added to the inode map
// to be a source for other link locations.
func getLinkSource(name string, fi os.FileInfo, inodes map[uint64]string) (string, error) {
inode, isHardlink := getLinkInfo(fi)
if !isHardlink {
return "", nil
}
path, ok := inodes[inode]
if !ok {
inodes[inode] = name
}
return path, nil
}

View File

@ -1,17 +0,0 @@
// +build !windows
package fs
import (
"os"
"syscall"
)
func getLinkInfo(fi os.FileInfo) (uint64, bool) {
s, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return 0, false
}
return uint64(s.Ino), !fi.IsDir() && s.Nlink > 1
}

View File

@ -1,7 +0,0 @@
package fs
import "os"
func getLinkInfo(fi os.FileInfo) (uint64, bool) {
return 0, false
}

View File

@ -1,162 +0,0 @@
package fs
import (
"bytes"
"context"
"io"
"os"
"path/filepath"
"strings"
)
type currentPath struct {
path string
f os.FileInfo
fullPath string
}
func pathChange(lower, upper *currentPath) (ChangeKind, string) {
if lower == nil {
if upper == nil {
panic("cannot compare nil paths")
}
return ChangeKindAdd, upper.path
}
if upper == nil {
return ChangeKindDelete, lower.path
}
// TODO: compare by directory
switch i := strings.Compare(lower.path, upper.path); {
case i < 0:
// File in lower that is not in upper
return ChangeKindDelete, lower.path
case i > 0:
// File in upper that is not in lower
return ChangeKindAdd, upper.path
default:
return ChangeKindModify, upper.path
}
}
func sameFile(f1, f2 *currentPath) (bool, error) {
if os.SameFile(f1.f, f2.f) {
return true, nil
}
equalStat, err := compareSysStat(f1.f.Sys(), f2.f.Sys())
if err != nil || !equalStat {
return equalStat, err
}
if eq, err := compareCapabilities(f1.fullPath, f2.fullPath); err != nil || !eq {
return eq, err
}
// If not a directory also check size, modtime, and content
if !f1.f.IsDir() {
if f1.f.Size() != f2.f.Size() {
return false, nil
}
t1 := f1.f.ModTime()
t2 := f2.f.ModTime()
if t1.Unix() != t2.Unix() {
return false, nil
}
// If the timestamp may have been truncated in one of the
// files, check content of file to determine difference
if t1.Nanosecond() == 0 || t2.Nanosecond() == 0 {
if f1.f.Size() > 0 {
eq, err := compareFileContent(f1.fullPath, f2.fullPath)
if err != nil || !eq {
return eq, err
}
}
} else if t1.Nanosecond() != t2.Nanosecond() {
return false, nil
}
}
return true, nil
}
const compareChuckSize = 32 * 1024
// compareFileContent compares the content of 2 same sized files
// by comparing each byte.
func compareFileContent(p1, p2 string) (bool, error) {
f1, err := os.Open(p1)
if err != nil {
return false, err
}
defer f1.Close()
f2, err := os.Open(p2)
if err != nil {
return false, err
}
defer f2.Close()
b1 := make([]byte, compareChuckSize)
b2 := make([]byte, compareChuckSize)
for {
n1, err1 := f1.Read(b1)
if err1 != nil && err1 != io.EOF {
return false, err1
}
n2, err2 := f2.Read(b2)
if err2 != nil && err2 != io.EOF {
return false, err2
}
if n1 != n2 || !bytes.Equal(b1[:n1], b2[:n2]) {
return false, nil
}
if err1 == io.EOF && err2 == io.EOF {
return true, nil
}
}
}
func pathWalk(ctx context.Context, root string, pathC chan<- *currentPath) error {
return filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
// Rebase path
path, err = filepath.Rel(root, path)
if err != nil {
return err
}
path = filepath.Join(string(os.PathSeparator), path)
// Skip root
if path == string(os.PathSeparator) {
return nil
}
p := &currentPath{
path: path,
f: f,
fullPath: filepath.Join(root, path),
}
select {
case <-ctx.Done():
return ctx.Err()
case pathC <- p:
return nil
}
})
}
func nextPath(ctx context.Context, pathC <-chan *currentPath) (*currentPath, error) {
select {
case <-ctx.Done():
return nil, ctx.Err()
case p := <-pathC:
return p, nil
}
}

View File

@ -1,13 +0,0 @@
package fs
import "time"
// Gnu tar and the go tar writer don't have sub-second mtime
// precision, which is problematic when we apply changes via tar
// files, we handle this by comparing for exact times, *or* same
// second count and either a or b having exactly 0 nanoseconds
func sameFsTime(a, b time.Time) bool {
return a == b ||
(a.Unix() == b.Unix() &&
(a.Nanosecond() == 0 || b.Nanosecond() == 0))
}

View File

@ -33,34 +33,7 @@ type Store interface {
// The caller can then use the descriptor to resolve and process the
// configuration of the image.
func (image *Image) Config(ctx context.Context, provider content.Provider) (ocispec.Descriptor, error) {
var configDesc ocispec.Descriptor
return configDesc, Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
switch image.Target.MediaType {
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
rc, err := provider.Reader(ctx, image.Target.Digest)
if err != nil {
return nil, err
}
defer rc.Close()
p, err := ioutil.ReadAll(rc)
if err != nil {
return nil, err
}
var manifest ocispec.Manifest
if err := json.Unmarshal(p, &manifest); err != nil {
return nil, err
}
configDesc = manifest.Config
return nil, nil
default:
return nil, errors.New("could not resolve config")
}
}), image.Target)
return Config(ctx, provider, image.Target)
}
// RootFS returns the unpacked diffids that make up and images rootfs.
@ -112,12 +85,43 @@ func (image *Image) Size(ctx context.Context, provider content.Provider) (int64,
}), image.Target)
}
func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor) (ocispec.Descriptor, error) {
var configDesc ocispec.Descriptor
return configDesc, Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
switch image.MediaType {
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
rc, err := provider.Reader(ctx, image.Digest)
if err != nil {
return nil, err
}
defer rc.Close()
p, err := ioutil.ReadAll(rc)
if err != nil {
return nil, err
}
var manifest ocispec.Manifest
if err := json.Unmarshal(p, &manifest); err != nil {
return nil, err
}
configDesc = manifest.Config
return nil, nil
default:
return nil, errors.New("could not resolve config")
}
}), image)
}
// RootFS returns the unpacked diffids that make up and images rootfs.
//
// These are used to verify that a set of layers unpacked to the expected
// values.
func RootFS(ctx context.Context, provider content.Provider, desc ocispec.Descriptor) ([]digest.Digest, error) {
p, err := content.ReadBlob(ctx, provider, desc.Digest)
func RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.Descriptor) ([]digest.Digest, error) {
p, err := content.ReadBlob(ctx, provider, configDesc.Digest)
if err != nil {
return nil, err
}

View File

@ -16,4 +16,6 @@ const (
MediaTypeContainerd1Resource = "application/vnd.containerd.container.resource.tar"
MediaTypeContainerd1RW = "application/vnd.containerd.container.rw.tar"
MediaTypeContainerd1CheckpointConfig = "application/vnd.containerd.container.checkpoint.config.v1+json"
// Legacy Docker schema1 manifest
MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws"
)

View File

@ -2,13 +2,36 @@ package metadata
import (
"github.com/boltdb/bolt"
"github.com/containerd/containerd/log"
)
// The layout where a "/" delineates a bucket is desribed in the following
// section. Please try to follow this as closely as possible when adding
// functionality. We can bolster this with helpers and more structure if that
// becomes an issue.
//
// Generically, we try to do the following:
//
// <version>/<namespace>/<object>/<key> -> <field>
//
// version: Currently, this is "v1". Additions can be made to v1 in a backwards
// compatible way. If the layout changes, a new version must be made, along
// with a migration.
//
// namespace: the namespace to which this object belongs.
//
// object: defines which object set is stored in the bucket. There are two
// special objects, "labels" and "indexes". The "labels" bucket stores the
// labels for the parent namespace. The "indexes" object is reserved for
// indexing objects, if we require in the future.
//
// key: object-specific key identifying the storage bucket for the objects
// contents.
var (
bucketKeyStorageVersion = []byte("v1")
bucketKeyImages = []byte("images")
bucketKeyContainers = []byte("containers")
bucketKeyVersion = []byte("v1")
bucketKeyObjectLabels = []byte("labels") // stores the labels for a namespace.
bucketKeyObjectIndexes = []byte("indexes") // reserved
bucketKeyObjectImages = []byte("images") // stores image objects
bucketKeyObjectContainers = []byte("containers") // stores container objects
bucketKeyDigest = []byte("digest")
bucketKeyMediaType = []byte("mediatype")
@ -18,23 +41,10 @@ var (
bucketKeyRuntime = []byte("runtime")
bucketKeySpec = []byte("spec")
bucketKeyRootFS = []byte("rootfs")
bucketKeyCreatedAt = []byte("createdat")
bucketKeyUpdatedAt = []byte("updatedat")
)
// InitDB will initialize the database for use. The database must be opened for
// write and the caller must not be holding an open transaction.
func InitDB(db *bolt.DB) error {
log.L.Debug("init db")
return db.Update(func(tx *bolt.Tx) error {
if _, err := createBucketIfNotExists(tx, bucketKeyStorageVersion, bucketKeyImages); err != nil {
return err
}
if _, err := createBucketIfNotExists(tx, bucketKeyStorageVersion, bucketKeyContainers); err != nil {
return err
}
return nil
})
}
func getBucket(tx *bolt.Tx, keys ...[]byte) *bolt.Bucket {
bkt := tx.Bucket(keys[0])
@ -64,44 +74,52 @@ func createBucketIfNotExists(tx *bolt.Tx, keys ...[]byte) (*bolt.Bucket, error)
return bkt, nil
}
func withImagesBucket(tx *bolt.Tx, fn func(bkt *bolt.Bucket) error) error {
bkt := getImagesBucket(tx)
if bkt == nil {
return ErrNotFound
func namespaceLabelsBucketPath(namespace string) [][]byte {
return [][]byte{bucketKeyVersion, []byte(namespace), bucketKeyObjectLabels}
}
func withNamespacesLabelsBucket(tx *bolt.Tx, namespace string, fn func(bkt *bolt.Bucket) error) error {
bkt, err := createBucketIfNotExists(tx, namespaceLabelsBucketPath(namespace)...)
if err != nil {
return err
}
return fn(bkt)
}
func withImageBucket(tx *bolt.Tx, name string, fn func(bkt *bolt.Bucket) error) error {
bkt := getImageBucket(tx, name)
if bkt == nil {
return ErrNotFound
func getNamespaceLabelsBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
return getBucket(tx, namespaceLabelsBucketPath(namespace)...)
}
func imagesBucketPath(namespace string) [][]byte {
return [][]byte{bucketKeyVersion, []byte(namespace), bucketKeyObjectImages}
}
func withImagesBucket(tx *bolt.Tx, namespace string, fn func(bkt *bolt.Bucket) error) error {
bkt, err := createBucketIfNotExists(tx, imagesBucketPath(namespace)...)
if err != nil {
return err
}
return fn(bkt)
}
func getImagesBucket(tx *bolt.Tx) *bolt.Bucket {
return getBucket(tx, bucketKeyStorageVersion, bucketKeyImages)
func getImagesBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
return getBucket(tx, imagesBucketPath(namespace)...)
}
func getImageBucket(tx *bolt.Tx, name string) *bolt.Bucket {
return getBucket(tx, bucketKeyStorageVersion, bucketKeyImages, []byte(name))
}
func createContainersBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
bkt, err := tx.CreateBucketIfNotExists(bucketKeyStorageVersion)
func createContainersBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) {
bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers)
if err != nil {
return nil, err
}
return bkt.CreateBucketIfNotExists(bucketKeyContainers)
return bkt, nil
}
func getContainersBucket(tx *bolt.Tx) *bolt.Bucket {
return getBucket(tx, bucketKeyStorageVersion, bucketKeyContainers)
func getContainersBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers)
}
func getContainerBucket(tx *bolt.Tx, id string) *bolt.Bucket {
return getBucket(tx, bucketKeyStorageVersion, bucketKeyContainers, []byte(id))
func getContainerBucket(tx *bolt.Tx, namespace, id string) *bolt.Bucket {
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers, []byte(id))
}

View File

@ -2,9 +2,11 @@ package metadata
import (
"context"
"time"
"github.com/boltdb/bolt"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/namespaces"
"github.com/pkg/errors"
)
@ -19,7 +21,12 @@ func NewContainerStore(tx *bolt.Tx) containers.Store {
}
func (s *containerStore) Get(ctx context.Context, id string) (containers.Container, error) {
bkt := getContainerBucket(s.tx, id)
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return containers.Container{}, err
}
bkt := getContainerBucket(s.tx, namespace, id)
if bkt == nil {
return containers.Container{}, errors.Wrap(ErrNotFound, "bucket does not exist")
}
@ -33,14 +40,19 @@ func (s *containerStore) Get(ctx context.Context, id string) (containers.Contain
}
func (s *containerStore) List(ctx context.Context, filter string) ([]containers.Container, error) {
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return nil, err
}
var (
m = []containers.Container{}
bkt = getContainersBucket(s.tx)
m []containers.Container
bkt = getContainersBucket(s.tx, namespace)
)
if bkt == nil {
return m, nil
}
err := bkt.ForEach(func(k, v []byte) error {
if err := bkt.ForEach(func(k, v []byte) error {
cbkt := bkt.Bucket(k)
if cbkt == nil {
return nil
@ -52,8 +64,7 @@ func (s *containerStore) List(ctx context.Context, filter string) ([]containers.
}
m = append(m, container)
return nil
})
if err != nil {
}); err != nil {
return nil, err
}
@ -61,7 +72,12 @@ func (s *containerStore) List(ctx context.Context, filter string) ([]containers.
}
func (s *containerStore) Create(ctx context.Context, container containers.Container) (containers.Container, error) {
bkt, err := createContainersBucket(s.tx)
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return containers.Container{}, err
}
bkt, err := createContainersBucket(s.tx, namespace)
if err != nil {
return containers.Container{}, err
}
@ -74,6 +90,8 @@ func (s *containerStore) Create(ctx context.Context, container containers.Contai
return containers.Container{}, err
}
container.CreatedAt = time.Now()
container.UpdatedAt = container.CreatedAt
if err := writeContainer(&container, cbkt); err != nil {
return containers.Container{}, errors.Wrap(err, "failed to write container")
}
@ -82,7 +100,12 @@ func (s *containerStore) Create(ctx context.Context, container containers.Contai
}
func (s *containerStore) Update(ctx context.Context, container containers.Container) (containers.Container, error) {
bkt := getContainersBucket(s.tx)
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return containers.Container{}, err
}
bkt := getContainersBucket(s.tx, namespace)
if bkt == nil {
return containers.Container{}, errors.Wrap(ErrNotFound, "no containers")
}
@ -92,6 +115,7 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
return containers.Container{}, errors.Wrap(ErrNotFound, "no content for id")
}
container.UpdatedAt = time.Now()
if err := writeContainer(&container, cbkt); err != nil {
return containers.Container{}, errors.Wrap(err, "failed to write container")
}
@ -100,13 +124,17 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
}
func (s *containerStore) Delete(ctx context.Context, id string) error {
bkt := getContainersBucket(s.tx)
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return err
}
bkt := getContainersBucket(s.tx, namespace)
if bkt == nil {
return errors.Wrap(ErrNotFound, "no containers")
}
err := bkt.DeleteBucket([]byte(id))
if err == bolt.ErrBucketNotFound {
if err := bkt.DeleteBucket([]byte(id)); err == bolt.ErrBucketNotFound {
return errors.Wrap(ErrNotFound, "no content for id")
}
return err
@ -120,9 +148,18 @@ func readContainer(container *containers.Container, bkt *bolt.Bucket) error {
case string(bucketKeyRuntime):
container.Runtime = string(v)
case string(bucketKeySpec):
container.Spec = v
container.Spec = make([]byte, len(v))
copy(container.Spec, v)
case string(bucketKeyRootFS):
container.RootFS = string(v)
case string(bucketKeyCreatedAt):
if err := container.CreatedAt.UnmarshalBinary(v); err != nil {
return err
}
case string(bucketKeyUpdatedAt):
if err := container.UpdatedAt.UnmarshalBinary(v); err != nil {
return err
}
case string(bucketKeyLabels):
lbkt := bkt.Bucket(bucketKeyLabels)
if lbkt == nil {
@ -142,11 +179,21 @@ func readContainer(container *containers.Container, bkt *bolt.Bucket) error {
}
func writeContainer(container *containers.Container, bkt *bolt.Bucket) error {
createdAt, err := container.CreatedAt.MarshalBinary()
if err != nil {
return err
}
updatedAt, err := container.UpdatedAt.MarshalBinary()
if err != nil {
return err
}
for _, v := range [][2][]byte{
{bucketKeyImage, []byte(container.Image)},
{bucketKeyRuntime, []byte(container.Runtime)},
{bucketKeySpec, container.Spec},
{bucketKeyRootFS, []byte(container.RootFS)},
{bucketKeyCreatedAt, createdAt},
{bucketKeyUpdatedAt, updatedAt},
} {
if err := bkt.Put(v[0], v[1]); err != nil {
return err

View File

@ -5,6 +5,7 @@ import "github.com/pkg/errors"
var (
ErrExists = errors.New("metadata: exists")
ErrNotFound = errors.New("metadata: not found")
ErrNotEmpty = errors.New("metadata: namespace not empty")
)
// IsNotFound returns true if the error is due to a missing image.
@ -15,3 +16,7 @@ func IsNotFound(err error) bool {
func IsExists(err error) bool {
return errors.Cause(err) == ErrExists
}
func IsNotEmpty(err error) bool {
return errors.Cause(err) == ErrNotEmpty
}

View File

@ -7,6 +7,7 @@ import (
"github.com/boltdb/bolt"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/namespaces"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
@ -21,10 +22,24 @@ func NewImageStore(tx *bolt.Tx) images.Store {
func (s *imageStore) Get(ctx context.Context, name string) (images.Image, error) {
var image images.Image
if err := withImageBucket(s.tx, name, func(bkt *bolt.Bucket) error {
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return images.Image{}, err
}
bkt := getImagesBucket(s.tx, namespace)
if bkt == nil {
return images.Image{}, ErrNotFound
}
ibkt := bkt.Bucket([]byte(name))
if ibkt == nil {
return images.Image{}, ErrNotFound
}
image.Name = name
return readImage(&image, bkt)
}); err != nil {
if err := readImage(&image, ibkt); err != nil {
return images.Image{}, err
}
@ -32,7 +47,12 @@ func (s *imageStore) Get(ctx context.Context, name string) (images.Image, error)
}
func (s *imageStore) Put(ctx context.Context, name string, desc ocispec.Descriptor) error {
return withImagesBucket(s.tx, func(bkt *bolt.Bucket) error {
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return err
}
return withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
ibkt, err := bkt.CreateBucketIfNotExists([]byte(name))
if err != nil {
return err
@ -64,9 +84,17 @@ func (s *imageStore) Put(ctx context.Context, name string, desc ocispec.Descript
func (s *imageStore) List(ctx context.Context) ([]images.Image, error) {
var m []images.Image
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return nil, err
}
if err := withImagesBucket(s.tx, func(bkt *bolt.Bucket) error {
return bkt.ForEach(func(k, v []byte) error {
bkt := getImagesBucket(s.tx, namespace)
if bkt == nil {
return nil, nil // empty store
}
if err := bkt.ForEach(func(k, v []byte) error {
var (
image = images.Image{
Name: string(k),
@ -80,7 +108,6 @@ func (s *imageStore) List(ctx context.Context) ([]images.Image, error) {
m = append(m, image)
return nil
})
}); err != nil {
return nil, err
}
@ -89,7 +116,12 @@ func (s *imageStore) List(ctx context.Context) ([]images.Image, error) {
}
func (s *imageStore) Delete(ctx context.Context, name string) error {
return withImagesBucket(s.tx, func(bkt *bolt.Bucket) error {
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return err
}
return withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
err := bkt.DeleteBucket([]byte(name))
if err == bolt.ErrBucketNotFound {
return ErrNotFound

View File

@ -0,0 +1,145 @@
package metadata
import (
"context"
"github.com/boltdb/bolt"
"github.com/containerd/containerd/namespaces"
)
type namespaceStore struct {
tx *bolt.Tx
}
func NewNamespaceStore(tx *bolt.Tx) namespaces.Store {
return &namespaceStore{tx: tx}
}
func (s *namespaceStore) Create(ctx context.Context, namespace string, labels map[string]string) error {
topbkt, err := createBucketIfNotExists(s.tx, bucketKeyVersion)
if err != nil {
return err
}
// provides the already exists error.
bkt, err := topbkt.CreateBucket([]byte(namespace))
if err != nil {
if err == bolt.ErrBucketExists {
return ErrExists
}
return err
}
lbkt, err := bkt.CreateBucketIfNotExists(bucketKeyObjectLabels)
if err != nil {
return err
}
for k, v := range labels {
if err := lbkt.Put([]byte(k), []byte(v)); err != nil {
return err
}
}
return nil
}
func (s *namespaceStore) Labels(ctx context.Context, namespace string) (map[string]string, error) {
labels := map[string]string{}
bkt := getNamespaceLabelsBucket(s.tx, namespace)
if bkt == nil {
return labels, nil
}
if err := bkt.ForEach(func(k, v []byte) error {
labels[string(k)] = string(v)
return nil
}); err != nil {
return nil, err
}
return labels, nil
}
func (s *namespaceStore) SetLabel(ctx context.Context, namespace, key, value string) error {
return withNamespacesLabelsBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
if value == "" {
return bkt.Delete([]byte(key))
}
return bkt.Put([]byte(key), []byte(value))
})
}
func (s *namespaceStore) List(ctx context.Context) ([]string, error) {
bkt := getBucket(s.tx, bucketKeyVersion)
if bkt == nil {
return nil, nil // no namespaces!
}
var namespaces []string
if err := bkt.ForEach(func(k, v []byte) error {
if v != nil {
return nil // not a bucket
}
namespaces = append(namespaces, string(k))
return nil
}); err != nil {
return nil, err
}
return namespaces, nil
}
func (s *namespaceStore) Delete(ctx context.Context, namespace string) error {
bkt := getBucket(s.tx, bucketKeyVersion)
if empty, err := s.namespaceEmpty(ctx, namespace); err != nil {
return err
} else if !empty {
return ErrNotEmpty
}
if err := bkt.DeleteBucket([]byte(namespace)); err != nil {
if err == bolt.ErrBucketNotFound {
return ErrNotFound
}
return err
}
return nil
}
func (s *namespaceStore) namespaceEmpty(ctx context.Context, namespace string) (bool, error) {
ctx = namespaces.WithNamespace(ctx, namespace)
// need to check the various object stores.
imageStore := NewImageStore(s.tx)
images, err := imageStore.List(ctx)
if err != nil {
return false, err
}
if len(images) > 0 {
return false, nil
}
containerStore := NewContainerStore(s.tx)
containers, err := containerStore.List(ctx, "")
if err != nil {
return false, err
}
if len(containers) > 0 {
return false, nil
}
// TODO(stevvooe): Need to add check for content store, as well. Still need
// to make content store namespace aware.
return true, nil
}

View File

@ -0,0 +1,42 @@
package namespaces
import (
"github.com/pkg/errors"
"golang.org/x/net/context"
)
var (
errNamespaceRequired = errors.New("namespace is required")
)
type namespaceKey struct{}
func WithNamespace(ctx context.Context, namespace string) context.Context {
ctx = context.WithValue(ctx, namespaceKey{}, namespace) // set our key for namespace
// also store on the grpc headers so it gets picked up by any clients that
// are using this.
return withGRPCNamespaceHeader(ctx, namespace)
}
func Namespace(ctx context.Context) (string, bool) {
namespace, ok := ctx.Value(namespaceKey{}).(string)
if !ok {
return fromGRPCHeader(ctx)
}
return namespace, ok
}
func IsNamespaceRequired(err error) bool {
return errors.Cause(err) == errNamespaceRequired
}
func NamespaceRequired(ctx context.Context) (string, error) {
namespace, ok := Namespace(ctx)
if !ok || namespace == "" {
return "", errNamespaceRequired
}
return namespace, nil
}

View File

@ -0,0 +1,44 @@
package namespaces
import (
"golang.org/x/net/context"
"google.golang.org/grpc/metadata"
)
const (
// GRPCHeader defines the header name for specifying a containerd namespace.
GRPCHeader = "containerd-namespace"
)
// NOTE(stevvooe): We can stub this file out if we don't want a grpc dependency here.
func withGRPCNamespaceHeader(ctx context.Context, namespace string) context.Context {
// also store on the grpc headers so it gets picked up by any clients that
// are using this.
nsheader := metadata.Pairs(GRPCHeader, namespace)
md, ok := metadata.FromOutgoingContext(ctx) // merge with outgoing context.
if !ok {
md = nsheader
} else {
// order ensures the latest is first in this list.
md = metadata.Join(nsheader, md)
}
return metadata.NewOutgoingContext(ctx, md)
}
func fromGRPCHeader(ctx context.Context) (string, bool) {
// try to extract for use in grpc servers.
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
// TODO(stevvooe): Check outgoing context?
return "", false
}
values := md[GRPCHeader]
if len(values) == 0 {
return "", false
}
return values[0], true
}

View File

@ -0,0 +1,21 @@
package namespaces
import "context"
// Store provides introspection about namespaces.
//
// Note that these are slightly different than other objects, which are record
// oriented. A namespace is really just a name and a set of labels. Objects
// that belong to a namespace are returned when the namespace is assigned to a
// given context.
//
//
type Store interface {
Create(ctx context.Context, namespace string, labels map[string]string) error
Labels(ctx context.Context, namespace string) (map[string]string, error)
SetLabel(ctx context.Context, namespace, key, value string) error
List(ctx context.Context) ([]string, error)
// Delete removes the namespace. The namespace must be empty to be deleted.
Delete(ctx context.Context, namespace string) error
}

View File

@ -7,6 +7,7 @@ type TaskInfo struct {
ContainerID string
Runtime string
Spec []byte
Namespace string
}
type Task interface {
@ -32,6 +33,8 @@ type Task interface {
CloseStdin(context.Context, uint32) error
// Checkpoint checkpoints a container to an image with live system data
Checkpoint(context.Context, CheckpointOpts) error
// DeleteProcess deletes a specific exec process via the pid
DeleteProcess(context.Context, uint32) (*Exit, error)
}
type CheckpointOpts struct {
@ -71,9 +74,13 @@ const (
PausedStatus
)
type State interface {
type State struct {
// Status is the current status of the container
Status() Status
Status Status
// Pid is the main process id for the container
Pid() uint32
Pid uint32
Stdin string
Stdout string
Stderr string
Terminal bool
}

View File

@ -0,0 +1,12 @@
package plugin
import (
"github.com/containerd/containerd/mount"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/net/context"
)
type Differ interface {
Apply(ctx context.Context, desc ocispec.Descriptor, mount []mount.Mount) (ocispec.Descriptor, error)
DiffMounts(ctx context.Context, lower, upper []mount.Mount, media, ref string) (ocispec.Descriptor, error)
}

View File

@ -19,6 +19,7 @@ const (
GRPCPlugin
SnapshotPlugin
TaskMonitorPlugin
DiffPlugin
)
type Registration struct {
@ -35,6 +36,7 @@ type InitContext struct {
Content content.Store
Meta *bolt.DB
Snapshotter snapshot.Snapshotter
Differ Differ
Config interface{}
Context context.Context
Monitor TaskMonitor

View File

@ -34,6 +34,8 @@ type Exit struct {
type Runtime interface {
// Create creates a container with the provided id and options
Create(ctx context.Context, id string, opts CreateOpts) (Task, error)
// Get returns a container
Get(context.Context, string) (Task, error)
// Containers returns all the current containers for the runtime
Tasks(context.Context) ([]Task, error)
// Delete removes the container in the runtime

View File

@ -67,6 +67,7 @@ func getV2URLPaths(desc ocispec.Descriptor) ([]string, error) {
switch desc.MediaType {
case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList,
images.MediaTypeDockerSchema1Manifest,
ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex:
urls = append(urls, path.Join("manifests", desc.Digest.String()))
}

View File

@ -1,16 +1,19 @@
package docker
import (
"bytes"
"context"
"io"
"io/ioutil"
"net/http"
"path"
"strings"
"time"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/remotes"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
@ -18,9 +21,23 @@ import (
type dockerPusher struct {
*dockerBase
tag string
// TODO: namespace tracker
tracker StatusTracker
}
func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor, r io.Reader) error {
func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) {
ref := remotes.MakeRefKey(ctx, desc)
status, err := p.tracker.GetStatus(ref)
if err == nil {
if status.Offset == status.Total {
return nil, content.ErrExists
}
// TODO: Handle incomplete status
} else if !content.IsNotFound(err) {
return nil, errors.Wrap(err, "failed to get status")
}
var (
isManifest bool
existCheck string
@ -37,34 +54,35 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor, r io.Re
req, err := http.NewRequest(http.MethodHead, p.url(existCheck), nil)
if err != nil {
return err
return nil, err
}
req.Header.Set("Accept", strings.Join([]string{desc.MediaType, `*`}, ", "))
resp, err := p.doRequestWithRetries(ctx, req, nil)
if err != nil {
if errors.Cause(err) != ErrInvalidAuthorization {
return err
return nil, err
}
log.G(ctx).WithError(err).Debugf("Unable to check existence, continuing with push")
} else {
if resp.StatusCode == http.StatusOK {
return nil
p.tracker.SetStatus(ref, Status{
Status: content.Status{
Ref: ref,
// TODO: Set updated time?
},
})
return nil, content.ErrExists
}
if resp.StatusCode != http.StatusNotFound {
// TODO: log error
return errors.Errorf("unexpected response: %s", resp.Status)
return nil, errors.Errorf("unexpected response: %s", resp.Status)
}
}
// TODO: Lookup related objects for cross repository push
if isManifest {
// Read all to use bytes.Reader for using GetBody
b, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrap(err, "failed to read manifest")
}
var putPath string
if p.tag != "" {
putPath = path.Join("manifests", p.tag)
@ -72,43 +90,27 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor, r io.Re
putPath = path.Join("manifests", desc.Digest.String())
}
req, err := http.NewRequest(http.MethodPut, p.url(putPath), nil)
req, err = http.NewRequest(http.MethodPut, p.url(putPath), nil)
if err != nil {
return err
}
req.ContentLength = int64(len(b))
req.Body = ioutil.NopCloser(bytes.NewReader(b))
req.GetBody = func() (io.ReadCloser, error) {
return ioutil.NopCloser(bytes.NewReader(b)), nil
return nil, err
}
req.Header.Add("Content-Type", desc.MediaType)
resp, err := p.doRequestWithRetries(ctx, req, nil)
if err != nil {
return err
}
if resp.StatusCode != http.StatusCreated {
// TODO: log error
return errors.Errorf("unexpected response: %s", resp.Status)
}
} else {
// TODO: Do monolithic upload if size is small
// TODO: Turn multi-request blob uploader into ingester
// Start upload request
req, err := http.NewRequest(http.MethodPost, p.url("blobs", "uploads")+"/", nil)
req, err = http.NewRequest(http.MethodPost, p.url("blobs", "uploads")+"/", nil)
if err != nil {
return err
return nil, err
}
resp, err := p.doRequestWithRetries(ctx, req, nil)
if err != nil {
return err
return nil, err
}
if resp.StatusCode != http.StatusAccepted {
// TODO: log error
return errors.Errorf("unexpected response: %s", resp.Status)
return nil, errors.Errorf("unexpected response: %s", resp.Status)
}
location := resp.Header.Get("Location")
@ -119,26 +121,143 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor, r io.Re
location = u.String()
}
// TODO: Support chunked upload
req, err = http.NewRequest(http.MethodPut, location, r)
req, err = http.NewRequest(http.MethodPut, location, nil)
if err != nil {
return err
return nil, err
}
q := req.URL.Query()
q.Add("digest", desc.Digest.String())
req.URL.RawQuery = q.Encode()
}
p.tracker.SetStatus(ref, Status{
Status: content.Status{
Ref: ref,
Total: desc.Size,
Expected: desc.Digest,
StartedAt: time.Now(),
},
})
// TODO: Support chunked upload
pr, pw := io.Pipe()
respC := make(chan *http.Response, 1)
req.Body = ioutil.NopCloser(pr)
req.ContentLength = desc.Size
go func() {
defer close(respC)
resp, err = p.doRequest(ctx, req)
if err != nil {
return err
pr.CloseWithError(err)
return
}
if resp.StatusCode != http.StatusCreated {
// TODO: log error
return errors.Errorf("unexpected response: %s", resp.Status)
pr.CloseWithError(errors.Errorf("unexpected response: %s", resp.Status))
}
respC <- resp
}()
return &pushWriter{
base: p.dockerBase,
ref: ref,
pipe: pw,
responseC: respC,
isManifest: isManifest,
expected: desc.Digest,
tracker: p.tracker,
}, nil
}
type pushWriter struct {
base *dockerBase
ref string
pipe *io.PipeWriter
responseC <-chan *http.Response
isManifest bool
expected digest.Digest
tracker StatusTracker
}
func (pw *pushWriter) Write(p []byte) (n int, err error) {
status, err := pw.tracker.GetStatus(pw.ref)
if err != nil {
return n, err
}
n, err = pw.pipe.Write(p)
status.Offset += int64(n)
status.UpdatedAt = time.Now()
pw.tracker.SetStatus(pw.ref, status)
return
}
func (pw *pushWriter) Close() error {
return pw.pipe.Close()
}
func (pw *pushWriter) Status() (content.Status, error) {
status, err := pw.tracker.GetStatus(pw.ref)
if err != nil {
return content.Status{}, err
}
return status.Status, nil
}
func (pw *pushWriter) Digest() digest.Digest {
// TODO: Get rid of this function?
return pw.expected
}
func (pw *pushWriter) Commit(size int64, expected digest.Digest) error {
// Check whether read has already thrown an error
if _, err := pw.pipe.Write([]byte{}); err != nil && err != io.ErrClosedPipe {
return errors.Wrap(err, "pipe error before commit")
}
if err := pw.pipe.Close(); err != nil {
return err
}
// TODO: Update status to determine committing
// TODO: timeout waiting for response
resp := <-pw.responseC
if resp == nil {
return errors.New("no response")
}
status, err := pw.tracker.GetStatus(pw.ref)
if err != nil {
return errors.Wrap(err, "failed to get status")
}
if size > 0 && size != status.Offset {
return errors.Errorf("unxpected size %d, expected %d", status.Offset, size)
}
if expected == "" {
expected = status.Expected
}
actual, err := digest.Parse(resp.Header.Get("Docker-Content-Digest"))
if err != nil {
return errors.Wrap(err, "invalid content digest in response")
}
if actual != expected {
return errors.Errorf("got digest %s, expected %s", actual, expected)
}
return nil
}
func (pw *pushWriter) Truncate(size int64) error {
// TODO: if blob close request and start new request at offset
// TODO: always error on manifest
return errors.New("cannot truncate remote upload")
}

View File

@ -38,6 +38,7 @@ type dockerResolver struct {
credentials func(string) (string, string, error)
plainHTTP bool
client *http.Client
tracker StatusTracker
}
// ResolverOptions are used to configured a new Docker register resolver
@ -52,14 +53,24 @@ type ResolverOptions struct {
// Client is the http client to used when making registry requests
Client *http.Client
// Tracker is used to track uploads to the registry. This is used
// since the registry does not have upload tracking and the existing
// mechanism for getting blob upload status is expensive.
Tracker StatusTracker
}
// NewResolver returns a new resolver to a Docker registry
func NewResolver(options ResolverOptions) remotes.Resolver {
tracker := options.Tracker
if tracker == nil {
tracker = NewInMemoryTracker()
}
return &dockerResolver{
credentials: options.Credentials,
plainHTTP: options.PlainHTTP,
client: options.Client,
tracker: tracker,
}
}
@ -212,6 +223,7 @@ func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher
return dockerPusher{
dockerBase: base,
tag: refspec.Object,
tracker: r.tracker,
}, nil
}

View File

@ -0,0 +1,449 @@
package schema1
import (
"bytes"
"compress/gzip"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"strings"
"sync"
"time"
"golang.org/x/sync/errgroup"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/remotes"
digest "github.com/opencontainers/go-digest"
specs "github.com/opencontainers/image-spec/specs-go"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
var (
mediaTypeManifest = "application/vnd.docker.distribution.manifest.v1+json"
)
type blobState struct {
diffID digest.Digest
empty bool
}
// Converter converts schema1 manifests to schema2 on fetch
type Converter struct {
contentStore content.Store
fetcher remotes.Fetcher
pulledManifest *manifest
mu sync.Mutex
blobMap map[digest.Digest]blobState
layerBlobs map[digest.Digest]ocispec.Descriptor
}
func NewConverter(contentStore content.Store, fetcher remotes.Fetcher) *Converter {
return &Converter{
contentStore: contentStore,
fetcher: fetcher,
blobMap: map[digest.Digest]blobState{},
layerBlobs: map[digest.Digest]ocispec.Descriptor{},
}
}
func (c *Converter) Handle(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
switch desc.MediaType {
case images.MediaTypeDockerSchema1Manifest:
if err := c.fetchManifest(ctx, desc); err != nil {
return nil, err
}
m := c.pulledManifest
if len(m.FSLayers) != len(m.History) {
return nil, errors.New("invalid schema 1 manifest, history and layer mismatch")
}
descs := make([]ocispec.Descriptor, 0, len(c.pulledManifest.FSLayers))
for i := range m.FSLayers {
if _, ok := c.blobMap[c.pulledManifest.FSLayers[i].BlobSum]; !ok {
empty, err := isEmptyLayer([]byte(m.History[i].V1Compatibility))
if err != nil {
return nil, err
}
// Do no attempt to download a known empty blob
if !empty {
descs = append([]ocispec.Descriptor{
{
MediaType: images.MediaTypeDockerSchema2LayerGzip,
Digest: c.pulledManifest.FSLayers[i].BlobSum,
},
}, descs...)
}
c.blobMap[c.pulledManifest.FSLayers[i].BlobSum] = blobState{
empty: empty,
}
}
}
return descs, nil
case images.MediaTypeDockerSchema2LayerGzip:
if c.pulledManifest == nil {
return nil, errors.New("manifest required for schema 1 blob pull")
}
return nil, c.fetchBlob(ctx, desc)
default:
return nil, fmt.Errorf("%v not support for schema 1 manifests", desc.MediaType)
}
}
func (c *Converter) Convert(ctx context.Context) (ocispec.Descriptor, error) {
history, diffIDs, err := c.schema1ManifestHistory()
if err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "schema 1 conversion failed")
}
var img ocispec.Image
if err := json.Unmarshal([]byte(c.pulledManifest.History[0].V1Compatibility), &img); err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to unmarshal image from schema 1 history")
}
img.History = history
img.RootFS = ocispec.RootFS{
Type: "layers",
DiffIDs: diffIDs,
}
b, err := json.Marshal(img)
if err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal image")
}
config := ocispec.Descriptor{
MediaType: ocispec.MediaTypeImageConfig,
Digest: digest.Canonical.FromBytes(b),
Size: int64(len(b)),
}
ref := remotes.MakeRefKey(ctx, config)
if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(b), config.Size, config.Digest); err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
}
layers := make([]ocispec.Descriptor, len(diffIDs))
for i, diffID := range diffIDs {
layers[i] = c.layerBlobs[diffID]
}
manifest := ocispec.Manifest{
Versioned: specs.Versioned{
SchemaVersion: 2,
},
Config: config,
Layers: layers,
}
b, err = json.Marshal(manifest)
if err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal image")
}
desc := ocispec.Descriptor{
MediaType: ocispec.MediaTypeImageManifest,
Digest: digest.Canonical.FromBytes(b),
Size: int64(len(b)),
}
ref = remotes.MakeRefKey(ctx, desc)
if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(b), desc.Size, desc.Digest); err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
}
return desc, nil
}
func (c *Converter) fetchManifest(ctx context.Context, desc ocispec.Descriptor) error {
log.G(ctx).Debug("fetch schema 1")
rc, err := c.fetcher.Fetch(ctx, desc)
if err != nil {
return err
}
b, err := ioutil.ReadAll(rc)
rc.Close()
if err != nil {
return err
}
b, err = stripSignature(b)
if err != nil {
return err
}
var m manifest
if err := json.Unmarshal(b, &m); err != nil {
return err
}
c.pulledManifest = &m
return nil
}
func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) error {
log.G(ctx).Debug("fetch blob")
ref := remotes.MakeRefKey(ctx, desc)
calc := newBlobStateCalculator()
cw, err := c.contentStore.Writer(ctx, ref, desc.Size, desc.Digest)
if err != nil {
if !content.IsExists(err) {
return err
}
// TODO: Check if blob -> diff id mapping already exists
// TODO: Check if blob empty label exists
r, err := c.contentStore.Reader(ctx, desc.Digest)
if err != nil {
return err
}
defer r.Close()
gr, err := gzip.NewReader(r)
defer gr.Close()
_, err = io.Copy(calc, gr)
if err != nil {
return err
}
} else {
defer cw.Close()
rc, err := c.fetcher.Fetch(ctx, desc)
if err != nil {
return err
}
defer rc.Close()
eg, _ := errgroup.WithContext(ctx)
pr, pw := io.Pipe()
eg.Go(func() error {
gr, err := gzip.NewReader(pr)
defer gr.Close()
_, err = io.Copy(calc, gr)
pr.CloseWithError(err)
return err
})
eg.Go(func() error {
defer pw.Close()
return content.Copy(cw, io.TeeReader(rc, pw), desc.Size, desc.Digest)
})
if err := eg.Wait(); err != nil {
return err
}
// TODO: Label blob
}
if desc.Size == 0 {
info, err := c.contentStore.Info(ctx, desc.Digest)
if err != nil {
return errors.Wrap(err, "failed to get blob info")
}
desc.Size = info.Size
}
state := calc.State()
c.mu.Lock()
c.blobMap[desc.Digest] = state
c.layerBlobs[state.diffID] = desc
c.mu.Unlock()
return nil
}
func (c *Converter) schema1ManifestHistory() ([]ocispec.History, []digest.Digest, error) {
if c.pulledManifest == nil {
return nil, nil, errors.New("missing schema 1 manifest for conversion")
}
m := *c.pulledManifest
if len(m.History) == 0 {
return nil, nil, errors.New("no history")
}
history := make([]ocispec.History, len(m.History))
diffIDs := []digest.Digest{}
for i := range m.History {
var h v1History
if err := json.Unmarshal([]byte(m.History[i].V1Compatibility), &h); err != nil {
return nil, nil, errors.Wrap(err, "failed to unmarshal history")
}
blobSum := m.FSLayers[i].BlobSum
state := c.blobMap[blobSum]
history[len(history)-i-1] = ocispec.History{
Author: h.Author,
Comment: h.Comment,
Created: &h.Created,
CreatedBy: strings.Join(h.ContainerConfig.Cmd, " "),
EmptyLayer: state.empty,
}
if !state.empty {
diffIDs = append([]digest.Digest{state.diffID}, diffIDs...)
}
}
return history, diffIDs, nil
}
type fsLayer struct {
BlobSum digest.Digest `json:"blobSum"`
}
type history struct {
V1Compatibility string `json:"v1Compatibility"`
}
type manifest struct {
FSLayers []fsLayer `json:"fsLayers"`
History []history `json:"history"`
}
type v1History struct {
Author string `json:"author,omitempty"`
Created time.Time `json:"created"`
Comment string `json:"comment,omitempty"`
ThrowAway *bool `json:"throwaway,omitempty"`
Size *int `json:"Size,omitempty"` // used before ThrowAway field
ContainerConfig struct {
Cmd []string `json:"Cmd,omitempty"`
} `json:"container_config,omitempty"`
}
// isEmptyLayer returns whether the v1 compability history describes an
// empty layer. A return value of true indicates the layer is empty,
// however false does not indicate non-empty.
func isEmptyLayer(compatHistory []byte) (bool, error) {
var h v1History
if err := json.Unmarshal(compatHistory, &h); err != nil {
return false, err
}
if h.ThrowAway != nil {
return *h.ThrowAway, nil
}
if h.Size != nil {
return *h.Size == 0, nil
}
// If no `Size` or `throwaway` field is given, then
// it cannot be determined whether the layer is empty
// from the history, return false
return false, nil
}
type signature struct {
Signatures []jsParsedSignature `json:"signatures"`
}
type jsParsedSignature struct {
Protected string `json:"protected"`
}
type protectedBlock struct {
Length int `json:"formatLength"`
Tail string `json:"formatTail"`
}
// joseBase64UrlDecode decodes the given string using the standard base64 url
// decoder but first adds the appropriate number of trailing '=' characters in
// accordance with the jose specification.
// http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-2
func joseBase64UrlDecode(s string) ([]byte, error) {
switch len(s) % 4 {
case 0:
case 2:
s += "=="
case 3:
s += "="
default:
return nil, errors.New("illegal base64url string")
}
return base64.URLEncoding.DecodeString(s)
}
func stripSignature(b []byte) ([]byte, error) {
var sig signature
if err := json.Unmarshal(b, &sig); err != nil {
return nil, err
}
if len(sig.Signatures) == 0 {
return nil, errors.New("no signatures")
}
pb, err := joseBase64UrlDecode(sig.Signatures[0].Protected)
if err != nil {
return nil, errors.Wrapf(err, "could not decode %s", sig.Signatures[0].Protected)
}
var protected protectedBlock
if err := json.Unmarshal(pb, &protected); err != nil {
return nil, err
}
if protected.Length > len(b) {
return nil, errors.New("invalid protected length block")
}
tail, err := joseBase64UrlDecode(protected.Tail)
if err != nil {
return nil, errors.Wrap(err, "invalid tail base 64 value")
}
return append(b[:protected.Length], tail...), nil
}
type blobStateCalculator struct {
empty bool
digester digest.Digester
}
func newBlobStateCalculator() *blobStateCalculator {
return &blobStateCalculator{
empty: true,
digester: digest.Canonical.Digester(),
}
}
func (c *blobStateCalculator) Write(p []byte) (int, error) {
if c.empty {
for _, b := range p {
if b != 0x00 {
c.empty = false
break
}
}
}
return c.digester.Hash().Write(p)
}
func (c *blobStateCalculator) State() blobState {
return blobState{
empty: c.empty,
diffID: c.digester.Digest(),
}
}

View File

@ -0,0 +1,46 @@
package docker
import (
"sync"
"github.com/containerd/containerd/content"
)
type Status struct {
content.Status
// UploadUUID is used by the Docker registry to reference blob uploads
UploadUUID string
}
type StatusTracker interface {
GetStatus(string) (Status, error)
SetStatus(string, Status)
}
type memoryStatusTracker struct {
statuses map[string]Status
m sync.Mutex
}
func NewInMemoryTracker() StatusTracker {
return &memoryStatusTracker{
statuses: map[string]Status{},
}
}
func (t *memoryStatusTracker) GetStatus(ref string) (Status, error) {
t.m.Lock()
defer t.m.Unlock()
status, ok := t.statuses[ref]
if !ok {
return Status{}, content.ErrNotFound
}
return status, nil
}
func (t *memoryStatusTracker) SetStatus(ref string, status Status) {
t.m.Lock()
t.statuses[ref] = status
t.m.Unlock()
}

View File

@ -3,6 +3,7 @@ package remotes
import (
"context"
"fmt"
"time"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/content"
@ -24,7 +25,7 @@ func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
return "manifest-" + desc.Digest.String()
case images.MediaTypeDockerSchema2Layer, images.MediaTypeDockerSchema2LayerGzip:
return "layer-" + desc.Digest.String()
case "application/vnd.docker.container.image.v1+json":
case images.MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig:
return "config-" + desc.Digest.String()
default:
log.G(ctx).Warnf("reference for unknown type: %s", desc.MediaType)
@ -46,6 +47,8 @@ func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc
switch desc.MediaType {
case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
return nil, fmt.Errorf("%v not yet supported", desc.MediaType)
case images.MediaTypeDockerSchema1Manifest:
return nil, fmt.Errorf("%v not supported", desc.MediaType)
default:
err := fetch(ctx, ingester, fetcher, desc)
return nil, err
@ -55,17 +58,39 @@ func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc
func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error {
log.G(ctx).Debug("fetch")
ref := MakeRefKey(ctx, desc)
cw, err := ingester.Writer(ctx, ref, desc.Size, desc.Digest)
var (
ref = MakeRefKey(ctx, desc)
cw content.Writer
err error
retry = 16
)
for {
cw, err = ingester.Writer(ctx, ref, desc.Size, desc.Digest)
if err != nil {
if !content.IsExists(err) {
if content.IsExists(err) {
return nil
} else if !content.IsLocked(err) {
return err
}
return nil
// TODO: On first time locked is encountered, get status
// of writer and abort if not updated recently.
select {
case <-time.After(time.Millisecond * time.Duration(retry)):
if retry < 2048 {
retry = retry << 1
}
continue
case <-ctx.Done():
// Propagate lock error
return err
}
}
defer cw.Close()
break
}
rc, err := fetcher.Fetch(ctx, desc)
if err != nil {
@ -76,6 +101,8 @@ func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc
return content.Copy(cw, rc, desc.Size, desc.Digest)
}
// PushHandler returns a handler that will push all content from the provider
// using a writer from the pusher.
func PushHandler(provider content.Provider, pusher Pusher) images.HandlerFunc {
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
ctx = log.WithLogger(ctx, log.G(ctx).WithFields(logrus.Fields{
@ -84,13 +111,29 @@ func PushHandler(provider content.Provider, pusher Pusher) images.HandlerFunc {
"size": desc.Size,
}))
log.G(ctx).Debug("push")
r, err := provider.Reader(ctx, desc.Digest)
if err != nil {
err := push(ctx, provider, pusher, desc)
return nil, err
}
defer r.Close()
return nil, pusher.Push(ctx, desc, r)
}
}
func push(ctx context.Context, provider content.Provider, pusher Pusher, desc ocispec.Descriptor) error {
log.G(ctx).Debug("push")
cw, err := pusher.Push(ctx, desc)
if err != nil {
if !content.IsExists(err) {
return err
}
return nil
}
defer cw.Close()
rc, err := provider.Reader(ctx, desc.Digest)
if err != nil {
return err
}
defer rc.Close()
return content.Copy(cw, rc, desc.Size, desc.Digest)
}

View File

@ -4,6 +4,7 @@ import (
"context"
"io"
"github.com/containerd/containerd/content"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
@ -37,9 +38,9 @@ type Fetcher interface {
}
type Pusher interface {
// Push pushes the resource identified by the descriptor using the
// passed in reader.
Push(ctx context.Context, d ocispec.Descriptor, r io.Reader) error
// Push returns a content writer for the given resource identified
// by the descriptor.
Push(ctx context.Context, d ocispec.Descriptor) (content.Writer, error)
}
// FetcherFunc allows package users to implement a Fetcher with just a

View File

@ -1,7 +1,6 @@
package rootfs
import (
"context"
"fmt"
"github.com/containerd/containerd/log"
@ -11,6 +10,7 @@ import (
"github.com/opencontainers/image-spec/identity"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/net/context"
)
type Applier interface {

View File

@ -1,13 +1,13 @@
package rootfs
import (
"context"
"fmt"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/snapshot"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/net/context"
)
type MountDiffer interface {

View File

@ -13,6 +13,8 @@ func rewriteGRPCError(err error) error {
return content.ErrExists
case codes.NotFound:
return content.ErrNotFound
case codes.Unavailable:
return content.ErrLocked
}
return err
@ -24,6 +26,8 @@ func serverErrorToGRPC(err error, id string) error {
return grpc.Errorf(codes.NotFound, "%v: not found", id)
case content.IsExists(err):
return grpc.Errorf(codes.AlreadyExists, "%v: exists", id)
case content.IsLocked(err):
return grpc.Errorf(codes.Unavailable, "%v: locked", id)
}
return err

View File

@ -1,7 +1,10 @@
package content
import (
"context"
contentapi "github.com/containerd/containerd/api/services/content"
digest "github.com/opencontainers/go-digest"
)
type remoteReader struct {
@ -34,18 +37,46 @@ func (rr *remoteReader) Read(p []byte) (n int, err error) {
n += copied
p = p[copied:]
if copied < len(p) {
continue
}
if len(p) == 0 {
rr.extra = append(rr.extra, resp.Data[copied:]...)
}
}
return
}
// TODO(stevvooe): Implemente io.ReaderAt.
func (rr *remoteReader) Close() error {
return rr.client.CloseSend()
}
type remoteReaderAt struct {
ctx context.Context
digest digest.Digest
client contentapi.ContentClient
}
func (ra *remoteReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
rr := &contentapi.ReadRequest{
Digest: ra.digest,
Offset: off,
Size_: int64(len(p)),
}
rc, err := ra.client.Read(ra.ctx, rr)
if err != nil {
return 0, err
}
for len(p) > 0 {
var resp *contentapi.ReadResponse
// fill our buffer up until we can fill p.
resp, err = rc.Recv()
if err != nil {
return n, err
}
copied := copy(p, resp.Data)
n += copied
p = p[copied:]
}
return n, nil
}

View File

@ -275,7 +275,7 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
// this action locks the writer for the session.
wr, err := s.store.Writer(ctx, ref, total, expected)
if err != nil {
return err
return serverErrorToGRPC(err, ref)
}
defer wr.Close()
@ -283,7 +283,7 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
msg.Action = req.Action
ws, err := wr.Status()
if err != nil {
return err
return serverErrorToGRPC(err, ref)
}
msg.Offset = ws.Offset // always set the offset.

View File

@ -85,6 +85,14 @@ func (rs *remoteStore) Reader(ctx context.Context, dgst digest.Digest) (io.ReadC
}, nil
}
func (rs *remoteStore) ReaderAt(ctx context.Context, dgst digest.Digest) (io.ReaderAt, error) {
return &remoteReaderAt{
ctx: ctx,
digest: dgst,
client: rs.client,
}, nil
}
func (rs *remoteStore) Status(ctx context.Context, re string) ([]content.Status, error) {
resp, err := rs.client.Status(ctx, &contentapi.StatusRequest{
Regexp: re,
@ -115,6 +123,7 @@ func (rs *remoteStore) Writer(ctx context.Context, ref string, size int64, expec
}
return &remoteWriter{
ref: ref,
client: wrclient,
offset: offset,
}, nil

View File

@ -16,14 +16,6 @@ type remoteWriter struct {
digest digest.Digest
}
func newRemoteWriter(client contentapi.Content_WriteClient, ref string, offset int64) (*remoteWriter, error) {
return &remoteWriter{
ref: ref,
client: client,
offset: offset,
}, nil
}
// send performs a synchronous req-resp cycle on the client.
func (rw *remoteWriter) send(req *contentapi.WriteRequest) (*contentapi.WriteResponse, error) {
if err := rw.client.Send(req); err != nil {

View File

@ -1,14 +1,13 @@
package diff
import (
"context"
diffapi "github.com/containerd/containerd/api/services/diff"
"github.com/containerd/containerd/api/types/descriptor"
mounttypes "github.com/containerd/containerd/api/types/mount"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/rootfs"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/net/context"
)
type DiffService interface {
@ -54,6 +53,14 @@ func (r *remote) DiffMounts(ctx context.Context, a, b []mount.Mount, media, ref
return toDescriptor(resp.Diff), nil
}
func toDescriptor(d *descriptor.Descriptor) ocispec.Descriptor {
return ocispec.Descriptor{
MediaType: d.MediaType,
Digest: d.Digest,
Size: d.Size_,
}
}
func fromDescriptor(d ocispec.Descriptor) *descriptor.Descriptor {
return &descriptor.Descriptor{
MediaType: d.MediaType,

View File

@ -1,22 +1,10 @@
package diff
import (
"io"
"io/ioutil"
"os"
diffapi "github.com/containerd/containerd/api/services/diff"
"github.com/containerd/containerd/api/types/descriptor"
mounttypes "github.com/containerd/containerd/api/types/mount"
"github.com/containerd/containerd/archive"
"github.com/containerd/containerd/archive/compression"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/snapshot"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
@ -25,21 +13,15 @@ func init() {
plugin.Register("diff-grpc", &plugin.Registration{
Type: plugin.GRPCPlugin,
Init: func(ic *plugin.InitContext) (interface{}, error) {
return newService(ic.Content, ic.Snapshotter)
return &service{
diff: ic.Differ,
}, nil
},
})
}
type service struct {
store content.Store
snapshotter snapshot.Snapshotter
}
func newService(store content.Store, snapshotter snapshot.Snapshotter) (*service, error) {
return &service{
store: store,
snapshotter: snapshotter,
}, nil
diff plugin.Differ
}
func (s *service) Register(gs *grpc.Server) error {
@ -53,143 +35,31 @@ func (s *service) Apply(ctx context.Context, er *diffapi.ApplyRequest) (*diffapi
mounts := toMounts(er.Mounts)
dir, err := ioutil.TempDir("", "extract-")
if err != nil {
return nil, errors.Wrap(err, "failed to create temporary directory")
}
defer os.RemoveAll(dir)
if err := mount.MountAll(mounts, dir); err != nil {
return nil, errors.Wrap(err, "failed to mount")
}
defer mount.Unmount(dir, 0)
r, err := s.store.Reader(ctx, desc.Digest)
if err != nil {
return nil, errors.Wrap(err, "failed to get reader from content store")
}
defer r.Close()
// TODO: only decompress stream if media type is compressed
ds, err := compression.DecompressStream(r)
ocidesc, err := s.diff.Apply(ctx, desc, mounts)
if err != nil {
return nil, err
}
defer ds.Close()
digester := digest.Canonical.Digester()
rc := &readCounter{
r: io.TeeReader(ds, digester.Hash()),
}
return &diffapi.ApplyResponse{
Applied: fromDescriptor(ocidesc),
}, nil
if _, err := archive.Apply(ctx, dir, rc); err != nil {
return nil, err
}
// Read any trailing data
if _, err := io.Copy(ioutil.Discard, rc); err != nil {
return nil, err
}
resp := &diffapi.ApplyResponse{
Applied: &descriptor.Descriptor{
MediaType: ocispec.MediaTypeImageLayer,
Digest: digester.Digest(),
Size_: rc.c,
},
}
return resp, nil
}
func (s *service) Diff(ctx context.Context, dr *diffapi.DiffRequest) (*diffapi.DiffResponse, error) {
aMounts := toMounts(dr.Left)
bMounts := toMounts(dr.Right)
aDir, err := ioutil.TempDir("", "left-")
ocidesc, err := s.diff.DiffMounts(ctx, aMounts, bMounts, dr.MediaType, dr.Ref)
if err != nil {
return nil, errors.Wrap(err, "failed to create temporary directory")
}
defer os.RemoveAll(aDir)
bDir, err := ioutil.TempDir("", "right-")
if err != nil {
return nil, errors.Wrap(err, "failed to create temporary directory")
}
defer os.RemoveAll(bDir)
if err := mount.MountAll(aMounts, aDir); err != nil {
return nil, errors.Wrap(err, "failed to mount")
}
defer mount.Unmount(aDir, 0)
if err := mount.MountAll(bMounts, bDir); err != nil {
return nil, errors.Wrap(err, "failed to mount")
}
defer mount.Unmount(bDir, 0)
cw, err := s.store.Writer(ctx, dr.Ref, 0, "")
if err != nil {
return nil, errors.Wrap(err, "failed to open writer")
}
// TODO: Validate media type
// TODO: Support compressed media types (link compressed to uncompressed)
//dgstr := digest.SHA256.Digester()
//wc := &writeCounter{}
//compressed, err := compression.CompressStream(cw, compression.Gzip)
//if err != nil {
// return nil, errors.Wrap(err, "failed to get compressed stream")
//}
//err = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash(), wc), lowerDir, upperDir)
//compressed.Close()
err = archive.WriteDiff(ctx, cw, aDir, bDir)
if err != nil {
return nil, errors.Wrap(err, "failed to write diff")
}
dgst := cw.Digest()
if err := cw.Commit(0, dgst); err != nil {
return nil, errors.Wrap(err, "failed to commit")
}
info, err := s.store.Info(ctx, dgst)
if err != nil {
return nil, errors.Wrap(err, "failed to get info from content store")
}
desc := ocispec.Descriptor{
MediaType: dr.MediaType,
Digest: info.Digest,
Size: info.Size,
return nil, err
}
return &diffapi.DiffResponse{
Diff: fromDescriptor(desc),
Diff: fromDescriptor(ocidesc),
}, nil
}
type readCounter struct {
r io.Reader
c int64
}
func (rc *readCounter) Read(p []byte) (n int, err error) {
n, err = rc.r.Read(p)
rc.c += int64(n)
return
}
func toDescriptor(d *descriptor.Descriptor) ocispec.Descriptor {
return ocispec.Descriptor{
MediaType: d.MediaType,
Digest: d.Digest,
Size: d.Size_,
}
}
func toMounts(apim []*mounttypes.Mount) []mount.Mount {
mounts := make([]mount.Mount, len(apim))
for i, m := range apim {

View File

@ -5,6 +5,7 @@ import (
"github.com/containerd/containerd/api/types/descriptor"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/metadata"
"github.com/containerd/containerd/namespaces"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"google.golang.org/grpc"
@ -82,6 +83,8 @@ func mapGRPCError(err error, id string) error {
return grpc.Errorf(codes.NotFound, "image %v not found", id)
case metadata.IsExists(err):
return grpc.Errorf(codes.AlreadyExists, "image %v already exists", id)
case namespaces.IsNamespaceRequired(err):
return grpc.Errorf(codes.InvalidArgument, "namespace required, please set %q header", namespaces.GRPCHeader)
}
return err

View File

@ -1,20 +0,0 @@
// +build linux
package sys
import "golang.org/x/sys/unix"
// EpollCreate1 directly calls unix.EpollCreate1
func EpollCreate1(flag int) (int, error) {
return unix.EpollCreate1(flag)
}
// EpollCtl directly calls unix.EpollCtl
func EpollCtl(epfd int, op int, fd int, event *unix.EpollEvent) error {
return unix.EpollCtl(epfd, op, fd, event)
}
// EpollWait directly calls unix.EpollWait
func EpollWait(epfd int, events []unix.EpollEvent, msec int) (int, error) {
return unix.EpollWait(epfd, events, msec)
}

View File

@ -1,18 +0,0 @@
// +build !windows,!darwin
package sys
import (
"io/ioutil"
"path/filepath"
"strconv"
)
// GetOpenFds returns the number of open fds for the process provided by pid
func GetOpenFds(pid int) (int, error) {
dirs, err := ioutil.ReadDir(filepath.Join("/proc", strconv.Itoa(pid), "fd"))
if err != nil {
return -1, err
}
return len(dirs), nil
}

View File

@ -1,236 +0,0 @@
// +build windows
package sys
import (
"os"
"path/filepath"
"regexp"
"strings"
"syscall"
"unsafe"
winio "github.com/Microsoft/go-winio"
)
// MkdirAllWithACL is a wrapper for MkdirAll that creates a directory
// ACL'd for Builtin Administrators and Local System.
func MkdirAllWithACL(path string, perm os.FileMode) error {
return mkdirall(path, true)
}
// MkdirAll implementation that is volume path aware for Windows.
func MkdirAll(path string, _ os.FileMode) error {
return mkdirall(path, false)
}
// mkdirall is a custom version of os.MkdirAll modified for use on Windows
// so that it is both volume path aware, and can create a directory with
// a DACL.
func mkdirall(path string, adminAndLocalSystem bool) error {
if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) {
return nil
}
// The rest of this method is largely copied from os.MkdirAll and should be kept
// as-is to ensure compatibility.
// Fast path: if we can tell whether path is a directory or file, stop with success or error.
dir, err := os.Stat(path)
if err == nil {
if dir.IsDir() {
return nil
}
return &os.PathError{
Op: "mkdir",
Path: path,
Err: syscall.ENOTDIR,
}
}
// Slow path: make sure parent exists and then call Mkdir for path.
i := len(path)
for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator.
i--
}
j := i
for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element.
j--
}
if j > 1 {
// Create parent
err = mkdirall(path[0:j-1], false)
if err != nil {
return err
}
}
// Parent now exists; invoke os.Mkdir or mkdirWithACL and use its result.
if adminAndLocalSystem {
err = mkdirWithACL(path)
} else {
err = os.Mkdir(path, 0)
}
if err != nil {
// Handle arguments like "foo/." by
// double-checking that directory doesn't exist.
dir, err1 := os.Lstat(path)
if err1 == nil && dir.IsDir() {
return nil
}
return err
}
return nil
}
// mkdirWithACL creates a new directory. If there is an error, it will be of
// type *PathError. .
//
// This is a modified and combined version of os.Mkdir and syscall.Mkdir
// in golang to cater for creating a directory am ACL permitting full
// access, with inheritance, to any subfolder/file for Built-in Administrators
// and Local System.
func mkdirWithACL(name string) error {
sa := syscall.SecurityAttributes{Length: 0}
sddl := "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)"
sd, err := winio.SddlToSecurityDescriptor(sddl)
if err != nil {
return &os.PathError{Op: "mkdir", Path: name, Err: err}
}
sa.Length = uint32(unsafe.Sizeof(sa))
sa.InheritHandle = 1
sa.SecurityDescriptor = uintptr(unsafe.Pointer(&sd[0]))
namep, err := syscall.UTF16PtrFromString(name)
if err != nil {
return &os.PathError{Op: "mkdir", Path: name, Err: err}
}
e := syscall.CreateDirectory(namep, &sa)
if e != nil {
return &os.PathError{Op: "mkdir", Path: name, Err: e}
}
return nil
}
// IsAbs is a platform-specific wrapper for filepath.IsAbs. On Windows,
// golang filepath.IsAbs does not consider a path \windows\system32 as absolute
// as it doesn't start with a drive-letter/colon combination. However, in
// docker we need to verify things such as WORKDIR /windows/system32 in
// a Dockerfile (which gets translated to \windows\system32 when being processed
// by the daemon. This SHOULD be treated as absolute from a docker processing
// perspective.
func IsAbs(path string) bool {
if !filepath.IsAbs(path) {
if !strings.HasPrefix(path, string(os.PathSeparator)) {
return false
}
}
return true
}
// The origin of the functions below here are the golang OS and syscall packages,
// slightly modified to only cope with files, not directories due to the
// specific use case.
//
// The alteration is to allow a file on Windows to be opened with
// FILE_FLAG_SEQUENTIAL_SCAN (particular for docker load), to avoid eating
// the standby list, particularly when accessing large files such as layer.tar.
// CreateSequential creates the named file with mode 0666 (before umask), truncating
// it if it already exists. If successful, methods on the returned
// File can be used for I/O; the associated file descriptor has mode
// O_RDWR.
// If there is an error, it will be of type *PathError.
func CreateSequential(name string) (*os.File, error) {
return OpenFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0)
}
// OpenSequential opens the named file for reading. If successful, methods on
// the returned file can be used for reading; the associated file
// descriptor has mode O_RDONLY.
// If there is an error, it will be of type *PathError.
func OpenSequential(name string) (*os.File, error) {
return OpenFileSequential(name, os.O_RDONLY, 0)
}
// OpenFileSequential is the generalized open call; most users will use Open
// or Create instead.
// If there is an error, it will be of type *PathError.
func OpenFileSequential(name string, flag int, _ os.FileMode) (*os.File, error) {
if name == "" {
return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOENT}
}
r, errf := syscallOpenFileSequential(name, flag, 0)
if errf == nil {
return r, nil
}
return nil, &os.PathError{Op: "open", Path: name, Err: errf}
}
func syscallOpenFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) {
r, e := syscallOpenSequential(name, flag|syscall.O_CLOEXEC, 0)
if e != nil {
return nil, e
}
return os.NewFile(uintptr(r), name), nil
}
func makeInheritSa() *syscall.SecurityAttributes {
var sa syscall.SecurityAttributes
sa.Length = uint32(unsafe.Sizeof(sa))
sa.InheritHandle = 1
return &sa
}
func syscallOpenSequential(path string, mode int, _ uint32) (fd syscall.Handle, err error) {
if len(path) == 0 {
return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
}
pathp, err := syscall.UTF16PtrFromString(path)
if err != nil {
return syscall.InvalidHandle, err
}
var access uint32
switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
case syscall.O_RDONLY:
access = syscall.GENERIC_READ
case syscall.O_WRONLY:
access = syscall.GENERIC_WRITE
case syscall.O_RDWR:
access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
}
if mode&syscall.O_CREAT != 0 {
access |= syscall.GENERIC_WRITE
}
if mode&syscall.O_APPEND != 0 {
access &^= syscall.GENERIC_WRITE
access |= syscall.FILE_APPEND_DATA
}
sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE)
var sa *syscall.SecurityAttributes
if mode&syscall.O_CLOEXEC == 0 {
sa = makeInheritSa()
}
var createmode uint32
switch {
case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL):
createmode = syscall.CREATE_NEW
case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC):
createmode = syscall.CREATE_ALWAYS
case mode&syscall.O_CREAT == syscall.O_CREAT:
createmode = syscall.OPEN_ALWAYS
case mode&syscall.O_TRUNC == syscall.O_TRUNC:
createmode = syscall.TRUNCATE_EXISTING
default:
createmode = syscall.OPEN_EXISTING
}
// Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang.
//https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN
h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0)
return h, e
}

View File

@ -1,31 +0,0 @@
// +build !windows
package sys
import (
"fmt"
"os"
"strconv"
"github.com/opencontainers/runc/libcontainer/system"
)
// OOMScoreMaxKillable is the maximum score keeping the process killable by the oom killer
const OOMScoreMaxKillable = -999
// SetOOMScore sets the oom score for the provided pid
func SetOOMScore(pid, score int) error {
path := fmt.Sprintf("/proc/%d/oom_score_adj", pid)
f, err := os.OpenFile(path, os.O_WRONLY, 0)
if err != nil {
return err
}
defer f.Close()
if _, err = f.WriteString(strconv.Itoa(score)); err != nil {
if os.IsPermission(err) && system.RunningInUserNS() {
return nil
}
return err
}
return nil
}

View File

@ -1,5 +0,0 @@
package sys
func SetOOMScore(pid, score int) error {
return nil
}

View File

@ -1,49 +0,0 @@
// +build linux
// Package osutils provide access to the Get Child and Set Child prctl
// flags.
// See http://man7.org/linux/man-pages/man2/prctl.2.html
package sys
import (
"unsafe"
"golang.org/x/sys/unix"
)
// PR_SET_CHILD_SUBREAPER allows setting the child subreaper.
// If arg2 is nonzero, set the "child subreaper" attribute of the
// calling process; if arg2 is zero, unset the attribute. When a
// process is marked as a child subreaper, all of the children
// that it creates, and their descendants, will be marked as
// having a subreaper. In effect, a subreaper fulfills the role
// of init(1) for its descendant processes. Upon termination of
// a process that is orphaned (i.e., its immediate parent has
// already terminated) and marked as having a subreaper, the
// nearest still living ancestor subreaper will receive a SIGCHLD
// signal and be able to wait(2) on the process to discover its
// termination status.
const prSetChildSubreaper = 36
// PR_GET_CHILD_SUBREAPER allows retrieving the current child
// subreaper.
// Returns the "child subreaper" setting of the caller, in the
// location pointed to by (int *) arg2.
const prGetChildSubreaper = 37
// GetSubreaper returns the subreaper setting for the calling process
func GetSubreaper() (int, error) {
var i uintptr
if _, _, err := unix.RawSyscall(unix.SYS_PRCTL, prGetChildSubreaper, uintptr(unsafe.Pointer(&i)), 0); err != 0 {
return -1, err
}
return int(i), nil
}
// SetSubreaper sets the value i as the subreaper setting for the calling process
func SetSubreaper(i int) error {
if _, _, err := unix.RawSyscall(unix.SYS_PRCTL, prSetChildSubreaper, uintptr(i), 0); err != 0 {
return err
}
return nil
}

View File

@ -1,19 +0,0 @@
// +build solaris
package sys
import (
"errors"
)
//Solaris TODO
// GetSubreaper returns the subreaper setting for the calling process
func GetSubreaper() (int, error) {
return 0, errors.New("osutils GetSubreaper not implemented on Solaris")
}
// SetSubreaper sets the value i as the subreaper setting for the calling process
func SetSubreaper(i int) error {
return errors.New("osutils SetSubreaper not implemented on Solaris")
}

View File

@ -1,64 +0,0 @@
// +build linux
package sys
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"github.com/opencontainers/runc/libcontainer/system"
)
const nanoSecondsPerSecond = 1e9
var clockTicksPerSecond = uint64(system.GetClockTicks())
// GetSystemCPUUsage returns the host system's cpu usage in
// nanoseconds. An error is returned if the format of the underlying
// file does not match.
//
// Uses /proc/stat defined by POSIX. Looks for the cpu
// statistics line and then sums up the first seven fields
// provided. See `man 5 proc` for details on specific field
// information.
func GetSystemCPUUsage() (uint64, error) {
var line string
f, err := os.Open("/proc/stat")
if err != nil {
return 0, err
}
bufReader := bufio.NewReaderSize(nil, 128)
defer func() {
bufReader.Reset(nil)
f.Close()
}()
bufReader.Reset(f)
err = nil
for err == nil {
line, err = bufReader.ReadString('\n')
if err != nil {
break
}
parts := strings.Fields(line)
switch parts[0] {
case "cpu":
if len(parts) < 8 {
return 0, fmt.Errorf("bad format of cpu stats")
}
var totalClockTicks uint64
for _, i := range parts[1:8] {
v, err := strconv.ParseUint(i, 10, 64)
if err != nil {
return 0, fmt.Errorf("error parsing cpu stats")
}
totalClockTicks += v
}
return (totalClockTicks * nanoSecondsPerSecond) /
clockTicksPerSecond, nil
}
}
return 0, fmt.Errorf("bad stats format")
}

View File

@ -1,51 +0,0 @@
// +build !windows
package sys
import "golang.org/x/sys/unix"
// Exit is the wait4 information from an exited process
type Exit struct {
Pid int
Status int
}
// Reap reaps all child processes for the calling process and returns their
// exit information
func Reap(wait bool) (exits []Exit, err error) {
var (
ws unix.WaitStatus
rus unix.Rusage
)
flag := unix.WNOHANG
if wait {
flag = 0
}
for {
pid, err := unix.Wait4(-1, &ws, flag, &rus)
if err != nil {
if err == unix.ECHILD {
return exits, nil
}
return exits, err
}
if pid <= 0 {
return exits, nil
}
exits = append(exits, Exit{
Pid: pid,
Status: exitStatus(ws),
})
}
}
const exitSignalOffset = 128
// exitStatus returns the correct exit status for a process based on if it
// was signaled or exited cleanly
func exitStatus(status unix.WaitStatus) int {
if status.Signaled() {
return exitSignalOffset + int(status.Signal())
}
return status.ExitStatus()
}

View File

@ -1,42 +0,0 @@
// +build !windows
package sys
import (
"net"
"os"
"path/filepath"
"golang.org/x/sys/unix"
)
// CreateUnixSocket creates a unix socket and returns the listener
func CreateUnixSocket(path string) (net.Listener, error) {
if err := os.MkdirAll(filepath.Dir(path), 0660); err != nil {
return nil, err
}
if err := unix.Unlink(path); err != nil && !os.IsNotExist(err) {
return nil, err
}
return net.Listen("unix", path)
}
// GetLocalListener returns a listerner out of a unix socket.
func GetLocalListener(path string, uid, gid int) (net.Listener, error) {
l, err := CreateUnixSocket(path)
if err != nil {
return l, err
}
if err := os.Chmod(path, 0660); err != nil {
l.Close()
return nil, err
}
if err := os.Chown(path, uid, gid); err != nil {
l.Close()
return nil, err
}
return l, nil
}

View File

@ -1,16 +0,0 @@
// +build windows
package sys
import (
"net"
"github.com/Microsoft/go-winio"
)
// GetLocalListener returns a Listernet out of a named pipe.
// `path` must be of the form of `\\.\pipe\<pipename>`
// (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150)
func GetLocalListener(path string, uid, gid int) (net.Listener, error) {
return winio.ListenPipe(path, nil)
}

View File

@ -1,8 +0,0 @@
Aaron Lehmann <aaron.lehmann@docker.com>
Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
Brandon Philips <brandon.philips@coreos.com>
Derek McGowan <derek@mcgstyle.net>
Justin Cormack <justin.cormack@docker.com>
Justin Cummins <sul3n3t@gmail.com>
Stephen J Day <stephen.day@docker.com>
Tonis Tiigi <tonistiigi@gmail.com>

View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,10 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
TEXT ·use(SB),NOSPLIT,$0
RET

View File

@ -1,18 +0,0 @@
package sysx
const (
// AtSymlinkNoFollow defined from AT_SYMLINK_NOFOLLOW in <sys/fcntl.h>
AtSymlinkNofollow = 0x20
)
const (
// SYS_FCHMODAT defined from golang.org/sys/unix
SYS_FCHMODAT = 467
)
// These functions will be generated by generate.sh
// $ GOOS=darwin GOARCH=386 ./generate.sh chmod
// $ GOOS=darwin GOARCH=amd64 ./generate.sh chmod
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)

View File

@ -1,25 +0,0 @@
// mksyscall.pl -l32 chmod_darwin.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package sysx
import (
"syscall"
"unsafe"
)
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
use(unsafe.Pointer(_p0))
if e1 != 0 {
err = errnoErr(e1)
}
return
}

View File

@ -1,25 +0,0 @@
// mksyscall.pl chmod_darwin.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package sysx
import (
"syscall"
"unsafe"
)
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
use(unsafe.Pointer(_p0))
if e1 != 0 {
err = errnoErr(e1)
}
return
}

Some files were not shown because too many files have changed in this diff Show More