update containerd library

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
docker-18.09
Akihiro Suda 2018-06-06 17:02:01 +09:00
parent 376093d234
commit 47a00b84fe
64 changed files with 2108 additions and 299 deletions

View File

@ -77,20 +77,20 @@ func (ce *CacheExporter) Finalize(ctx context.Context, cc *v1.CacheChains, targe
return err
}
dgst := digest.FromBytes(dt)
desc := ocispec.Descriptor{
Digest: dgst,
Size: int64(len(dt)),
MediaType: v1.CacheConfigMediaTypeV0,
}
configDone := oneOffProgress(ctx, fmt.Sprintf("writing config %s", dgst))
buf := contentutil.NewBuffer()
if err := content.WriteBlob(ctx, buf, dgst.String(), bytes.NewReader(dt), int64(len(dt)), dgst); err != nil {
if err := content.WriteBlob(ctx, buf, dgst.String(), bytes.NewReader(dt), desc); err != nil {
return configDone(errors.Wrap(err, "error writing config blob"))
}
configDone(nil)
mp.Add(dgst, buf)
mfst.Manifests = append(mfst.Manifests, ocispec.Descriptor{
MediaType: v1.CacheConfigMediaTypeV0,
Size: int64(len(dt)),
Digest: dgst,
})
mfst.Manifests = append(mfst.Manifests, desc)
dt, err = json.Marshal(mfst)
if err != nil {
@ -99,8 +99,12 @@ func (ce *CacheExporter) Finalize(ctx context.Context, cc *v1.CacheChains, targe
dgst = digest.FromBytes(dt)
buf = contentutil.NewBuffer()
desc = ocispec.Descriptor{
Digest: dgst,
Size: int64(len(dt)),
}
mfstDone := oneOffProgress(ctx, fmt.Sprintf("writing manifest %s", dgst))
if err := content.WriteBlob(ctx, buf, dgst.String(), bytes.NewReader(dt), int64(len(dt)), dgst); err != nil {
if err := content.WriteBlob(ctx, buf, dgst.String(), bytes.NewReader(dt), desc); err != nil {
return mfstDone(errors.Wrap(err, "error writing manifest blob"))
}
mfstDone(nil)

View File

@ -73,7 +73,7 @@ func (ci *CacheImporter) Resolve(ctx context.Context, ref string) (solver.CacheM
return nil, err
}
dt, err := content.ReadBlob(ctx, b, desc.Digest)
dt, err := content.ReadBlob(ctx, b, desc)
if err != nil {
return nil, err
}
@ -106,7 +106,7 @@ func (ci *CacheImporter) Resolve(ctx context.Context, ref string) (solver.CacheM
return nil, err
}
dt, err = content.ReadBlob(ctx, b, configDesc.Digest)
dt, err = content.ReadBlob(ctx, b, configDesc)
if err != nil {
return nil, err
}

View File

@ -497,7 +497,7 @@ func testBuildPushAndValidate(t *testing.T, sb integration.Sandbox) {
desc, err := img.Config(ctx)
require.NoError(t, err)
dt, err = content.ReadBlob(ctx, img.ContentStore(), desc.Digest)
dt, err = content.ReadBlob(ctx, img.ContentStore(), desc)
require.NoError(t, err)
var ociimg ocispec.Image
@ -528,7 +528,7 @@ func testBuildPushAndValidate(t *testing.T, sb integration.Sandbox) {
require.True(t, ociimg.History[1].EmptyLayer)
require.False(t, ociimg.History[2].EmptyLayer)
dt, err = content.ReadBlob(ctx, img.ContentStore(), img.Target().Digest)
dt, err = content.ReadBlob(ctx, img.ContentStore(), img.Target())
require.NoError(t, err)
var mfst schema2.Manifest
@ -538,7 +538,7 @@ func testBuildPushAndValidate(t *testing.T, sb integration.Sandbox) {
require.Equal(t, schema2.MediaTypeManifest, mfst.MediaType)
require.Equal(t, 2, len(mfst.Layers))
dt, err = content.ReadBlob(ctx, img.ContentStore(), mfst.Layers[0].Digest)
dt, err = content.ReadBlob(ctx, img.ContentStore(), ocispec.Descriptor{Digest: mfst.Layers[0].Digest})
require.NoError(t, err)
m, err := readTarToMap(dt, true)
@ -561,7 +561,7 @@ func testBuildPushAndValidate(t *testing.T, sb integration.Sandbox) {
_, ok = m["foo/sub/baz"]
require.False(t, ok)
dt, err = content.ReadBlob(ctx, img.ContentStore(), mfst.Layers[1].Digest)
dt, err = content.ReadBlob(ctx, img.ContentStore(), ocispec.Descriptor{Digest: mfst.Layers[1].Digest})
require.NoError(t, err)
m, err = readTarToMap(dt, true)

View File

@ -103,16 +103,24 @@ func (ic *ImageWriter) Commit(ctx context.Context, ref cache.ImmutableRef, confi
}
mfstDigest := digest.FromBytes(mfstJSON)
mfstDesc := ocispec.Descriptor{
Digest: mfstDigest,
Size: int64(len(mfstJSON)),
}
mfstDone := oneOffProgress(ctx, "exporting manifest "+mfstDigest.String())
if err := content.WriteBlob(ctx, ic.opt.ContentStore, mfstDigest.String(), bytes.NewReader(mfstJSON), int64(len(mfstJSON)), mfstDigest, content.WithLabels(labels)); err != nil {
if err := content.WriteBlob(ctx, ic.opt.ContentStore, mfstDigest.String(), bytes.NewReader(mfstJSON), mfstDesc, content.WithLabels(labels)); err != nil {
return nil, mfstDone(errors.Wrapf(err, "error writing manifest blob %s", mfstDigest))
}
mfstDone(nil)
configDesc := ocispec.Descriptor{
Digest: configDigest,
Size: int64(len(config)),
}
configDone := oneOffProgress(ctx, "exporting config "+configDigest.String())
if err := content.WriteBlob(ctx, ic.opt.ContentStore, configDigest.String(), bytes.NewReader(config), int64(len(config)), configDigest); err != nil {
if err := content.WriteBlob(ctx, ic.opt.ContentStore, configDigest.String(), bytes.NewReader(config), configDesc); err != nil {
return nil, configDone(errors.Wrap(err, "error writing config blob"))
}
configDone(nil)

View File

@ -199,7 +199,7 @@ ENTRYPOINT my entrypoint
desc, err := img.Config(ctx, ctr.ContentStore(), platforms.Default())
require.NoError(t, err)
dt, err := content.ReadBlob(ctx, ctr.ContentStore(), desc.Digest)
dt, err := content.ReadBlob(ctx, ctr.ContentStore(), desc)
require.NoError(t, err)
var ociimg ocispec.Image
@ -290,7 +290,7 @@ COPY foo .
desc, err := img.Config(ctx, ctr.ContentStore(), platforms.Default())
require.NoError(t, err)
dt, err := content.ReadBlob(ctx, ctr.ContentStore(), desc.Digest)
dt, err := content.ReadBlob(ctx, ctr.ContentStore(), desc)
require.NoError(t, err)
var ociimg ocispec.Image
@ -789,7 +789,7 @@ ENV foo=bar
desc, err := img.Config(ctx, client.ContentStore(), platforms.Default())
require.NoError(t, err)
dt, err := content.ReadBlob(ctx, client.ContentStore(), desc.Digest)
dt, err := content.ReadBlob(ctx, client.ContentStore(), desc)
require.NoError(t, err)
var ociimg ocispec.Image
@ -872,7 +872,7 @@ EXPOSE 5000
desc, err := img.Config(ctx, client.ContentStore(), platforms.Default())
require.NoError(t, err)
dt, err := content.ReadBlob(ctx, client.ContentStore(), desc.Digest)
dt, err := content.ReadBlob(ctx, client.ContentStore(), desc)
require.NoError(t, err)
var ociimg ocispec.Image
@ -1052,7 +1052,7 @@ RUN ["ls"]
desc, err := img.Config(ctx, client.ContentStore(), platforms.Default())
require.NoError(t, err)
dt, err := content.ReadBlob(ctx, client.ContentStore(), desc.Digest)
dt, err := content.ReadBlob(ctx, client.ContentStore(), desc)
require.NoError(t, err)
var ociimg ocispec.Image
@ -1157,7 +1157,7 @@ USER nobody
desc, err := img.Config(ctx, client.ContentStore(), platforms.Default())
require.NoError(t, err)
dt, err = content.ReadBlob(ctx, client.ContentStore(), desc.Digest)
dt, err = content.ReadBlob(ctx, client.ContentStore(), desc)
require.NoError(t, err)
var ociimg ocispec.Image
@ -1730,7 +1730,7 @@ LABEL foo=bar
desc, err := img.Config(ctx, client.ContentStore(), platforms.Default())
require.NoError(t, err)
dt, err := content.ReadBlob(ctx, client.ContentStore(), desc.Digest)
dt, err := content.ReadBlob(ctx, client.ContentStore(), desc)
require.NoError(t, err)
var ociimg ocispec.Image

View File

@ -3,7 +3,7 @@
set -eu -o pipefail -x
iidfile=$(mktemp -t docker-iidfile.XXXXXXXXXX)
docker build --build-arg VNDR_VERSION=15dc0965b7ba6dd78ae741e6fda33f23207033c4 --iidfile $iidfile -f ./hack/dockerfiles/vendor.Dockerfile --force-rm .
docker build --build-arg VNDR_VERSION=1fc68ee0c852556a9ed53cbde16247033f104111 --iidfile $iidfile -f ./hack/dockerfiles/vendor.Dockerfile --force-rm .
iid=$(cat $iidfile)
cid=$(docker create $iid noop)
rm -rf ./vendor

View File

@ -3,7 +3,7 @@
set -eu -o pipefail -x
iidfile=$(mktemp -t docker-iidfile.XXXXXXXXXX)
docker build --build-arg VNDR_VERSION=15dc0965b7ba6dd78ae741e6fda33f23207033c4 --iidfile $iidfile -f ./hack/dockerfiles/vendor.Dockerfile --force-rm .
docker build --build-arg VNDR_VERSION=1fc68ee0c852556a9ed53cbde16247033f104111 --iidfile $iidfile -f ./hack/dockerfiles/vendor.Dockerfile --force-rm .
iid=$(cat $iidfile)
diffs="$(docker run --rm $iid git status --porcelain -- vendor 2>/dev/null)"
if [ "$diffs" ]; then

View File

@ -8,6 +8,7 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/namespaces"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
type garbageCollectFn func(context.Context) error
@ -65,28 +66,34 @@ func (c *nsContent) Abort(ctx context.Context, ref string) error {
return c.Store.Abort(ctx, ref)
}
func (c *nsContent) ReaderAt(ctx context.Context, dgst digest.Digest) (content.ReaderAt, error) {
func (c *nsContent) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
ctx = namespaces.WithNamespace(ctx, c.ns)
return c.Store.ReaderAt(ctx, dgst)
return c.Store.ReaderAt(ctx, desc)
}
func (c *nsContent) Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (content.Writer, error) {
return c.writer(ctx, ref, size, expected, 3)
func (c *nsContent) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
return c.writer(ctx, 3, opts...)
}
func (c *nsContent) writer(ctx context.Context, ref string, size int64, expected digest.Digest, retries int) (content.Writer, error) {
func (c *nsContent) writer(ctx context.Context, retries int, opts ...content.WriterOpt) (content.Writer, error) {
var wOpts content.WriterOpts
for _, opt := range opts {
if err := opt(&wOpts); err != nil {
return nil, err
}
}
ctx = namespaces.WithNamespace(ctx, c.ns)
w, err := c.Store.Writer(ctx, ref, size, expected)
w, err := c.Store.Writer(ctx, opts...)
if err != nil {
if errdefs.IsAlreadyExists(err) && expected != "" && retries > 0 {
if errdefs.IsAlreadyExists(err) && wOpts.Desc.Digest != "" && retries > 0 {
_, err2 := c.Update(ctx, content.Info{
Digest: expected,
Digest: wOpts.Desc.Digest,
Labels: map[string]string{
"containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339Nano),
},
}, "labels.containerd.io/gc.root")
if err2 != nil {
return c.writer(ctx, ref, size, expected, retries-1)
return c.writer(ctx, retries-1, opts...)
}
}
}
@ -100,8 +107,8 @@ type noGCWriter struct {
content.Writer
}
func (cs *noGCContentStore) Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (content.Writer, error) {
w, err := cs.Store.Writer(ctx, ref, size, expected)
func (cs *noGCContentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
w, err := cs.Store.Writer(ctx, opts...)
return &noGCWriter{w}, err
}

View File

@ -10,6 +10,7 @@ import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
@ -33,27 +34,33 @@ type buffer struct {
refs map[string]struct{}
}
func (b *buffer) Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (content.Writer, error) {
func (b *buffer) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
var wOpts content.WriterOpts
for _, opt := range opts {
if err := opt(&wOpts); err != nil {
return nil, err
}
}
b.mu.Lock()
if _, ok := b.refs[ref]; ok {
return nil, errors.Wrapf(errdefs.ErrUnavailable, "ref %s locked", ref)
if _, ok := b.refs[wOpts.Ref]; ok {
return nil, errors.Wrapf(errdefs.ErrUnavailable, "ref %s locked", wOpts.Ref)
}
b.mu.Unlock()
return &bufferedWriter{
main: b,
digester: digest.Canonical.Digester(),
buffer: bytes.NewBuffer(nil),
expected: expected,
expected: wOpts.Desc.Digest,
releaseRef: func() {
b.mu.Lock()
delete(b.refs, ref)
delete(b.refs, wOpts.Ref)
b.mu.Unlock()
},
}, nil
}
func (b *buffer) ReaderAt(ctx context.Context, dgst digest.Digest) (content.ReaderAt, error) {
r, err := b.getBytesReader(ctx, dgst)
func (b *buffer) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
r, err := b.getBytesReader(ctx, desc.Digest)
if err != nil {
return nil, err
}

View File

@ -9,6 +9,7 @@ import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
@ -19,26 +20,26 @@ func TestReadWrite(t *testing.T) {
b := NewBuffer()
err := content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foo0")), -1, "")
err := content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foo0")), ocispec.Descriptor{Size: -1})
require.NoError(t, err)
err = content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foo1")), 4, "")
err = content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foo1")), ocispec.Descriptor{Size: 4})
require.NoError(t, err)
err = content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foo2")), 3, "")
err = content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foo2")), ocispec.Descriptor{Size: 3})
require.Error(t, err)
err = content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foo3")), -1, digest.FromBytes([]byte("foo4")))
err = content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foo3")), ocispec.Descriptor{Size: -1, Digest: digest.FromBytes([]byte("foo4"))})
require.Error(t, err)
err = content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foo4")), -1, digest.FromBytes([]byte("foo4")))
err = content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foo4")), ocispec.Descriptor{Size: -1, Digest: digest.FromBytes([]byte("foo4"))})
require.NoError(t, err)
dt, err := content.ReadBlob(ctx, b, digest.FromBytes([]byte("foo1")))
dt, err := content.ReadBlob(ctx, b, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foo1"))})
require.NoError(t, err)
require.Equal(t, string(dt), "foo1")
_, err = content.ReadBlob(ctx, b, digest.FromBytes([]byte("foo3")))
_, err = content.ReadBlob(ctx, b, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foo3"))})
require.Error(t, err)
require.Equal(t, errors.Cause(err), errdefs.ErrNotFound)
}
@ -49,10 +50,10 @@ func TestReaderAt(t *testing.T) {
b := NewBuffer()
err := content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foobar")), -1, "")
err := content.WriteBlob(ctx, b, "foo", bytes.NewBuffer([]byte("foobar")), ocispec.Descriptor{Size: -1})
require.NoError(t, err)
rdr, err := b.ReaderAt(ctx, digest.FromBytes([]byte("foobar")))
rdr, err := b.ReaderAt(ctx, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foobar"))})
require.NoError(t, err)
require.Equal(t, int64(6), rdr.Size())

View File

@ -21,7 +21,7 @@ type localFetcher struct {
}
func (f *localFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) {
r, err := f.Provider.ReaderAt(ctx, desc.Digest)
r, err := f.Provider.ReaderAt(ctx, desc)
if err != nil {
return nil, err
}

View File

@ -18,13 +18,13 @@ func TestCopy(t *testing.T) {
b0 := NewBuffer()
b1 := NewBuffer()
err := content.WriteBlob(ctx, b0, "foo", bytes.NewBuffer([]byte("foobar")), -1, "")
err := content.WriteBlob(ctx, b0, "foo", bytes.NewBuffer([]byte("foobar")), ocispec.Descriptor{Size: -1})
require.NoError(t, err)
err = Copy(ctx, b1, b0, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foobar")), Size: -1})
require.NoError(t, err)
dt, err := content.ReadBlob(ctx, b1, digest.FromBytes([]byte("foobar")))
dt, err := content.ReadBlob(ctx, b1, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foobar"))})
require.NoError(t, err)
require.Equal(t, string(dt), "foobar")
}

View File

@ -7,7 +7,6 @@ import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/remotes"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
@ -24,9 +23,9 @@ type fetchedProvider struct {
desc ocispec.Descriptor
}
func (p *fetchedProvider) ReaderAt(ctx context.Context, dgst digest.Digest) (content.ReaderAt, error) {
if dgst != p.desc.Digest {
return nil, errors.Wrapf(errdefs.ErrNotFound, "content %v", dgst)
func (p *fetchedProvider) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
if desc.Digest != p.desc.Digest {
return nil, errors.Wrapf(errdefs.ErrNotFound, "content %v", desc.Digest)
}
rc, err := p.f.Fetch(ctx, p.desc)

View File

@ -19,7 +19,7 @@ func TestFetcher(t *testing.T) {
b0 := NewBuffer()
err := content.WriteBlob(ctx, b0, "foo", bytes.NewBuffer([]byte("foobar")), -1, "")
err := content.WriteBlob(ctx, b0, "foo", bytes.NewBuffer([]byte("foobar")), ocispec.Descriptor{Size: -1})
require.NoError(t, err)
f := &localFetcher{b0}
@ -29,11 +29,11 @@ func TestFetcher(t *testing.T) {
err = Copy(ctx, b1, p, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foobar")), Size: -1})
require.NoError(t, err)
dt, err := content.ReadBlob(ctx, b1, digest.FromBytes([]byte("foobar")))
dt, err := content.ReadBlob(ctx, b1, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foobar"))})
require.NoError(t, err)
require.Equal(t, string(dt), "foobar")
rdr, err := p.ReaderAt(ctx, digest.FromBytes([]byte("foobar")))
rdr, err := p.ReaderAt(ctx, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foobar"))})
require.NoError(t, err)
buf := make([]byte, 3)
@ -55,7 +55,7 @@ func TestSlowFetch(t *testing.T) {
f := &dummySlowFetcher{}
p := FromFetcher(f, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foobar")), Size: -1})
rdr, err := p.ReaderAt(ctx, digest.FromBytes([]byte("foobar")))
rdr, err := p.ReaderAt(ctx, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foobar"))})
require.NoError(t, err)
buf := make([]byte, 3)

View File

@ -7,6 +7,7 @@ import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
@ -23,17 +24,17 @@ type MultiProvider struct {
sub map[digest.Digest]content.Provider
}
func (mp *MultiProvider) ReaderAt(ctx context.Context, dgst digest.Digest) (content.ReaderAt, error) {
func (mp *MultiProvider) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
mp.mu.RLock()
if p, ok := mp.sub[dgst]; ok {
if p, ok := mp.sub[desc.Digest]; ok {
mp.mu.RUnlock()
return p.ReaderAt(ctx, dgst)
return p.ReaderAt(ctx, desc)
}
mp.mu.RUnlock()
if mp.base == nil {
return nil, errors.Wrapf(errdefs.ErrNotFound, "content %v", dgst)
return nil, errors.Wrapf(errdefs.ErrNotFound, "content %v", desc.Digest)
}
return mp.base.ReaderAt(ctx, dgst)
return mp.base.ReaderAt(ctx, desc)
}
func (mp *MultiProvider) Add(dgst digest.Digest, p content.Provider) {

View File

@ -8,6 +8,7 @@ import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
@ -19,25 +20,25 @@ func TestMultiProvider(t *testing.T) {
b0 := NewBuffer()
b1 := NewBuffer()
err := content.WriteBlob(ctx, b0, "foo", bytes.NewBuffer([]byte("foo0")), -1, "")
err := content.WriteBlob(ctx, b0, "foo", bytes.NewBuffer([]byte("foo0")), ocispec.Descriptor{Size: -1})
require.NoError(t, err)
err = content.WriteBlob(ctx, b1, "foo", bytes.NewBuffer([]byte("foo1")), -1, "")
err = content.WriteBlob(ctx, b1, "foo", bytes.NewBuffer([]byte("foo1")), ocispec.Descriptor{Size: -1})
require.NoError(t, err)
mp := NewMultiProvider(nil)
mp.Add(digest.FromBytes([]byte("foo0")), b0)
mp.Add(digest.FromBytes([]byte("foo1")), b1)
dt, err := content.ReadBlob(ctx, mp, digest.FromBytes([]byte("foo0")))
dt, err := content.ReadBlob(ctx, mp, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foo0"))})
require.NoError(t, err)
require.Equal(t, string(dt), "foo0")
dt, err = content.ReadBlob(ctx, mp, digest.FromBytes([]byte("foo1")))
dt, err = content.ReadBlob(ctx, mp, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foo1"))})
require.NoError(t, err)
require.Equal(t, string(dt), "foo1")
_, err = content.ReadBlob(ctx, mp, digest.FromBytes([]byte("foo2")))
_, err = content.ReadBlob(ctx, mp, ocispec.Descriptor{Digest: digest.FromBytes([]byte("foo2"))})
require.Error(t, err)
require.Equal(t, errors.Cause(err), errdefs.ErrNotFound)
}

View File

@ -83,7 +83,7 @@ type tarRecord struct {
func dockerManifestRecord(ctx context.Context, provider content.Provider, desc ocispec.Descriptor, name string) (*tarRecord, error) {
switch desc.MediaType {
case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
p, err := content.ReadBlob(ctx, provider, desc)
if err != nil {
return nil, err
}
@ -141,7 +141,7 @@ func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord {
Typeflag: tar.TypeReg,
},
CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
r, err := cs.ReaderAt(ctx, desc.Digest)
r, err := cs.ReaderAt(ctx, desc)
if err != nil {
return 0, err
}

View File

@ -28,28 +28,25 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester
return "", nil, errors.WithStack(err)
}
dgst := ref.Digest()
var desc *ocispec.Descriptor
if dgst != "" {
ra, err := ingester.ReaderAt(ctx, dgst)
desc := ocispec.Descriptor{
Digest: ref.Digest(),
}
if desc.Digest != "" {
ra, err := ingester.ReaderAt(ctx, desc)
if err == nil {
desc.Size = ra.Size()
mt, err := DetectManifestMediaType(ra)
if err == nil {
desc = &ocispec.Descriptor{
Size: ra.Size(),
Digest: dgst,
MediaType: mt,
}
desc.MediaType = mt
}
}
}
if desc == nil {
_, desc2, err := resolver.Resolve(ctx, ref.String())
// use resolver if desc is incomplete
if desc.MediaType == "" {
_, desc, err = resolver.Resolve(ctx, ref.String())
if err != nil {
return "", nil, err
}
desc = &desc2
}
fetcher, err := resolver.Fetcher(ctx, ref.String())
@ -61,15 +58,15 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester
remotes.FetchHandler(ingester, fetcher),
childrenConfigHandler(ingester, platform),
}
if err := images.Dispatch(ctx, images.Handlers(handlers...), *desc); err != nil {
if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
return "", nil, err
}
config, err := images.Config(ctx, ingester, *desc, platform)
config, err := images.Config(ctx, ingester, desc, platform)
if err != nil {
return "", nil, err
}
dt, err := content.ReadBlob(ctx, ingester, config.Digest)
dt, err := content.ReadBlob(ctx, ingester, config)
if err != nil {
return "", nil, err
}
@ -82,7 +79,7 @@ func childrenConfigHandler(provider content.Provider, platform string) images.Ha
var descs []ocispec.Descriptor
switch desc.MediaType {
case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
p, err := content.ReadBlob(ctx, provider, desc)
if err != nil {
return nil, err
}
@ -96,7 +93,7 @@ func childrenConfigHandler(provider content.Provider, platform string) images.Ha
descs = append(descs, manifest.Config)
case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
p, err := content.ReadBlob(ctx, provider, desc)
if err != nil {
return nil, err
}

View File

@ -47,20 +47,20 @@ func (p *Puller) Resolve(ctx context.Context) (string, ocispec.Descriptor, error
p.resolveOnce.Do(func() {
resolveProgressDone := oneOffProgress(ctx, "resolve "+p.Src.String())
dgst := p.Src.Digest()
if dgst != "" {
info, err := p.ContentStore.Info(ctx, dgst)
desc := ocispec.Descriptor{
Digest: p.Src.Digest(),
}
if desc.Digest != "" {
info, err := p.ContentStore.Info(ctx, desc.Digest)
if err == nil {
desc.Size = info.Size
p.ref = p.Src.String()
ra, err := p.ContentStore.ReaderAt(ctx, dgst)
ra, err := p.ContentStore.ReaderAt(ctx, desc)
if err == nil {
mt, err := imageutil.DetectManifestMediaType(ra)
if err == nil {
p.desc = ocispec.Descriptor{
Size: info.Size,
Digest: dgst,
MediaType: mt,
}
desc.MediaType = mt
p.desc = desc
resolveProgressDone(nil)
return
}

View File

@ -41,7 +41,9 @@ func getCredentialsFunc(ctx context.Context, sm *session.Manager) func(string) (
}
func Push(ctx context.Context, sm *session.Manager, cs content.Provider, dgst digest.Digest, ref string, insecure bool) error {
desc := ocispec.Descriptor{
Digest: dgst,
}
parsed, err := reference.ParseNormalizedNamed(ref)
if err != nil {
return err
@ -83,7 +85,7 @@ func Push(ctx context.Context, sm *session.Manager, cs content.Provider, dgst di
pushHandler,
)
ra, err := cs.ReaderAt(ctx, dgst)
ra, err := cs.ReaderAt(ctx, desc)
if err != nil {
return err
}
@ -138,7 +140,7 @@ func childrenHandler(provider content.Provider) images.HandlerFunc {
var descs []ocispec.Descriptor
switch desc.MediaType {
case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
p, err := content.ReadBlob(ctx, provider, desc)
if err != nil {
return nil, err
}
@ -153,7 +155,7 @@ func childrenHandler(provider content.Provider) images.HandlerFunc {
descs = append(descs, manifest.Config)
descs = append(descs, manifest.Layers...)
case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
p, err := content.ReadBlob(ctx, provider, desc)
if err != nil {
return nil, err
}

View File

@ -6,7 +6,7 @@ github.com/davecgh/go-spew v1.1.0
github.com/pmezard/go-difflib v1.0.0
golang.org/x/sys 314a259e304ff91bd6985da2a7149bbf91237993
github.com/containerd/containerd e1428ef05460da40720d622c803262e6fc8d3477
github.com/containerd/containerd 63522d9eaa5a0443d225642c4b6f4f5fdedf932b
github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
github.com/sirupsen/logrus v1.0.0
@ -23,7 +23,7 @@ github.com/Microsoft/go-winio v0.4.7
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/opencontainers/runtime-spec v1.0.1
github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd5
github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925
github.com/containerd/console 9290d21dc56074581f619579c43d970b4514bc08
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9

View File

@ -0,0 +1,107 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <dlfcn.h>
int copies;
int non_copies;
void *realloc(void *ptr, size_t size) {
static void *(*real_realloc)(void*, size_t) = NULL;
if (real_realloc == NULL) {
real_realloc = (void* (*) (void*, size_t)) dlsym(RTLD_NEXT, "realloc");
}
void *ret_ptr = (*real_realloc)(ptr, size);
if (ret_ptr == ptr) {
non_copies++;
} else {
copies++;
}
return ret_ptr;
}
struct TMemoryBuffer {
void* ptr;
int size;
};
int main(int argc, char *argv[]) {
int num_buffers;
int init_size;
int max_size;
int doublings;
int iterations;
if (argc < 6 ||
argc > 7 ||
(num_buffers = atoi(argv[1])) == 0 ||
(init_size = atoi(argv[2])) == 0 ||
(max_size = atoi(argv[3])) == 0 ||
init_size > max_size ||
(iterations = atoi(argv[4])) == 0 ||
(doublings = atoi(argv[5])) == 0 ||
(argc == 7 && atoi(argv[6]) == 0)) {
fprintf(stderr, "usage: realloc_test <num_buffers> <init_size> <max_size> <doublings> <iterations> [seed]\n");
exit(EXIT_FAILURE);
}
for ( int i = 0 ; i < argc ; i++ ) {
printf("%s ", argv[i]);
}
printf("\n");
if (argc == 7) {
srand(atoi(argv[6]));
} else {
srand(time(NULL));
}
struct TMemoryBuffer* buffers = calloc(num_buffers, sizeof(*buffers));
if (buffers == NULL) abort();
for ( int i = 0 ; i < num_buffers ; i++ ) {
buffers[i].size = max_size;
}
while (iterations --> 0) {
for ( int i = 0 ; i < doublings * num_buffers ; i++ ) {
struct TMemoryBuffer* buf = &buffers[rand() % num_buffers];
buf->size *= 2;
if (buf->size <= max_size) {
buf->ptr = realloc(buf->ptr, buf->size);
} else {
free(buf->ptr);
buf->size = init_size;
buf->ptr = malloc(buf->size);
}
if (buf->ptr == NULL) abort();
}
}
printf("Non-copied %d/%d (%.2f%%)\n", non_copies, copies + non_copies, 100.0 * non_copies / (copies + non_copies));
return 0;
}

42
vendor/github.com/apache/thrift/tutorial/README.md generated vendored Normal file
View File

@ -0,0 +1,42 @@
Thrift Tutorial
License
=======
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
Tutorial
========
1) First things first, you'll need to install the Thrift compiler and the
language libraries. Do that using the instructions in the top level
README.md file.
2) Read tutorial.thrift to learn about the syntax of a Thrift file
3) Compile the code for the language of your choice:
$ thrift
$ thrift -r --gen cpp tutorial.thrift
4) Take a look at the generated code.
5) Look in the language directories for sample client/server code.
6) That's about it for now. This tutorial is intentionally brief. It should be
just enough to get you started and ready to build your own project.

View File

@ -0,0 +1,190 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <stdio.h>
#include <glib-object.h>
#include <thrift/c_glib/protocol/thrift_binary_protocol.h>
#include <thrift/c_glib/transport/thrift_buffered_transport.h>
#include <thrift/c_glib/transport/thrift_socket.h>
#include "gen-c_glib/calculator.h"
int main (void)
{
ThriftSocket *socket;
ThriftTransport *transport;
ThriftProtocol *protocol;
CalculatorIf *client;
GError *error = NULL;
InvalidOperation *invalid_operation = NULL;
Work *work;
gint32 sum;
gint32 diff;
int exit_status = 0;
#if (!GLIB_CHECK_VERSION (2, 36, 0))
g_type_init ();
#endif
socket = g_object_new (THRIFT_TYPE_SOCKET,
"hostname", "localhost",
"port", 9090,
NULL);
transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
"transport", socket,
NULL);
protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
"transport", transport,
NULL);
thrift_transport_open (transport, &error);
/* In the C (GLib) implementation of Thrift, service methods on the
server are accessed via a generated client class that implements
the service interface. In this tutorial, we access a Calculator
service through an instance of CalculatorClient, which implements
CalculatorIf. */
client = g_object_new (TYPE_CALCULATOR_CLIENT,
"input_protocol", protocol,
"output_protocol", protocol,
NULL);
/* Each of the client methods requires at least two parameters: A
pointer to the client-interface implementation (the client
object), and a handle to a GError structure to receive
information about any error that occurs.
On success, client methods return TRUE. A return value of FALSE
indicates an error occurred and the error parameter has been
set. */
if (!error && calculator_if_ping (client, &error)) {
puts ("ping()");
}
/* Service methods that return a value do so by passing the result
back via an output parameter (here, "sum"). */
if (!error && calculator_if_add (client, &sum, 1, 1, &error)) {
printf ("1+1=%d\n", sum);
}
/* Thrift structs are implemented as GObjects, with each of the
struct's members exposed as an object property. */
work = g_object_new (TYPE_WORK, NULL);
if (!error) {
g_object_set (work,
"num1", 1,
"num2", 0,
"op", OPERATION_DIVIDE,
NULL);
/* Exceptions are passed back from service methods in a manner
similar to return values. */
if (calculator_if_calculate (client,
NULL,
1,
work,
&invalid_operation,
&error)) {
puts ("Whoa? We can divide by zero!");
}
else {
if (invalid_operation) {
gchar *why;
/* Like structs, exceptions are implemented as objects with
properties. */
g_object_get (invalid_operation, "why", &why, NULL);
printf ("InvalidOperation: %s\n", why);
if (why != NULL)
g_free (why);
g_object_unref (invalid_operation);
invalid_operation = NULL;
}
g_clear_error (&error);
}
}
if (!error) {
/* Struct objects can be reused across method invocations. */
g_object_set (work,
"num1", 15,
"num2", 10,
"op", OPERATION_SUBTRACT,
NULL);
if (calculator_if_calculate (client,
&diff,
1,
work,
&invalid_operation,
&error)) {
printf ("15-10=%d\n", diff);
}
}
g_object_unref (work);
if (!error) {
SharedStruct *shared_struct;
gchar *value;
shared_struct = g_object_new (TYPE_SHARED_STRUCT, NULL);
/* As defined in the Thrift file, the Calculator service extends
the SharedService service. Correspondingly, in the generated
code CalculatorIf inherits from SharedServiceIf, and the parent
service's methods are accessible through a simple cast. */
if (shared_service_client_get_struct (SHARED_SERVICE_IF (client),
&shared_struct,
1,
&error)) {
g_object_get (shared_struct, "value", &value, NULL);
printf ("Check log: %s\n", value);
g_free (value);
}
g_object_unref (shared_struct);
}
if (error) {
printf ("ERROR: %s\n", error->message);
g_clear_error (&error);
exit_status = 1;
}
thrift_transport_close (transport, NULL);
g_object_unref (client);
g_object_unref (protocol);
g_object_unref (transport);
g_object_unref (socket);
return exit_status;
}

View File

@ -0,0 +1,527 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <glib-object.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <thrift/c_glib/thrift.h>
#include <thrift/c_glib/protocol/thrift_binary_protocol_factory.h>
#include <thrift/c_glib/protocol/thrift_protocol_factory.h>
#include <thrift/c_glib/server/thrift_server.h>
#include <thrift/c_glib/server/thrift_simple_server.h>
#include <thrift/c_glib/transport/thrift_buffered_transport_factory.h>
#include <thrift/c_glib/transport/thrift_server_socket.h>
#include <thrift/c_glib/transport/thrift_server_transport.h>
#include "gen-c_glib/calculator.h"
G_BEGIN_DECLS
/* In the C (GLib) implementation of Thrift, the actual work done by a
server---that is, the code that runs when a client invokes a
service method---is defined in a separate "handler" class that
implements the service interface. Here we define the
TutorialCalculatorHandler class, which implements the CalculatorIf
interface and provides the behavior expected by tutorial clients.
(Typically this code would be placed in its own module but for
clarity this tutorial is presented entirely in a single file.)
For each service the Thrift compiler generates an abstract base
class from which handler implementations should inherit. In our
case TutorialCalculatorHandler inherits from CalculatorHandler,
defined in gen-c_glib/calculator.h.
If you're new to GObject, try not to be intimidated by the quantity
of code here---much of it is boilerplate and can mostly be
copied-and-pasted from existing work. For more information refer to
the GObject Reference Manual, available online at
https://developer.gnome.org/gobject/. */
#define TYPE_TUTORIAL_CALCULATOR_HANDLER \
(tutorial_calculator_handler_get_type ())
#define TUTORIAL_CALCULATOR_HANDLER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
TYPE_TUTORIAL_CALCULATOR_HANDLER, \
TutorialCalculatorHandler))
#define TUTORIAL_CALCULATOR_HANDLER_CLASS(c) \
(G_TYPE_CHECK_CLASS_CAST ((c), \
TYPE_TUTORIAL_CALCULATOR_HANDLER, \
TutorialCalculatorHandlerClass))
#define IS_TUTORIAL_CALCULATOR_HANDLER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
TYPE_TUTORIAL_CALCULATOR_HANDLER))
#define IS_TUTORIAL_CALCULATOR_HANDLER_CLASS(c) \
(G_TYPE_CHECK_CLASS_TYPE ((c), \
TYPE_TUTORIAL_CALCULATOR_HANDLER))
#define TUTORIAL_CALCULATOR_HANDLER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
TYPE_TUTORIAL_CALCULATOR_HANDLER, \
TutorialCalculatorHandlerClass))
struct _TutorialCalculatorHandler {
CalculatorHandler parent_instance;
/* private */
GHashTable *log;
};
typedef struct _TutorialCalculatorHandler TutorialCalculatorHandler;
struct _TutorialCalculatorHandlerClass {
CalculatorHandlerClass parent_class;
};
typedef struct _TutorialCalculatorHandlerClass TutorialCalculatorHandlerClass;
GType tutorial_calculator_handler_get_type (void);
G_END_DECLS
/* ---------------------------------------------------------------- */
/* The implementation of TutorialCalculatorHandler follows. */
G_DEFINE_TYPE (TutorialCalculatorHandler,
tutorial_calculator_handler,
TYPE_CALCULATOR_HANDLER)
/* Each of a handler's methods accepts at least two parameters: A
pointer to the service-interface implementation (the handler object
itself) and a handle to a GError structure to receive information
about any error that occurs.
On success, a handler method returns TRUE. A return value of FALSE
indicates an error occurred and the error parameter has been
set. (Methods should not return FALSE without first setting the
error parameter.) */
static gboolean
tutorial_calculator_handler_ping (CalculatorIf *iface,
GError **error)
{
THRIFT_UNUSED_VAR (iface);
THRIFT_UNUSED_VAR (error);
puts ("ping()");
return TRUE;
}
/* Service-method parameters are passed through as parameters to the
handler method.
If the service method returns a value an output parameter, _return,
is additionally passed to the handler method. This parameter should
be set appropriately before the method returns, whenever it
succeeds.
The return value from this method happens to be of a base type,
i32, but note if a method returns a complex type such as a map or
list *_return will point to a pre-allocated data structure that
does not need to be re-allocated and should not be destroyed. */
static gboolean
tutorial_calculator_handler_add (CalculatorIf *iface,
gint32 *_return,
const gint32 num1,
const gint32 num2,
GError **error)
{
THRIFT_UNUSED_VAR (iface);
THRIFT_UNUSED_VAR (error);
printf ("add(%d,%d)\n", num1, num2);
*_return = num1 + num2;
return TRUE;
}
/* Any handler method can return a ThriftApplicationException to the
client by setting its error parameter appropriately and returning
FALSE. See the ThriftApplicationExceptionError enumeration defined
in thrift_application_exception.h for a list of recognized
exception types (GError codes).
If a service method can also throw a custom exception (that is, one
defined in the .thrift file) an additional output parameter will be
provided (here, "ouch") to hold an instance of the exception, when
necessary. Note there will be a separate parameter added for each
type of exception the method can throw.
Unlike return values, exception objects are never pre-created; this
is always the responsibility of the handler method. */
static gboolean
tutorial_calculator_handler_calculate (CalculatorIf *iface,
gint32 *_return,
const gint32 logid,
const Work *w,
InvalidOperation **ouch,
GError **error)
{
TutorialCalculatorHandler *self;
gint *log_key;
gchar log_value[12];
SharedStruct *log_struct;
gint num1;
gint num2;
Operation op;
gboolean result = TRUE;
THRIFT_UNUSED_VAR (error);
g_return_val_if_fail (IS_TUTORIAL_CALCULATOR_HANDLER (iface),
FALSE);
self = TUTORIAL_CALCULATOR_HANDLER (iface);
/* Remember: Exception objects are never pre-created */
g_assert (*ouch == NULL);
/* Fetch the contents of our Work parameter.
Note that integer properties of thirty-two bits or fewer in width
are _always_ of type gint, regardless of the range of values they
hold. A common error is trying to retrieve, say, a structure
member defined in the .thrift file as type i16 into a variable of
type gint16, which will clobber variables adjacent on the
stack. Remember: If you're retrieving an integer property the
receiving variable must be of either type gint or gint64, as
appropriate. */
g_object_get ((Work *)w,
"num1", &num1,
"num2", &num2,
"op", &op,
NULL);
printf ("calculate(%d,{%d,%d,%d})\n", logid, op, num1, num2);
switch (op) {
case OPERATION_ADD:
*_return = num1 + num2;
break;
case OPERATION_SUBTRACT:
*_return = num1 - num2;
break;
case OPERATION_MULTIPLY:
*_return = num1 * num2;
break;
case OPERATION_DIVIDE:
if (num2 == 0) {
/* For each custom exception type a subclass of ThriftStruct is
generated by the Thrift compiler. Throw an exception by
setting the corresponding output parameter to a new instance
of its type and returning FALSE. */
*ouch = g_object_new (TYPE_INVALID_OPERATION,
"whatOp", op,
"why", g_strdup ("Cannot divide by 0"),
NULL);
result = FALSE;
/* Note the call to g_strdup above: All the memory used by a
ThriftStruct's properties belongs to the object itself and
will be freed on destruction. Removing this call to g_strdup
will lead to a segmentation fault as the object tries to
release memory allocated statically to the program. */
}
else {
*_return = num1 / num2;
}
break;
default:
*ouch = g_object_new (TYPE_INVALID_OPERATION,
"whatOp", op,
"why", g_strdup ("Invalid Operation"),
NULL);
result = FALSE;
}
/* On success, log a record of the result to our hash table */
if (result) {
log_key = g_malloc (sizeof *log_key);
*log_key = logid;
snprintf (log_value, sizeof log_value, "%d", *_return);
log_struct = g_object_new (TYPE_SHARED_STRUCT,
"key", *log_key,
"value", g_strdup (log_value),
NULL);
g_hash_table_replace (self->log, log_key, log_struct);
}
return result;
}
/* A one-way method has the same signature as an equivalent, regular
method that returns no value. */
static gboolean
tutorial_calculator_handler_zip (CalculatorIf *iface,
GError **error)
{
THRIFT_UNUSED_VAR (iface);
THRIFT_UNUSED_VAR (error);
puts ("zip()");
return TRUE;
}
/* As specified in the .thrift file (tutorial.thrift), the Calculator
service extends the SharedService service. Correspondingly, in the
generated code the Calculator interface, CalculatorIf, extends the
SharedService interface, SharedServiceIf, and subclasses of
CalculatorHandler should implement its methods as well.
Here we provide an implementation for the getStruct method from the
parent service. */
static gboolean
tutorial_calculator_handler_get_struct (SharedServiceIf *iface,
SharedStruct **_return,
const gint32 key32,
GError **error)
{
gint key = (gint)key32;
TutorialCalculatorHandler *self;
SharedStruct *log_struct;
gint log_key;
gchar *log_value;
THRIFT_UNUSED_VAR (error);
g_return_val_if_fail (IS_TUTORIAL_CALCULATOR_HANDLER (iface),
FALSE);
self = TUTORIAL_CALCULATOR_HANDLER (iface);
/* Remember: Complex return types are always pre-created and need
only be populated */
g_assert (*_return != NULL);
printf ("getStruct(%d)\n", key);
/* If the key exists in our log, return the corresponding logged
data (or an empty SharedStruct structure if it does not).
Incidentally, note we _must_ here copy the values from the hash
table into the return structure. All memory used by the return
structure belongs to the structure itself and will be freed once
a response is sent to the client. If we merely freed *_return and
set it to point to our hash-table entry, that would mean memory
would be released (effectively, data erased) out of the hash
table! */
log_struct = g_hash_table_lookup (self->log, &key);
if (log_struct != NULL) {
g_object_get (log_struct,
"key", &log_key,
"value", &log_value,
NULL);
g_object_set (*_return,
"key", log_key,
"value", g_strdup (log_value),
NULL);
}
return TRUE;
}
/* TutorialCalculatorHandler's instance finalizer (destructor) */
static void
tutorial_calculator_handler_finalize (GObject *object)
{
TutorialCalculatorHandler *self =
TUTORIAL_CALCULATOR_HANDLER (object);
/* Free our calculation-log hash table */
g_hash_table_unref (self->log);
self->log = NULL;
/* Chain up to the parent class */
G_OBJECT_CLASS (tutorial_calculator_handler_parent_class)->
finalize (object);
}
/* TutorialCalculatorHandler's instance initializer (constructor) */
static void
tutorial_calculator_handler_init (TutorialCalculatorHandler *self)
{
/* Create our calculation-log hash table */
self->log = g_hash_table_new_full (g_int_hash,
g_int_equal,
g_free,
g_object_unref);
}
/* TutorialCalculatorHandler's class initializer */
static void
tutorial_calculator_handler_class_init (TutorialCalculatorHandlerClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
SharedServiceHandlerClass *shared_service_handler_class =
SHARED_SERVICE_HANDLER_CLASS (klass);
CalculatorHandlerClass *calculator_handler_class =
CALCULATOR_HANDLER_CLASS (klass);
/* Register our destructor */
gobject_class->finalize = tutorial_calculator_handler_finalize;
/* Register our implementations of CalculatorHandler's methods */
calculator_handler_class->ping =
tutorial_calculator_handler_ping;
calculator_handler_class->add =
tutorial_calculator_handler_add;
calculator_handler_class->calculate =
tutorial_calculator_handler_calculate;
calculator_handler_class->zip =
tutorial_calculator_handler_zip;
/* Register our implementation of SharedServiceHandler's method */
shared_service_handler_class->get_struct =
tutorial_calculator_handler_get_struct;
}
/* ---------------------------------------------------------------- */
/* That ends the implementation of TutorialCalculatorHandler.
Everything below is fairly generic code that sets up a minimal
Thrift server for tutorial clients. */
/* Our server object, declared globally so it is accessible within the
SIGINT signal handler */
ThriftServer *server = NULL;
/* A flag that indicates whether the server was interrupted with
SIGINT (i.e. Ctrl-C) so we can tell whether its termination was
abnormal */
gboolean sigint_received = FALSE;
/* Handle SIGINT ("Ctrl-C") signals by gracefully stopping the
server */
static void
sigint_handler (int signal_number)
{
THRIFT_UNUSED_VAR (signal_number);
/* Take note we were called */
sigint_received = TRUE;
/* Shut down the server gracefully */
if (server != NULL)
thrift_server_stop (server);
}
int main (void)
{
TutorialCalculatorHandler *handler;
CalculatorProcessor *processor;
ThriftServerTransport *server_transport;
ThriftTransportFactory *transport_factory;
ThriftProtocolFactory *protocol_factory;
struct sigaction sigint_action;
GError *error = NULL;
int exit_status = 0;
#if (!GLIB_CHECK_VERSION (2, 36, 0))
g_type_init ();
#endif
/* Create an instance of our handler, which provides the service's
methods' implementation */
handler =
g_object_new (TYPE_TUTORIAL_CALCULATOR_HANDLER,
NULL);
/* Create an instance of the service's processor, automatically
generated by the Thrift compiler, which parses incoming messages
and dispatches them to the appropriate method in the handler */
processor =
g_object_new (TYPE_CALCULATOR_PROCESSOR,
"handler", handler,
NULL);
/* Create our server socket, which binds to the specified port and
listens for client connections */
server_transport =
g_object_new (THRIFT_TYPE_SERVER_SOCKET,
"port", 9090,
NULL);
/* Create our transport factory, used by the server to wrap "raw"
incoming connections from the client (in this case with a
ThriftBufferedTransport to improve performance) */
transport_factory =
g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY,
NULL);
/* Create our protocol factory, which determines which wire protocol
the server will use (in this case, Thrift's binary protocol) */
protocol_factory =
g_object_new (THRIFT_TYPE_BINARY_PROTOCOL_FACTORY,
NULL);
/* Create the server itself */
server =
g_object_new (THRIFT_TYPE_SIMPLE_SERVER,
"processor", processor,
"server_transport", server_transport,
"input_transport_factory", transport_factory,
"output_transport_factory", transport_factory,
"input_protocol_factory", protocol_factory,
"output_protocol_factory", protocol_factory,
NULL);
/* Install our SIGINT handler, which handles Ctrl-C being pressed by
stopping the server gracefully (not strictly necessary, but a
nice touch) */
memset (&sigint_action, 0, sizeof (sigint_action));
sigint_action.sa_handler = sigint_handler;
sigint_action.sa_flags = SA_RESETHAND;
sigaction (SIGINT, &sigint_action, NULL);
/* Start the server, which will run until its stop method is invoked
(from within the SIGINT handler, in this case) */
puts ("Starting the server...");
thrift_server_serve (server, &error);
/* If the server stopped for any reason other than having been
interrupted by the user, report the error */
if (!sigint_received) {
g_message ("thrift_server_serve: %s",
error != NULL ? error->message : "(null)");
g_clear_error (&error);
}
puts ("done.");
g_object_unref (server);
g_object_unref (transport_factory);
g_object_unref (protocol_factory);
g_object_unref (server_transport);
g_object_unref (processor);
g_object_unref (handler);
return exit_status;
}

View File

@ -72,7 +72,7 @@ func NewEpoller() (*Epoller, error) {
}, nil
}
// Add creates a epoll console based on the provided console. The console will
// Add creates an epoll console based on the provided console. The console will
// be registered with EPOLLET (i.e. using edge-triggered notification) and its
// file descriptor will be set to non-blocking mode. After this, user should use
// the return console to perform I/O.
@ -134,7 +134,7 @@ func (e *Epoller) Wait() error {
}
}
// Close unregister the console's file descriptor from epoll interface
// CloseConsole unregisters the console's file descriptor from epoll interface
func (e *Epoller) CloseConsole(fd int) error {
e.mu.Lock()
defer e.mu.Unlock()
@ -149,12 +149,12 @@ func (e *Epoller) getConsole(sysfd int) *EpollConsole {
return f
}
// Close the epoll fd
// Close closes the epoll fd
func (e *Epoller) Close() error {
return unix.Close(e.efd)
}
// EpollConsole acts like a console but register its file descriptor with a
// EpollConsole acts like a console but registers its file descriptor with an
// epoll fd and uses epoll API to perform I/O.
type EpollConsole struct {
Console
@ -167,7 +167,7 @@ type EpollConsole struct {
// Read reads up to len(p) bytes into p. It returns the number of bytes read
// (0 <= n <= len(p)) and any error encountered.
//
// If the console's read returns EAGAIN or EIO, we assumes that its a
// If the console's read returns EAGAIN or EIO, we assume that it's a
// temporary error because the other side went away and wait for the signal
// generated by epoll event to continue.
func (ec *EpollConsole) Read(p []byte) (n int, err error) {
@ -207,7 +207,7 @@ func (ec *EpollConsole) Read(p []byte) (n int, err error) {
// written from p (0 <= n <= len(p)) and any error encountered that caused
// the write to stop early.
//
// If writes to the console returns EAGAIN or EIO, we assumes that its a
// If writes to the console returns EAGAIN or EIO, we assume that it's a
// temporary error because the other side went away and wait for the signal
// generated by epoll event to continue.
func (ec *EpollConsole) Write(p []byte) (n int, err error) {
@ -224,7 +224,7 @@ func (ec *EpollConsole) Write(p []byte) (n int, err error) {
} else {
hangup = (err == unix.EAGAIN || err == unix.EIO)
}
// if the other end disappear, assume this is temporary and wait for the
// if the other end disappears, assume this is temporary and wait for the
// signal to continue again.
if hangup {
ec.writec.Wait()
@ -242,7 +242,7 @@ func (ec *EpollConsole) Write(p []byte) (n int, err error) {
return n, err
}
// Close closed the file descriptor and signal call waiters for this fd.
// Shutdown closes the file descriptor and signals call waiters for this fd.
// It accepts a callback which will be called with the console's fd. The
// callback typically will be used to do further cleanup such as unregister the
// console's fd from the epoll interface.

View File

@ -17,7 +17,6 @@
package console
import (
"fmt"
"os"
"github.com/pkg/errors"
@ -29,90 +28,55 @@ var (
ErrNotImplemented = errors.New("not implemented")
)
func (m *master) initStdios() {
m.in = windows.Handle(os.Stdin.Fd())
if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil {
// Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
if err = windows.SetConsoleMode(m.in, m.inMode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil {
vtInputSupported = true
}
// Unconditionally set the console mode back even on failure because SetConsoleMode
// remembers invalid bits on input handles.
windows.SetConsoleMode(m.in, m.inMode)
} else {
fmt.Printf("failed to get console mode for stdin: %v\n", err)
}
m.out = windows.Handle(os.Stdout.Fd())
if err := windows.GetConsoleMode(m.out, &m.outMode); err == nil {
if err := windows.SetConsoleMode(m.out, m.outMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
m.outMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
func (m *master) init() {
m.h = windows.Handle(m.f.Fd())
if err := windows.GetConsoleMode(m.h, &m.mode); err == nil {
if m.f == os.Stdin {
// Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
if err = windows.SetConsoleMode(m.h, m.mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil {
vtInputSupported = true
}
// Unconditionally set the console mode back even on failure because SetConsoleMode
// remembers invalid bits on input handles.
windows.SetConsoleMode(m.h, m.mode)
} else if err := windows.SetConsoleMode(m.h, m.mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
m.mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
} else {
windows.SetConsoleMode(m.out, m.outMode)
windows.SetConsoleMode(m.h, m.mode)
}
} else {
fmt.Printf("failed to get console mode for stdout: %v\n", err)
}
m.err = windows.Handle(os.Stderr.Fd())
if err := windows.GetConsoleMode(m.err, &m.errMode); err == nil {
if err := windows.SetConsoleMode(m.err, m.errMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
m.errMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
} else {
windows.SetConsoleMode(m.err, m.errMode)
}
} else {
fmt.Printf("failed to get console mode for stderr: %v\n", err)
}
}
type master struct {
in windows.Handle
inMode uint32
out windows.Handle
outMode uint32
err windows.Handle
errMode uint32
h windows.Handle
mode uint32
f *os.File
}
func (m *master) SetRaw() error {
if err := makeInputRaw(m.in, m.inMode); err != nil {
return err
if m.f == os.Stdin {
if err := makeInputRaw(m.h, m.mode); err != nil {
return err
}
} else {
// Set StdOut and StdErr to raw mode, we ignore failures since
// windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
// Windows.
windows.SetConsoleMode(m.h, m.mode|windows.DISABLE_NEWLINE_AUTO_RETURN)
}
// Set StdOut and StdErr to raw mode, we ignore failures since
// windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
// Windows.
windows.SetConsoleMode(m.out, m.outMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
windows.SetConsoleMode(m.err, m.errMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
return nil
}
func (m *master) Reset() error {
for _, s := range []struct {
fd windows.Handle
mode uint32
}{
{m.in, m.inMode},
{m.out, m.outMode},
{m.err, m.errMode},
} {
if err := windows.SetConsoleMode(s.fd, s.mode); err != nil {
return errors.Wrap(err, "unable to restore console mode")
}
if err := windows.SetConsoleMode(m.h, m.mode); err != nil {
return errors.Wrap(err, "unable to restore console mode")
}
return nil
}
func (m *master) Size() (WinSize, error) {
var info windows.ConsoleScreenBufferInfo
err := windows.GetConsoleScreenBufferInfo(m.out, &info)
err := windows.GetConsoleScreenBufferInfo(m.h, &info)
if err != nil {
return WinSize{}, errors.Wrap(err, "unable to get console info")
}
@ -134,11 +98,11 @@ func (m *master) ResizeFrom(c Console) error {
}
func (m *master) DisableEcho() error {
mode := m.inMode &^ windows.ENABLE_ECHO_INPUT
mode := m.mode &^ windows.ENABLE_ECHO_INPUT
mode |= windows.ENABLE_PROCESSED_INPUT
mode |= windows.ENABLE_LINE_INPUT
if err := windows.SetConsoleMode(m.in, mode); err != nil {
if err := windows.SetConsoleMode(m.h, mode); err != nil {
return errors.Wrap(err, "unable to set console to disable echo")
}
@ -150,15 +114,15 @@ func (m *master) Close() error {
}
func (m *master) Read(b []byte) (int, error) {
panic("not implemented on windows")
return m.f.Read(b)
}
func (m *master) Write(b []byte) (int, error) {
panic("not implemented on windows")
return m.f.Write(b)
}
func (m *master) Fd() uintptr {
return uintptr(m.in)
return uintptr(m.h)
}
// on windows, console can only be made from os.Std{in,out,err}, hence there
@ -210,7 +174,7 @@ func newMaster(f *os.File) (Console, error) {
if f != os.Stdin && f != os.Stdout && f != os.Stderr {
return nil, errors.New("creating a console from a file is not supported on windows")
}
m := &master{}
m.initStdios()
m := &master{f: f}
m.init()
return m, nil
}

View File

@ -141,18 +141,8 @@ func openFifos(ctx context.Context, fifos *FIFOSet) (pipes, error) {
// NewDirectIO returns an IO implementation that exposes the IO streams as io.ReadCloser
// and io.WriteCloser.
func NewDirectIO(ctx context.Context, fifos *FIFOSet) (*DirectIO, error) {
return newDirectIO(ctx, fifos, false)
}
// NewDirectIOWithTerminal returns an IO implementation that exposes the streams with terminal enabled
func NewDirectIOWithTerminal(ctx context.Context, fifos *FIFOSet) (*DirectIO, error) {
return newDirectIO(ctx, fifos, true)
}
func newDirectIO(ctx context.Context, fifos *FIFOSet, terminal bool) (*DirectIO, error) {
ctx, cancel := context.WithCancel(ctx)
pipes, err := openFifos(ctx, fifos)
fifos.Config.Terminal = terminal
return &DirectIO{
pipes: pipes,
cio: cio{

View File

@ -36,9 +36,9 @@ import (
"github.com/containerd/containerd/runtime/linux/runctypes"
"github.com/gogo/protobuf/proto"
protobuf "github.com/gogo/protobuf/types"
digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/identity"
"github.com/opencontainers/image-spec/specs-go/v1"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
@ -50,10 +50,9 @@ func WithCheckpoint(im Image, snapshotKey string) NewContainerOpts {
return func(ctx context.Context, client *Client, c *containers.Container) error {
var (
desc = im.Target()
id = desc.Digest
store = client.ContentStore()
)
index, err := decodeIndex(ctx, store, id)
index, err := decodeIndex(ctx, store, desc)
if err != nil {
return err
}
@ -80,7 +79,7 @@ func WithCheckpoint(im Image, snapshotKey string) NewContainerOpts {
}
c.Image = index.Annotations["image.name"]
case images.MediaTypeContainerd1CheckpointConfig:
data, err := content.ReadBlob(ctx, store, m.Digest)
data, err := content.ReadBlob(ctx, store, m)
if err != nil {
return errors.Wrap(err, "unable to read checkpoint config")
}
@ -113,7 +112,7 @@ func WithTaskCheckpoint(im Image) NewTaskOpts {
return func(ctx context.Context, c *Client, info *TaskInfo) error {
desc := im.Target()
id := desc.Digest
index, err := decodeIndex(ctx, c.ContentStore(), id)
index, err := decodeIndex(ctx, c.ContentStore(), desc)
if err != nil {
return err
}
@ -131,9 +130,9 @@ func WithTaskCheckpoint(im Image) NewTaskOpts {
}
}
func decodeIndex(ctx context.Context, store content.Provider, id digest.Digest) (*v1.Index, error) {
func decodeIndex(ctx context.Context, store content.Provider, desc ocispec.Descriptor) (*v1.Index, error) {
var index v1.Index
p, err := content.ReadBlob(ctx, store, id)
p, err := content.ReadBlob(ctx, store, desc)
if err != nil {
return nil, err
}

View File

@ -22,6 +22,7 @@ import (
"time"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ReaderAt extends the standard io.ReaderAt interface with reporting of Size and io.Closer
@ -33,12 +34,16 @@ type ReaderAt interface {
// Provider provides a reader interface for specific content
type Provider interface {
ReaderAt(ctx context.Context, dgst digest.Digest) (ReaderAt, error)
// ReaderAt only requires desc.Digest to be set.
// Other fields in the descriptor may be used internally for resolving
// the location of the actual data.
ReaderAt(ctx context.Context, dec ocispec.Descriptor) (ReaderAt, error)
}
// Ingester writes content
type Ingester interface {
Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (Writer, error)
// Some implementations require WithRef to be included in opts.
Writer(ctx context.Context, opts ...WriterOpt) (Writer, error)
}
// Info holds content specific information
@ -142,3 +147,33 @@ func WithLabels(labels map[string]string) Opt {
return nil
}
}
// WriterOpts is internally used by WriterOpt.
type WriterOpts struct {
Ref string
Desc ocispec.Descriptor
}
// WriterOpt is used for passing options to Ingester.Writer.
type WriterOpt func(*WriterOpts) error
// WithDescriptor specifies an OCI descriptor.
// Writer may optionally use the descriptor internally for resolving
// the location of the actual data.
// Write does not require any field of desc to be set.
// If the data size is unknown, desc.Size should be set to 0.
// Some implementations may also accept negative values as "unknown".
func WithDescriptor(desc ocispec.Descriptor) WriterOpt {
return func(opts *WriterOpts) error {
opts.Desc = desc
return nil
}
}
// WithRef specifies a ref string.
func WithRef(ref string) WriterOpt {
return func(opts *WriterOpts) error {
opts.Ref = ref
return nil
}
}

View File

@ -26,6 +26,7 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
@ -45,8 +46,8 @@ func NewReader(ra ReaderAt) io.Reader {
// ReadBlob retrieves the entire contents of the blob from the provider.
//
// Avoid using this for large blobs, such as layers.
func ReadBlob(ctx context.Context, provider Provider, dgst digest.Digest) ([]byte, error) {
ra, err := provider.ReaderAt(ctx, dgst)
func ReadBlob(ctx context.Context, provider Provider, desc ocispec.Descriptor) ([]byte, error) {
ra, err := provider.ReaderAt(ctx, desc)
if err != nil {
return nil, err
}
@ -65,8 +66,8 @@ func ReadBlob(ctx context.Context, provider Provider, dgst digest.Digest) ([]byt
// This is useful when the digest and size are known beforehand.
//
// Copy is buffered, so no need to wrap reader in buffered io.
func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size int64, expected digest.Digest, opts ...Opt) error {
cw, err := OpenWriter(ctx, cs, ref, size, expected)
func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, desc ocispec.Descriptor, opts ...Opt) error {
cw, err := OpenWriter(ctx, cs, WithRef(ref), WithDescriptor(desc))
if err != nil {
if !errdefs.IsAlreadyExists(err) {
return err
@ -76,19 +77,19 @@ func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size i
}
defer cw.Close()
return Copy(ctx, cw, r, size, expected, opts...)
return Copy(ctx, cw, r, desc.Size, desc.Digest, opts...)
}
// OpenWriter opens a new writer for the given reference, retrying if the writer
// is locked until the reference is available or returns an error.
func OpenWriter(ctx context.Context, cs Ingester, ref string, size int64, expected digest.Digest) (Writer, error) {
func OpenWriter(ctx context.Context, cs Ingester, opts ...WriterOpt) (Writer, error) {
var (
cw Writer
err error
retry = 16
)
for {
cw, err = cs.Writer(ctx, ref, size, expected)
cw, err = cs.Writer(ctx, opts...)
if err != nil {
if !errdefs.IsUnavailable(err) {
return nil, err

View File

@ -34,6 +34,7 @@ import (
"github.com/containerd/containerd/filters"
"github.com/containerd/containerd/log"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
@ -119,15 +120,15 @@ func (s *store) info(dgst digest.Digest, fi os.FileInfo, labels map[string]strin
}
// ReaderAt returns an io.ReaderAt for the blob.
func (s *store) ReaderAt(ctx context.Context, dgst digest.Digest) (content.ReaderAt, error) {
p := s.blobPath(dgst)
func (s *store) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
p := s.blobPath(desc.Digest)
fi, err := os.Stat(p)
if err != nil {
if !os.IsNotExist(err) {
return nil, err
}
return nil, errors.Wrapf(errdefs.ErrNotFound, "blob %s expected at %s", dgst, p)
return nil, errors.Wrapf(errdefs.ErrNotFound, "blob %s expected at %s", desc.Digest, p)
}
fp, err := os.Open(p)
@ -136,7 +137,7 @@ func (s *store) ReaderAt(ctx context.Context, dgst digest.Digest) (content.Reade
return nil, err
}
return nil, errors.Wrapf(errdefs.ErrNotFound, "blob %s expected at %s", dgst, p)
return nil, errors.Wrapf(errdefs.ErrNotFound, "blob %s expected at %s", desc.Digest, p)
}
return sizeReaderAt{size: fi.Size(), fp: fp}, nil
@ -400,11 +401,22 @@ func (s *store) total(ingestPath string) int64 {
// ref at a time.
//
// The argument `ref` is used to uniquely identify a long-lived writer transaction.
func (s *store) Writer(ctx context.Context, ref string, total int64, expected digest.Digest) (content.Writer, error) {
func (s *store) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
var wOpts content.WriterOpts
for _, opt := range opts {
if err := opt(&wOpts); err != nil {
return nil, err
}
}
// TODO(AkihiroSuda): we could create a random string or one calculated based on the context
// https://github.com/containerd/containerd/issues/2129#issuecomment-380255019
if wOpts.Ref == "" {
return nil, errors.Wrap(errdefs.ErrInvalidArgument, "ref must not be empty")
}
var lockErr error
for count := uint64(0); count < 10; count++ {
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1<<count)))
if err := tryLock(ref); err != nil {
if err := tryLock(wOpts.Ref); err != nil {
if !errdefs.IsUnavailable(err) {
return nil, err
}
@ -420,9 +432,9 @@ func (s *store) Writer(ctx context.Context, ref string, total int64, expected di
return nil, lockErr
}
w, err := s.writer(ctx, ref, total, expected)
w, err := s.writer(ctx, wOpts.Ref, wOpts.Desc.Size, wOpts.Desc.Digest)
if err != nil {
unlock(ref)
unlock(wOpts.Ref)
return nil, err
}

View File

@ -25,6 +25,7 @@ import (
"github.com/containerd/containerd/errdefs"
protobuftypes "github.com/gogo/protobuf/types"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
type proxyContentStore struct {
@ -88,15 +89,16 @@ func (pcs *proxyContentStore) Delete(ctx context.Context, dgst digest.Digest) er
return nil
}
func (pcs *proxyContentStore) ReaderAt(ctx context.Context, dgst digest.Digest) (content.ReaderAt, error) {
i, err := pcs.Info(ctx, dgst)
// ReaderAt ignores MediaType.
func (pcs *proxyContentStore) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
i, err := pcs.Info(ctx, desc.Digest)
if err != nil {
return nil, err
}
return &remoteReaderAt{
ctx: ctx,
digest: dgst,
digest: desc.Digest,
size: i.Size,
client: pcs.client,
}, nil
@ -157,14 +159,21 @@ func (pcs *proxyContentStore) ListStatuses(ctx context.Context, filters ...strin
return statuses, nil
}
func (pcs *proxyContentStore) Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (content.Writer, error) {
wrclient, offset, err := pcs.negotiate(ctx, ref, size, expected)
// Writer ignores MediaType.
func (pcs *proxyContentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
var wOpts content.WriterOpts
for _, opt := range opts {
if err := opt(&wOpts); err != nil {
return nil, err
}
}
wrclient, offset, err := pcs.negotiate(ctx, wOpts.Ref, wOpts.Desc.Size, wOpts.Desc.Digest)
if err != nil {
return nil, errdefs.FromGRPC(err)
}
return &remoteWriter{
ref: ref,
ref: wOpts.Ref,
client: wrclient,
offset: offset,
}, nil

View File

@ -73,7 +73,7 @@ func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts [
var ocidesc ocispec.Descriptor
if err := mount.WithTempMount(ctx, mounts, func(root string) error {
ra, err := s.store.ReaderAt(ctx, desc.Digest)
ra, err := s.store.ReaderAt(ctx, desc)
if err != nil {
return errors.Wrap(err, "failed to get reader from content store")
}

View File

@ -86,7 +86,11 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o
config.Reference = uniqueRef()
}
cw, err := s.store.Writer(ctx, config.Reference, 0, "")
cw, err := s.store.Writer(ctx,
content.WithRef(config.Reference),
content.WithDescriptor(ocispec.Descriptor{
MediaType: config.MediaType, // most contentstore implementations just ignore this
}))
if err != nil {
return errors.Wrap(err, "failed to open writer")
}

View File

@ -143,7 +143,7 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
if err := Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
switch desc.MediaType {
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
p, err := content.ReadBlob(ctx, provider, desc)
if err != nil {
return nil, err
}
@ -159,7 +159,7 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
}
if desc.Platform == nil {
p, err := content.ReadBlob(ctx, provider, manifest.Config.Digest)
p, err := content.ReadBlob(ctx, provider, manifest.Config)
if err != nil {
return nil, err
}
@ -180,7 +180,7 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
return nil, nil
case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
p, err := content.ReadBlob(ctx, provider, desc)
if err != nil {
return nil, err
}
@ -240,7 +240,7 @@ func Platforms(ctx context.Context, provider content.Provider, image ocispec.Des
switch desc.MediaType {
case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
p, err := content.ReadBlob(ctx, provider, desc)
if err != nil {
return nil, err
}
@ -283,7 +283,7 @@ func Check(ctx context.Context, provider content.Provider, image ocispec.Descrip
required = append([]ocispec.Descriptor{mfst.Config}, mfst.Layers...)
for _, desc := range required {
ra, err := provider.ReaderAt(ctx, desc.Digest)
ra, err := provider.ReaderAt(ctx, desc)
if err != nil {
if errdefs.IsNotFound(err) {
missing = append(missing, desc)
@ -305,7 +305,7 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
var descs []ocispec.Descriptor
switch desc.MediaType {
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
p, err := content.ReadBlob(ctx, provider, desc)
if err != nil {
return nil, err
}
@ -320,7 +320,7 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
descs = append(descs, manifest.Config)
descs = append(descs, manifest.Layers...)
case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
p, err := content.ReadBlob(ctx, provider, desc)
if err != nil {
return nil, err
}
@ -351,7 +351,7 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
// These are used to verify that a set of layers unpacked to the expected
// values.
func RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.Descriptor) ([]digest.Digest, error) {
p, err := content.ReadBlob(ctx, provider, configDesc.Digest)
p, err := content.ReadBlob(ctx, provider, configDesc)
if err != nil {
return nil, err
}

View File

@ -93,7 +93,7 @@ func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord {
Typeflag: tar.TypeReg,
},
CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
r, err := cs.ReaderAt(ctx, desc.Digest)
r, err := cs.ReaderAt(ctx, desc)
if err != nil {
return 0, err
}

View File

@ -140,7 +140,7 @@ func onUntarBlob(ctx context.Context, r io.Reader, store content.Ingester, name
return errors.Errorf("unsupported algorithm: %s", algo)
}
dgst := digest.NewDigestFromHex(algo.String(), split[2])
return content.WriteBlob(ctx, store, "unknown-"+dgst.String(), r, size, dgst)
return content.WriteBlob(ctx, store, "unknown-"+dgst.String(), r, ocispec.Descriptor{Size: size, Digest: dgst})
}
// GetChildrenDescriptors returns children blob descriptors for the following supported types:
@ -175,7 +175,7 @@ func setGCRefContentLabels(ctx context.Context, store content.Store, desc ocispe
}
return err
}
ra, err := store.ReaderAt(ctx, desc.Digest)
ra, err := store.ReaderAt(ctx, desc)
if err != nil {
return err
}

View File

@ -32,6 +32,7 @@ import (
"github.com/containerd/containerd/metadata/boltutil"
"github.com/containerd/containerd/namespaces"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
@ -337,7 +338,18 @@ func (cs *contentStore) Abort(ctx context.Context, ref string) error {
}
func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (content.Writer, error) {
func (cs *contentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
var wOpts content.WriterOpts
for _, opt := range opts {
if err := opt(&wOpts); err != nil {
return nil, err
}
}
// TODO(AkihiroSuda): we could create a random string or one calculated based on the context
// https://github.com/containerd/containerd/issues/2129#issuecomment-380255019
if wOpts.Ref == "" {
return nil, errors.Wrap(errdefs.ErrInvalidArgument, "ref must not be empty")
}
ns, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return nil, err
@ -353,12 +365,12 @@ func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expe
)
if err := update(ctx, cs.db, func(tx *bolt.Tx) error {
var shared bool
if expected != "" {
cbkt := getBlobBucket(tx, ns, expected)
if wOpts.Desc.Digest != "" {
cbkt := getBlobBucket(tx, ns, wOpts.Desc.Digest)
if cbkt != nil {
// Add content to lease to prevent other reference removals
// from effecting this object during a provided lease
if err := addContentLease(ctx, tx, expected); err != nil {
if err := addContentLease(ctx, tx, wOpts.Desc.Digest); err != nil {
return errors.Wrap(err, "unable to lease content")
}
// Return error outside of transaction to ensure
@ -367,18 +379,18 @@ func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expe
return nil
}
if st, err := cs.Store.Info(ctx, expected); err == nil {
if st, err := cs.Store.Info(ctx, wOpts.Desc.Digest); err == nil {
// Ensure the expected size is the same, it is likely
// an error if the size is mismatched but the caller
// must resolve this on commit
if size == 0 || size == st.Size {
if wOpts.Desc.Size == 0 || wOpts.Desc.Size == st.Size {
shared = true
size = st.Size
wOpts.Desc.Size = st.Size
}
}
}
bkt, err := createIngestBucket(tx, ns, ref)
bkt, err := createIngestBucket(tx, ns, wOpts.Ref)
if err != nil {
return err
}
@ -390,7 +402,7 @@ func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expe
return err
}
bref = createKey(sid, ns, ref)
bref = createKey(sid, ns, wOpts.Ref)
if err := bkt.Put(bucketKeyRef, []byte(bref)); err != nil {
return err
}
@ -399,7 +411,7 @@ func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expe
}
if shared {
if err := bkt.Put(bucketKeyExpected, []byte(expected)); err != nil {
if err := bkt.Put(bucketKeyExpected, []byte(wOpts.Desc.Digest)); err != nil {
return err
}
} else {
@ -407,19 +419,21 @@ func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expe
// already checked against the user metadata. The content must
// be committed in the namespace before it will be seen as
// available in the current namespace.
w, err = cs.Store.Writer(ctx, bref, size, "")
desc := wOpts.Desc
desc.Digest = ""
w, err = cs.Store.Writer(ctx, content.WithRef(bref), content.WithDescriptor(desc))
}
return err
}); err != nil {
return nil, err
}
if exists {
return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", expected)
return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", wOpts.Desc.Digest)
}
return &namespacedWriter{
ctx: ctx,
ref: ref,
ref: wOpts.Ref,
namespace: ns,
db: cs.db,
provider: cs.Store,
@ -427,8 +441,7 @@ func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expe
w: w,
bref: bref,
started: time.Now(),
expected: expected,
size: size,
desc: wOpts.Desc,
}, nil
}
@ -445,10 +458,9 @@ type namespacedWriter struct {
w content.Writer
bref string
started time.Time
expected digest.Digest
size int64
bref string
started time.Time
desc ocispec.Descriptor
}
func (nw *namespacedWriter) Close() error {
@ -465,7 +477,7 @@ func (nw *namespacedWriter) Write(p []byte) (int, error) {
return 0, nil
}
if err := nw.createAndCopy(nw.ctx, nw.size); err != nil {
if err := nw.createAndCopy(nw.ctx, nw.desc); err != nil {
return 0, err
}
}
@ -477,31 +489,35 @@ func (nw *namespacedWriter) Digest() digest.Digest {
if nw.w != nil {
return nw.w.Digest()
}
return nw.expected
return nw.desc.Digest
}
func (nw *namespacedWriter) Truncate(size int64) error {
if nw.w != nil {
return nw.w.Truncate(size)
}
return nw.createAndCopy(nw.ctx, size)
desc := nw.desc
desc.Size = size
desc.Digest = ""
return nw.createAndCopy(nw.ctx, desc)
}
func (nw *namespacedWriter) createAndCopy(ctx context.Context, size int64) error {
w, err := nw.provider.Writer(ctx, nw.bref, nw.size, "")
func (nw *namespacedWriter) createAndCopy(ctx context.Context, desc ocispec.Descriptor) error {
nwDescWithoutDigest := desc
nwDescWithoutDigest.Digest = ""
w, err := nw.provider.Writer(ctx, content.WithRef(nw.bref), content.WithDescriptor(nwDescWithoutDigest))
if err != nil {
return err
}
if size > 0 {
ra, err := nw.provider.ReaderAt(ctx, nw.expected)
if desc.Size > 0 {
ra, err := nw.provider.ReaderAt(ctx, nw.desc)
if err != nil {
return err
}
defer ra.Close()
if err := content.CopyReaderAt(w, ra, size); err != nil {
if err := content.CopyReaderAt(w, ra, desc.Size); err != nil {
nw.w.Close()
nw.w = nil
return err
@ -544,14 +560,14 @@ func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64,
var actual digest.Digest
if nw.w == nil {
if size != 0 && size != nw.size {
return "", errors.Errorf("%q failed size validation: %v != %v", nw.ref, nw.size, size)
if size != 0 && size != nw.desc.Size {
return "", errors.Errorf("%q failed size validation: %v != %v", nw.ref, nw.desc.Size, size)
}
if expected != "" && expected != nw.expected {
if expected != "" && expected != nw.desc.Digest {
return "", errors.Errorf("%q unexpected digest", nw.ref)
}
size = nw.size
actual = nw.expected
size = nw.desc.Size
actual = nw.desc.Digest
if getBlobBucket(tx, nw.namespace, actual) != nil {
return "", errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", actual)
}
@ -601,11 +617,11 @@ func (nw *namespacedWriter) Status() (st content.Status, err error) {
if nw.w != nil {
st, err = nw.w.Status()
} else {
st.Offset = nw.size
st.Total = nw.size
st.Offset = nw.desc.Size
st.Total = nw.desc.Size
st.StartedAt = nw.started
st.UpdatedAt = nw.started
st.Expected = nw.expected
st.Expected = nw.desc.Digest
}
if err == nil {
st.Ref = nw.ref
@ -613,11 +629,11 @@ func (nw *namespacedWriter) Status() (st content.Status, err error) {
return
}
func (cs *contentStore) ReaderAt(ctx context.Context, dgst digest.Digest) (content.ReaderAt, error) {
if err := cs.checkAccess(ctx, dgst); err != nil {
func (cs *contentStore) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
if err := cs.checkAccess(ctx, desc.Digest); err != nil {
return nil, err
}
return cs.Store.ReaderAt(ctx, dgst)
return cs.Store.ReaderAt(ctx, desc)
}
func (cs *contentStore) checkAccess(ctx context.Context, dgst digest.Digest) error {

View File

@ -117,7 +117,7 @@ func WithImageConfig(image Image) SpecOpts {
)
switch ic.MediaType {
case v1.MediaTypeImageConfig, images.MediaTypeDockerSchema2Config:
p, err := content.ReadBlob(ctx, image.ContentStore(), ic.Digest)
p, err := content.ReadBlob(ctx, image.ContentStore(), ic)
if err != nil {
return err
}

View File

@ -44,7 +44,7 @@ func WithImageConfig(image Image) SpecOpts {
)
switch ic.MediaType {
case v1.MediaTypeImageConfig, images.MediaTypeDockerSchema2Config:
p, err := content.ReadBlob(ctx, image.ContentStore(), ic.Digest)
p, err := content.ReadBlob(ctx, image.ContentStore(), ic)
if err != nil {
return err
}

View File

@ -155,9 +155,18 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
location := resp.Header.Get("Location")
// Support paths without host in location
if strings.HasPrefix(location, "/") {
u := p.base
u.Path = location
location = u.String()
// Support location string containing path and query
qmIndex := strings.Index(location, "?")
if qmIndex > 0 {
u := p.base
u.Path = location[:qmIndex]
u.RawQuery = location[qmIndex+1:]
location = u.String()
} else {
u := p.base
u.Path = location
location = u.String()
}
}
req, err = http.NewRequest(http.MethodPut, location, nil)

View File

@ -211,12 +211,12 @@ func (c *Converter) Convert(ctx context.Context, opts ...ConvertOpt) (ocispec.De
}
ref := remotes.MakeRefKey(ctx, desc)
if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(mb), desc.Size, desc.Digest, content.WithLabels(labels)); err != nil {
if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(mb), desc, content.WithLabels(labels)); err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
}
ref = remotes.MakeRefKey(ctx, config)
if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(b), config.Size, config.Digest); err != nil {
if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(b), config); err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
}
@ -257,15 +257,15 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
var (
ref = remotes.MakeRefKey(ctx, desc)
calc = newBlobStateCalculator()
size = desc.Size
)
// size may be unknown, set to zero for content ingest
if size == -1 {
size = 0
ingestDesc := desc
if ingestDesc.Size == -1 {
ingestDesc.Size = 0
}
cw, err := content.OpenWriter(ctx, c.contentStore, ref, size, desc.Digest)
cw, err := content.OpenWriter(ctx, c.contentStore, content.WithRef(ref), content.WithDescriptor(ingestDesc))
if err != nil {
if !errdefs.IsAlreadyExists(err) {
return err
@ -274,7 +274,7 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
// TODO: Check if blob -> diff id mapping already exists
// TODO: Check if blob empty label exists
ra, err := c.contentStore.ReaderAt(ctx, desc.Digest)
ra, err := c.contentStore.ReaderAt(ctx, desc)
if err != nil {
return err
}
@ -317,7 +317,7 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
eg.Go(func() error {
defer pw.Close()
return content.Copy(ctx, cw, io.TeeReader(rc, pw), size, desc.Digest)
return content.Copy(ctx, cw, io.TeeReader(rc, pw), ingestDesc.Size, ingestDesc.Digest)
})
if err := eg.Wait(); err != nil {

View File

@ -81,7 +81,7 @@ 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")
cw, err := content.OpenWriter(ctx, ingester, MakeRefKey(ctx, desc), desc.Size, desc.Digest)
cw, err := content.OpenWriter(ctx, ingester, content.WithRef(MakeRefKey(ctx, desc)), content.WithDescriptor(desc))
if err != nil {
if errdefs.IsAlreadyExists(err) {
return nil
@ -141,7 +141,7 @@ func push(ctx context.Context, provider content.Provider, pusher Pusher, desc oc
}
defer cw.Close()
ra, err := provider.ReaderAt(ctx, desc.Digest)
ra, err := provider.ReaderAt(ctx, desc)
if err != nil {
return err
}

View File

@ -597,7 +597,7 @@ func (t *task) writeIndex(ctx context.Context, index *v1.Index) (d v1.Descriptor
}
func writeContent(ctx context.Context, store content.Ingester, mediaType, ref string, r io.Reader, opts ...content.Opt) (d v1.Descriptor, err error) {
writer, err := store.Writer(ctx, ref, 0, "")
writer, err := store.Writer(ctx, content.WithRef(ref))
if err != nil {
return d, err
}

View File

@ -1,5 +1,5 @@
github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd5
github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925
github.com/containerd/console 9290d21dc56074581f619579c43d970b4514bc08
github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130
github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
@ -43,8 +43,7 @@ github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16
github.com/gotestyourself/gotestyourself 44dbf532bbf5767611f6f2a61bded572e337010a
github.com/google/go-cmp v0.1.0
# cri dependencies
github.com/containerd/cri b68fb075d49aa1c2885f45f2467142666c244f4a
github.com/containerd/cri 8bcb9a95394e8d7845da1d6a994d3ac2a86d22f0
github.com/containerd/go-cni f2d7272f12d045b16ed924f50e91f9f9cecc55a7
github.com/blang/semver v3.1.0
github.com/containernetworking/cni v0.6.0

4
vendor/github.com/docker/docker/contrib/README.md generated vendored Normal file
View File

@ -0,0 +1,4 @@
The `contrib` directory contains scripts, images, and other helpful things
which are not part of the core docker distribution. Please note that they
could be out of date, since they do not receive the same attention as the
rest of the repository.

View File

@ -0,0 +1,10 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
printf("EUID=%d\n", geteuid());
return 0;
}

View File

@ -0,0 +1,16 @@
#define _GNU_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
int err = acct("/tmp/t");
if (err == -1) {
fprintf(stderr, "acct failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,7 @@
.globl _start
.text
_start:
xorl %eax, %eax
incl %eax
movb $0, %bl
int $0x80

View File

@ -0,0 +1,63 @@
#define _GNU_SOURCE
#include <errno.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#define STACK_SIZE (1024 * 1024) /* Stack size for cloned child */
struct clone_args {
char **argv;
};
// child_exec is the func that will be executed as the result of clone
static int child_exec(void *stuff)
{
struct clone_args *args = (struct clone_args *)stuff;
if (execvp(args->argv[0], args->argv) != 0) {
fprintf(stderr, "failed to execvp arguments %s\n",
strerror(errno));
exit(-1);
}
// we should never reach here!
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
struct clone_args args;
args.argv = &argv[1];
int clone_flags = CLONE_NEWNS | CLONE_NEWPID | SIGCHLD;
// allocate stack for child
char *stack; /* Start of stack buffer */
char *child_stack; /* End of stack buffer */
stack =
mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANON | MAP_STACK, -1, 0);
if (stack == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
child_stack = stack + STACK_SIZE; /* Assume stack grows downward */
// the result of this call is that our child_exec will be run in another
// process returning its pid
pid_t pid = clone(child_exec, child_stack, clone_flags, &args);
if (pid < 0) {
fprintf(stderr, "clone failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// lets wait on our child process here before we, the parent, exits
if (waitpid(pid, NULL, 0) == -1) {
fprintf(stderr, "failed to wait pid %d\n", pid);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,14 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
int main() {
if (socket(PF_INET, SOCK_RAW, IPPROTO_UDP) == -1) {
perror("socket");
return 1;
}
return 0;
}

View File

@ -0,0 +1,11 @@
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main() {
if (setgid(1) == -1) {
perror("setgid");
return 1;
}
return 0;
}

View File

@ -0,0 +1,11 @@
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main() {
if (setuid(1) == -1) {
perror("setuid");
return 1;
}
return 0;
}

View File

@ -0,0 +1,30 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int s;
struct sockaddr_in sin;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) {
perror("socket");
return 1;
}
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(80);
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
perror("bind");
return 1;
}
close(s);
return 0;
}

View File

@ -0,0 +1,63 @@
#define _GNU_SOURCE
#include <errno.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#define STACK_SIZE (1024 * 1024) /* Stack size for cloned child */
struct clone_args {
char **argv;
};
// child_exec is the func that will be executed as the result of clone
static int child_exec(void *stuff)
{
struct clone_args *args = (struct clone_args *)stuff;
if (execvp(args->argv[0], args->argv) != 0) {
fprintf(stderr, "failed to execvp arguments %s\n",
strerror(errno));
exit(-1);
}
// we should never reach here!
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
struct clone_args args;
args.argv = &argv[1];
int clone_flags = CLONE_NEWUSER | SIGCHLD;
// allocate stack for child
char *stack; /* Start of stack buffer */
char *child_stack; /* End of stack buffer */
stack =
mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANON | MAP_STACK, -1, 0);
if (stack == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
child_stack = stack + STACK_SIZE; /* Assume stack grows downward */
// the result of this call is that our child_exec will be run in another
// process returning its pid
pid_t pid = clone(child_exec, child_stack, clone_flags, &args);
if (pid < 0) {
fprintf(stderr, "clone failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// lets wait on our child process here before we, the parent, exits
if (waitpid(pid, NULL, 0) == -1) {
fprintf(stderr, "failed to wait pid %d\n", pid);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

48
vendor/golang.org/x/sys/windows/svc/event.go generated vendored Normal file
View File

@ -0,0 +1,48 @@
// Copyright 2012 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 windows
package svc
import (
"errors"
"golang.org/x/sys/windows"
)
// event represents auto-reset, initially non-signaled Windows event.
// It is used to communicate between go and asm parts of this package.
type event struct {
h windows.Handle
}
func newEvent() (*event, error) {
h, err := windows.CreateEvent(nil, 0, 0, nil)
if err != nil {
return nil, err
}
return &event{h: h}, nil
}
func (e *event) Close() error {
return windows.CloseHandle(e.h)
}
func (e *event) Set() error {
return windows.SetEvent(e.h)
}
func (e *event) Wait() error {
s, err := windows.WaitForSingleObject(e.h, windows.INFINITE)
switch s {
case windows.WAIT_OBJECT_0:
break
case windows.WAIT_FAILED:
return err
default:
return errors.New("unexpected result from WaitForSingleObject")
}
return nil
}

24
vendor/golang.org/x/sys/windows/svc/go12.c generated vendored Normal file
View File

@ -0,0 +1,24 @@
// Copyright 2012 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 windows
// +build !go1.3
// copied from pkg/runtime
typedef unsigned int uint32;
typedef unsigned long long int uint64;
#ifdef _64BIT
typedef uint64 uintptr;
#else
typedef uint32 uintptr;
#endif
// from sys_386.s or sys_amd64.s
void ·servicemain(void);
void
·getServiceMain(uintptr *r)
{
*r = (uintptr)·servicemain;
}

11
vendor/golang.org/x/sys/windows/svc/go12.go generated vendored Normal file
View File

@ -0,0 +1,11 @@
// 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 windows
// +build !go1.3
package svc
// from go12.c
func getServiceMain(r *uintptr)

31
vendor/golang.org/x/sys/windows/svc/go13.go generated vendored Normal file
View File

@ -0,0 +1,31 @@
// 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 windows
// +build go1.3
package svc
import "unsafe"
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
// Should be a built-in for unsafe.Pointer?
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
return unsafe.Pointer(uintptr(p) + x)
}
// funcPC returns the entry PC of the function f.
// It assumes that f is a func value. Otherwise the behavior is undefined.
func funcPC(f interface{}) uintptr {
return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize))
}
// from sys_386.s and sys_amd64.s
func servicectlhandler(ctl uint32) uintptr
func servicemain(argc uint32, argv **uint16)
func getServiceMain(r *uintptr) {
*r = funcPC(servicemain)
}

62
vendor/golang.org/x/sys/windows/svc/security.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
// Copyright 2012 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 windows
package svc
import (
"unsafe"
"golang.org/x/sys/windows"
)
func allocSid(subAuth0 uint32) (*windows.SID, error) {
var sid *windows.SID
err := windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY,
1, subAuth0, 0, 0, 0, 0, 0, 0, 0, &sid)
if err != nil {
return nil, err
}
return sid, nil
}
// IsAnInteractiveSession determines if calling process is running interactively.
// It queries the process token for membership in the Interactive group.
// http://stackoverflow.com/questions/2668851/how-do-i-detect-that-my-application-is-running-as-service-or-in-an-interactive-s
func IsAnInteractiveSession() (bool, error) {
interSid, err := allocSid(windows.SECURITY_INTERACTIVE_RID)
if err != nil {
return false, err
}
defer windows.FreeSid(interSid)
serviceSid, err := allocSid(windows.SECURITY_SERVICE_RID)
if err != nil {
return false, err
}
defer windows.FreeSid(serviceSid)
t, err := windows.OpenCurrentProcessToken()
if err != nil {
return false, err
}
defer t.Close()
gs, err := t.GetTokenGroups()
if err != nil {
return false, err
}
p := unsafe.Pointer(&gs.Groups[0])
groups := (*[2 << 20]windows.SIDAndAttributes)(p)[:gs.GroupCount]
for _, g := range groups {
if windows.EqualSid(g.Sid, interSid) {
return true, nil
}
if windows.EqualSid(g.Sid, serviceSid) {
return false, nil
}
}
return false, nil
}

363
vendor/golang.org/x/sys/windows/svc/service.go generated vendored Normal file
View File

@ -0,0 +1,363 @@
// Copyright 2012 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 windows
// Package svc provides everything required to build Windows service.
//
package svc
import (
"errors"
"runtime"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// State describes service execution state (Stopped, Running and so on).
type State uint32
const (
Stopped = State(windows.SERVICE_STOPPED)
StartPending = State(windows.SERVICE_START_PENDING)
StopPending = State(windows.SERVICE_STOP_PENDING)
Running = State(windows.SERVICE_RUNNING)
ContinuePending = State(windows.SERVICE_CONTINUE_PENDING)
PausePending = State(windows.SERVICE_PAUSE_PENDING)
Paused = State(windows.SERVICE_PAUSED)
)
// Cmd represents service state change request. It is sent to a service
// by the service manager, and should be actioned upon by the service.
type Cmd uint32
const (
Stop = Cmd(windows.SERVICE_CONTROL_STOP)
Pause = Cmd(windows.SERVICE_CONTROL_PAUSE)
Continue = Cmd(windows.SERVICE_CONTROL_CONTINUE)
Interrogate = Cmd(windows.SERVICE_CONTROL_INTERROGATE)
Shutdown = Cmd(windows.SERVICE_CONTROL_SHUTDOWN)
ParamChange = Cmd(windows.SERVICE_CONTROL_PARAMCHANGE)
NetBindAdd = Cmd(windows.SERVICE_CONTROL_NETBINDADD)
NetBindRemove = Cmd(windows.SERVICE_CONTROL_NETBINDREMOVE)
NetBindEnable = Cmd(windows.SERVICE_CONTROL_NETBINDENABLE)
NetBindDisable = Cmd(windows.SERVICE_CONTROL_NETBINDDISABLE)
DeviceEvent = Cmd(windows.SERVICE_CONTROL_DEVICEEVENT)
HardwareProfileChange = Cmd(windows.SERVICE_CONTROL_HARDWAREPROFILECHANGE)
PowerEvent = Cmd(windows.SERVICE_CONTROL_POWEREVENT)
SessionChange = Cmd(windows.SERVICE_CONTROL_SESSIONCHANGE)
)
// Accepted is used to describe commands accepted by the service.
// Note that Interrogate is always accepted.
type Accepted uint32
const (
AcceptStop = Accepted(windows.SERVICE_ACCEPT_STOP)
AcceptShutdown = Accepted(windows.SERVICE_ACCEPT_SHUTDOWN)
AcceptPauseAndContinue = Accepted(windows.SERVICE_ACCEPT_PAUSE_CONTINUE)
AcceptParamChange = Accepted(windows.SERVICE_ACCEPT_PARAMCHANGE)
AcceptNetBindChange = Accepted(windows.SERVICE_ACCEPT_NETBINDCHANGE)
AcceptHardwareProfileChange = Accepted(windows.SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
AcceptPowerEvent = Accepted(windows.SERVICE_ACCEPT_POWEREVENT)
AcceptSessionChange = Accepted(windows.SERVICE_ACCEPT_SESSIONCHANGE)
)
// Status combines State and Accepted commands to fully describe running service.
type Status struct {
State State
Accepts Accepted
CheckPoint uint32 // used to report progress during a lengthy operation
WaitHint uint32 // estimated time required for a pending operation, in milliseconds
}
// ChangeRequest is sent to the service Handler to request service status change.
type ChangeRequest struct {
Cmd Cmd
EventType uint32
EventData uintptr
CurrentStatus Status
}
// Handler is the interface that must be implemented to build Windows service.
type Handler interface {
// Execute will be called by the package code at the start of
// the service, and the service will exit once Execute completes.
// Inside Execute you must read service change requests from r and
// act accordingly. You must keep service control manager up to date
// about state of your service by writing into s as required.
// args contains service name followed by argument strings passed
// to the service.
// You can provide service exit code in exitCode return parameter,
// with 0 being "no error". You can also indicate if exit code,
// if any, is service specific or not by using svcSpecificEC
// parameter.
Execute(args []string, r <-chan ChangeRequest, s chan<- Status) (svcSpecificEC bool, exitCode uint32)
}
var (
// These are used by asm code.
goWaitsH uintptr
cWaitsH uintptr
ssHandle uintptr
sName *uint16
sArgc uintptr
sArgv **uint16
ctlHandlerExProc uintptr
cSetEvent uintptr
cWaitForSingleObject uintptr
cRegisterServiceCtrlHandlerExW uintptr
)
func init() {
k := syscall.MustLoadDLL("kernel32.dll")
cSetEvent = k.MustFindProc("SetEvent").Addr()
cWaitForSingleObject = k.MustFindProc("WaitForSingleObject").Addr()
a := syscall.MustLoadDLL("advapi32.dll")
cRegisterServiceCtrlHandlerExW = a.MustFindProc("RegisterServiceCtrlHandlerExW").Addr()
}
// The HandlerEx prototype also has a context pointer but since we don't use
// it at start-up time we don't have to pass it over either.
type ctlEvent struct {
cmd Cmd
eventType uint32
eventData uintptr
errno uint32
}
// service provides access to windows service api.
type service struct {
name string
h windows.Handle
cWaits *event
goWaits *event
c chan ctlEvent
handler Handler
}
func newService(name string, handler Handler) (*service, error) {
var s service
var err error
s.name = name
s.c = make(chan ctlEvent)
s.handler = handler
s.cWaits, err = newEvent()
if err != nil {
return nil, err
}
s.goWaits, err = newEvent()
if err != nil {
s.cWaits.Close()
return nil, err
}
return &s, nil
}
func (s *service) close() error {
s.cWaits.Close()
s.goWaits.Close()
return nil
}
type exitCode struct {
isSvcSpecific bool
errno uint32
}
func (s *service) updateStatus(status *Status, ec *exitCode) error {
if s.h == 0 {
return errors.New("updateStatus with no service status handle")
}
var t windows.SERVICE_STATUS
t.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
t.CurrentState = uint32(status.State)
if status.Accepts&AcceptStop != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_STOP
}
if status.Accepts&AcceptShutdown != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_SHUTDOWN
}
if status.Accepts&AcceptPauseAndContinue != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_PAUSE_CONTINUE
}
if status.Accepts&AcceptParamChange != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_PARAMCHANGE
}
if status.Accepts&AcceptNetBindChange != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_NETBINDCHANGE
}
if status.Accepts&AcceptHardwareProfileChange != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_HARDWAREPROFILECHANGE
}
if status.Accepts&AcceptPowerEvent != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_POWEREVENT
}
if status.Accepts&AcceptSessionChange != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_SESSIONCHANGE
}
if ec.errno == 0 {
t.Win32ExitCode = windows.NO_ERROR
t.ServiceSpecificExitCode = windows.NO_ERROR
} else if ec.isSvcSpecific {
t.Win32ExitCode = uint32(windows.ERROR_SERVICE_SPECIFIC_ERROR)
t.ServiceSpecificExitCode = ec.errno
} else {
t.Win32ExitCode = ec.errno
t.ServiceSpecificExitCode = windows.NO_ERROR
}
t.CheckPoint = status.CheckPoint
t.WaitHint = status.WaitHint
return windows.SetServiceStatus(s.h, &t)
}
const (
sysErrSetServiceStatusFailed = uint32(syscall.APPLICATION_ERROR) + iota
sysErrNewThreadInCallback
)
func (s *service) run() {
s.goWaits.Wait()
s.h = windows.Handle(ssHandle)
argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc]
args := make([]string, len(argv))
for i, a := range argv {
args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:])
}
cmdsToHandler := make(chan ChangeRequest)
changesFromHandler := make(chan Status)
exitFromHandler := make(chan exitCode)
go func() {
ss, errno := s.handler.Execute(args, cmdsToHandler, changesFromHandler)
exitFromHandler <- exitCode{ss, errno}
}()
status := Status{State: Stopped}
ec := exitCode{isSvcSpecific: true, errno: 0}
var outch chan ChangeRequest
inch := s.c
var cmd Cmd
var evtype uint32
var evdata uintptr
loop:
for {
select {
case r := <-inch:
if r.errno != 0 {
ec.errno = r.errno
break loop
}
inch = nil
outch = cmdsToHandler
cmd = r.cmd
evtype = r.eventType
evdata = r.eventData
case outch <- ChangeRequest{cmd, evtype, evdata, status}:
inch = s.c
outch = nil
case c := <-changesFromHandler:
err := s.updateStatus(&c, &ec)
if err != nil {
// best suitable error number
ec.errno = sysErrSetServiceStatusFailed
if err2, ok := err.(syscall.Errno); ok {
ec.errno = uint32(err2)
}
break loop
}
status = c
case ec = <-exitFromHandler:
break loop
}
}
s.updateStatus(&Status{State: Stopped}, &ec)
s.cWaits.Set()
}
func newCallback(fn interface{}) (cb uintptr, err error) {
defer func() {
r := recover()
if r == nil {
return
}
cb = 0
switch v := r.(type) {
case string:
err = errors.New(v)
case error:
err = v
default:
err = errors.New("unexpected panic in syscall.NewCallback")
}
}()
return syscall.NewCallback(fn), nil
}
// BUG(brainman): There is no mechanism to run multiple services
// inside one single executable. Perhaps, it can be overcome by
// using RegisterServiceCtrlHandlerEx Windows api.
// Run executes service name by calling appropriate handler function.
func Run(name string, handler Handler) error {
runtime.LockOSThread()
tid := windows.GetCurrentThreadId()
s, err := newService(name, handler)
if err != nil {
return err
}
ctlHandler := func(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr {
e := ctlEvent{cmd: Cmd(ctl), eventType: evtype, eventData: evdata}
// We assume that this callback function is running on
// the same thread as Run. Nowhere in MS documentation
// I could find statement to guarantee that. So putting
// check here to verify, otherwise things will go bad
// quickly, if ignored.
i := windows.GetCurrentThreadId()
if i != tid {
e.errno = sysErrNewThreadInCallback
}
s.c <- e
// Always return NO_ERROR (0) for now.
return 0
}
var svcmain uintptr
getServiceMain(&svcmain)
t := []windows.SERVICE_TABLE_ENTRY{
{syscall.StringToUTF16Ptr(s.name), svcmain},
{nil, 0},
}
goWaitsH = uintptr(s.goWaits.h)
cWaitsH = uintptr(s.cWaits.h)
sName = t[0].ServiceName
ctlHandlerExProc, err = newCallback(ctlHandler)
if err != nil {
return err
}
go s.run()
err = windows.StartServiceCtrlDispatcher(&t[0])
if err != nil {
return err
}
return nil
}
// StatusHandle returns service status handle. It is safe to call this function
// from inside the Handler.Execute because then it is guaranteed to be set.
// This code will have to change once multiple services are possible per process.
func StatusHandle() windows.Handle {
return windows.Handle(ssHandle)
}

68
vendor/golang.org/x/sys/windows/svc/sys_386.s generated vendored Normal file
View File

@ -0,0 +1,68 @@
// Copyright 2012 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 windows
// func servicemain(argc uint32, argv **uint16)
TEXT ·servicemain(SB),7,$0
MOVL argc+0(FP), AX
MOVL AX, ·sArgc(SB)
MOVL argv+4(FP), AX
MOVL AX, ·sArgv(SB)
PUSHL BP
PUSHL BX
PUSHL SI
PUSHL DI
SUBL $12, SP
MOVL ·sName(SB), AX
MOVL AX, (SP)
MOVL $·servicectlhandler(SB), AX
MOVL AX, 4(SP)
MOVL $0, 8(SP)
MOVL ·cRegisterServiceCtrlHandlerExW(SB), AX
MOVL SP, BP
CALL AX
MOVL BP, SP
CMPL AX, $0
JE exit
MOVL AX, ·ssHandle(SB)
MOVL ·goWaitsH(SB), AX
MOVL AX, (SP)
MOVL ·cSetEvent(SB), AX
MOVL SP, BP
CALL AX
MOVL BP, SP
MOVL ·cWaitsH(SB), AX
MOVL AX, (SP)
MOVL $-1, AX
MOVL AX, 4(SP)
MOVL ·cWaitForSingleObject(SB), AX
MOVL SP, BP
CALL AX
MOVL BP, SP
exit:
ADDL $12, SP
POPL DI
POPL SI
POPL BX
POPL BP
MOVL 0(SP), CX
ADDL $12, SP
JMP CX
// I do not know why, but this seems to be the only way to call
// ctlHandlerProc on Windows 7.
// func servicectlhandler(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr {
TEXT ·servicectlhandler(SB),7,$0
MOVL ·ctlHandlerExProc(SB), CX
JMP CX

42
vendor/golang.org/x/sys/windows/svc/sys_amd64.s generated vendored Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2012 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 windows
// func servicemain(argc uint32, argv **uint16)
TEXT ·servicemain(SB),7,$0
MOVL CX, ·sArgc(SB)
MOVL DX, ·sArgv(SB)
SUBQ $32, SP // stack for the first 4 syscall params
MOVQ ·sName(SB), CX
MOVQ $·servicectlhandler(SB), DX
// BUG(pastarmovj): Figure out a way to pass in context in R8.
MOVQ ·cRegisterServiceCtrlHandlerExW(SB), AX
CALL AX
CMPQ AX, $0
JE exit
MOVQ AX, ·ssHandle(SB)
MOVQ ·goWaitsH(SB), CX
MOVQ ·cSetEvent(SB), AX
CALL AX
MOVQ ·cWaitsH(SB), CX
MOVQ $4294967295, DX
MOVQ ·cWaitForSingleObject(SB), AX
CALL AX
exit:
ADDQ $32, SP
RET
// I do not know why, but this seems to be the only way to call
// ctlHandlerProc on Windows 7.
// func ·servicectlhandler(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr {
TEXT ·servicectlhandler(SB),7,$0
MOVQ ·ctlHandlerExProc(SB), AX
JMP AX