Browse code

vendor: update buildkit to v0.16.0-rc1

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>

CrazyMax authored on 2024/08/08 18:25:32
Showing 86 changed files
... ...
@@ -33,7 +33,7 @@ require (
33 33
 	github.com/containerd/fifo v1.1.0
34 34
 	github.com/containerd/log v0.1.0
35 35
 	github.com/containerd/platforms v0.2.1
36
-	github.com/containerd/typeurl/v2 v2.1.1
36
+	github.com/containerd/typeurl/v2 v2.2.0
37 37
 	github.com/coreos/go-systemd/v22 v22.5.0
38 38
 	github.com/cpuguy83/tar2go v0.3.1
39 39
 	github.com/creack/pty v1.1.21
... ...
@@ -63,7 +63,7 @@ require (
63 63
 	github.com/miekg/dns v1.1.57
64 64
 	github.com/mistifyio/go-zfs/v3 v3.0.1
65 65
 	github.com/mitchellh/copystructure v1.2.0
66
-	github.com/moby/buildkit v0.15.2
66
+	github.com/moby/buildkit v0.16.0-rc1
67 67
 	github.com/moby/docker-image-spec v1.3.1
68 68
 	github.com/moby/ipvs v1.1.0
69 69
 	github.com/moby/locker v1.0.1
... ...
@@ -209,9 +209,8 @@ require (
209 209
 	go.etcd.io/etcd/server/v3 v3.5.6 // indirect
210 210
 	go.opencensus.io v0.24.0 // indirect
211 211
 	go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 // indirect
212
-	go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect
213
-	go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 // indirect
214
-	go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 // indirect
212
+	go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 // indirect
213
+	go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 // indirect
215 214
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect
216 215
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect
217 216
 	go.opentelemetry.io/otel/metric v1.21.0 // indirect
... ...
@@ -170,8 +170,8 @@ github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G
170 170
 github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
171 171
 github.com/containerd/ttrpc v1.2.5 h1:IFckT1EFQoFBMG4c3sMdT8EP3/aKfumK1msY+Ze4oLU=
172 172
 github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o=
173
-github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4=
174
-github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0=
173
+github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso=
174
+github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g=
175 175
 github.com/containernetworking/cni v1.2.2 h1:9IbP6KJQQxVKo4hhnm8r50YcVKrJbJu3Dqw+Rbt1vYk=
176 176
 github.com/containernetworking/cni v1.2.2/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M=
177 177
 github.com/containernetworking/plugins v1.4.0 h1:+w22VPYgk7nQHw7KT92lsRmuToHvb7wwSv9iTbXzzic=
... ...
@@ -474,8 +474,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
474 474
 github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
475 475
 github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
476 476
 github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs=
477
-github.com/moby/buildkit v0.15.2 h1:DnONr0AoceTWyv+plsQ7IhkSaj+6o0WyoaxYPyTFIxs=
478
-github.com/moby/buildkit v0.15.2/go.mod h1:Yis8ZMUJTHX9XhH9zVyK2igqSHV3sxi3UN0uztZocZk=
477
+github.com/moby/buildkit v0.16.0-rc1 h1:G6KBYr6T4B1ylpinYIjcNLcVkPUkuddw3daqaM9yg9A=
478
+github.com/moby/buildkit v0.16.0-rc1/go.mod h1:WLr3pMBXsAoSuZIGdGww1JPz8S8Qp+OTf0dlrPnzbDg=
479 479
 github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
480 480
 github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
481 481
 github.com/moby/ipvs v1.1.0 h1:ONN4pGaZQgAx+1Scz5RvWV4Q7Gb+mvfRh3NsPS+1XQQ=
... ...
@@ -597,8 +597,8 @@ github.com/rexray/gocsi v1.2.2/go.mod h1:X9oJHHpIVGmfKdK8e+JuCXafggk7HxL9mWQOgrs
597 597
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
598 598
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
599 599
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
600
-github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
601
-github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
600
+github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
601
+github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
602 602
 github.com/rootless-containers/rootlesskit/v2 v2.0.2 h1:wztWcDYFlk+EVAUuPJwlNMFXZIk1G14T45lv47WWGuA=
603 603
 github.com/rootless-containers/rootlesskit/v2 v2.0.2/go.mod h1:hE+ztevrQxNi+tdZyPKumzDk7VKDAf0E4seOzlOyBsY=
604 604
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
... ...
@@ -735,12 +735,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:
735 735
 go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
736 736
 go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
737 737
 go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
738
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU=
739
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU=
740
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 h1:NmnYCiR0qNufkldjVvyQfZTHSdzeHoZ41zggMsdMcLM=
741
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0/go.mod h1:UVAO61+umUsHLtYb8KXXRoHtxUkdOPkYidzW3gipRLQ=
742
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8=
743
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0=
738
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI=
739
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk=
740
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 h1:bflGWrfYyuulcdxf14V6n9+CoQcu5SAAdHmDPAJnlps=
741
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0/go.mod h1:qcTO4xHAxZLaLxPd60TdE88rxtItPHgHWqOhOGRr0as=
744 742
 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw=
745 743
 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
746 744
 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
747 745
deleted file mode 100644
... ...
@@ -1,29 +0,0 @@
1
-/*
2
-   Copyright The containerd Authors.
3
-
4
-   Licensed under the Apache License, Version 2.0 (the "License");
5
-   you may not use this file except in compliance with the License.
6
-   You may obtain a copy of the License at
7
-
8
-       http://www.apache.org/licenses/LICENSE-2.0
9
-
10
-   Unless required by applicable law or agreed to in writing, software
11
-   distributed under the License is distributed on an "AS IS" BASIS,
12
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
-   See the License for the specific language governing permissions and
14
-   limitations under the License.
15
-*/
16
-
17
-// Deprecated: use github.com/moby/sys/userns
18
-package userns
19
-
20
-import "github.com/moby/sys/userns"
21
-
22
-// RunningInUserNS detects whether we are currently running in a Linux
23
-// user namespace and memoizes the result. It returns false on non-Linux
24
-// platforms.
25
-//
26
-// Deprecated: use [userns.RunningInUserNS].
27
-func RunningInUserNS() bool {
28
-	return userns.RunningInUserNS()
29
-}
... ...
@@ -2,7 +2,7 @@
2 2
 
3 3
 [![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/typeurl)](https://pkg.go.dev/github.com/containerd/typeurl)
4 4
 [![Build Status](https://github.com/containerd/typeurl/workflows/CI/badge.svg)](https://github.com/containerd/typeurl/actions?query=workflow%3ACI)
5
-[![codecov](https://codecov.io/gh/containerd/typeurl/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/typeurl)
5
+[![codecov](https://codecov.io/gh/containerd/typeurl/branch/main/graph/badge.svg)](https://codecov.io/gh/containerd/typeurl)
6 6
 [![Go Report Card](https://goreportcard.com/badge/github.com/containerd/typeurl)](https://goreportcard.com/report/github.com/containerd/typeurl)
7 7
 
8 8
 A Go package for managing the registration, marshaling, and unmarshaling of encoded types.
... ...
@@ -13,8 +13,8 @@ This package helps when types are sent over a ttrpc/GRPC API and marshaled as a
13 13
 
14 14
 **typeurl** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
15 15
 As a containerd sub-project, you will find the:
16
- * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
17
- * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
18
- * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
16
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
17
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
18
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
19 19
 
20 20
 information in our [`containerd/project`](https://github.com/containerd/project) repository.
... ...
@@ -27,6 +27,7 @@ import (
27 27
 	gogoproto "github.com/gogo/protobuf/proto"
28 28
 	"google.golang.org/protobuf/proto"
29 29
 	"google.golang.org/protobuf/reflect/protoregistry"
30
+	"google.golang.org/protobuf/types/known/anypb"
30 31
 )
31 32
 
32 33
 var (
... ...
@@ -122,6 +123,9 @@ func TypeURL(v interface{}) (string, error) {
122 122
 
123 123
 // Is returns true if the type of the Any is the same as v.
124 124
 func Is(any Any, v interface{}) bool {
125
+	if any == nil {
126
+		return false
127
+	}
125 128
 	// call to check that v is a pointer
126 129
 	tryDereference(v)
127 130
 	url, err := TypeURL(v)
... ...
@@ -193,6 +197,31 @@ func UnmarshalToByTypeURL(typeURL string, value []byte, out interface{}) error {
193 193
 	return err
194 194
 }
195 195
 
196
+// MarshalProto converts typeurl.Any to google.golang.org/protobuf/types/known/anypb.Any.
197
+func MarshalProto(from Any) *anypb.Any {
198
+	if from == nil {
199
+		return nil
200
+	}
201
+
202
+	if pbany, ok := from.(*anypb.Any); ok {
203
+		return pbany
204
+	}
205
+
206
+	return &anypb.Any{
207
+		TypeUrl: from.GetTypeUrl(),
208
+		Value:   from.GetValue(),
209
+	}
210
+}
211
+
212
+// MarshalAnyToProto converts an arbitrary interface to google.golang.org/protobuf/types/known/anypb.Any.
213
+func MarshalAnyToProto(from interface{}) (*anypb.Any, error) {
214
+	anyType, err := MarshalAny(from)
215
+	if err != nil {
216
+		return nil, err
217
+	}
218
+	return MarshalProto(anyType), nil
219
+}
220
+
196 221
 func unmarshal(typeURL string, value []byte, v interface{}) (interface{}, error) {
197 222
 	t, err := getTypeByUrl(typeURL)
198 223
 	if err != nil {
... ...
@@ -1520,6 +1520,7 @@ type BuildHistoryRecord struct {
1520 1520
 	NumTotalSteps        int32                       `protobuf:"varint,16,opt,name=numTotalSteps,proto3" json:"numTotalSteps,omitempty"`
1521 1521
 	NumCompletedSteps    int32                       `protobuf:"varint,17,opt,name=numCompletedSteps,proto3" json:"numCompletedSteps,omitempty"`
1522 1522
 	ExternalError        *Descriptor                 `protobuf:"bytes,18,opt,name=externalError,proto3" json:"externalError,omitempty"`
1523
+	NumWarnings          int32                       `protobuf:"varint,19,opt,name=numWarnings,proto3" json:"numWarnings,omitempty"`
1523 1524
 	XXX_NoUnkeyedLiteral struct{}                    `json:"-"`
1524 1525
 	XXX_unrecognized     []byte                      `json:"-"`
1525 1526
 	XXX_sizecache        int32                       `json:"-"`
... ...
@@ -1684,6 +1685,13 @@ func (m *BuildHistoryRecord) GetExternalError() *Descriptor {
1684 1684
 	return nil
1685 1685
 }
1686 1686
 
1687
+func (m *BuildHistoryRecord) GetNumWarnings() int32 {
1688
+	if m != nil {
1689
+		return m.NumWarnings
1690
+	}
1691
+	return 0
1692
+}
1693
+
1687 1694
 type UpdateBuildHistoryRequest struct {
1688 1695
 	Ref                  string   `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"`
1689 1696
 	Pinned               bool     `protobuf:"varint,2,opt,name=Pinned,proto3" json:"Pinned,omitempty"`
... ...
@@ -2025,154 +2033,155 @@ func init() {
2025 2025
 func init() { proto.RegisterFile("control.proto", fileDescriptor_0c5120591600887d) }
2026 2026
 
2027 2027
 var fileDescriptor_0c5120591600887d = []byte{
2028
-	// 2340 bytes of a gzipped FileDescriptorProto
2028
+	// 2354 bytes of a gzipped FileDescriptorProto
2029 2029
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x19, 0x4d, 0x73, 0x1b, 0x59,
2030 2030
 	0x31, 0x23, 0xc9, 0xb2, 0xd4, 0x92, 0x1c, 0xf9, 0x25, 0x1b, 0x86, 0x21, 0x6b, 0x3b, 0xb3, 0x09,
2031 2031
 	0xb8, 0x42, 0x32, 0xf2, 0x0a, 0x42, 0xb2, 0x0e, 0x84, 0x58, 0x96, 0xd8, 0x38, 0xc4, 0x15, 0xef,
2032 2032
 	0xb3, 0xb3, 0xa1, 0xb6, 0x6a, 0xa1, 0xc6, 0xd2, 0xb3, 0x32, 0xe5, 0xd1, 0xcc, 0xf0, 0xde, 0x93,
2033
-	0x37, 0xe2, 0xc4, 0x89, 0x2a, 0x2e, 0x14, 0x17, 0x8a, 0x0b, 0x77, 0x4e, 0x9c, 0x39, 0x71, 0xe0,
2034
-	0x40, 0x55, 0x8e, 0x9c, 0xf7, 0x10, 0xa8, 0xfc, 0x00, 0x8a, 0x23, 0x47, 0xea, 0x7d, 0x8c, 0x34,
2035
-	0x92, 0x46, 0xb6, 0x9c, 0xe4, 0xa4, 0xd7, 0xef, 0x75, 0xf7, 0x74, 0xf7, 0xeb, 0xee, 0xd7, 0xdd,
2036
-	0x82, 0x4a, 0x3b, 0x0c, 0x38, 0x0d, 0x7d, 0x27, 0xa2, 0x21, 0x0f, 0x51, 0xb5, 0x17, 0x1e, 0x0e,
2037
-	0x9c, 0xc3, 0xbe, 0xe7, 0x77, 0x8e, 0x3d, 0xee, 0x9c, 0x7c, 0x6c, 0xd5, 0xbb, 0x1e, 0x7f, 0xd1,
2038
-	0x3f, 0x74, 0xda, 0x61, 0xaf, 0xd6, 0x0d, 0xbb, 0x61, 0xad, 0x1b, 0x86, 0x5d, 0x9f, 0xb8, 0x91,
2039
-	0xc7, 0xf4, 0xb2, 0x46, 0xa3, 0x76, 0x8d, 0x71, 0x97, 0xf7, 0x99, 0xe2, 0x62, 0xdd, 0x9e, 0xa4,
2040
-	0x91, 0xdb, 0x87, 0xfd, 0x23, 0x09, 0x49, 0x40, 0xae, 0x34, 0x7a, 0x2d, 0x81, 0x2e, 0xbe, 0x5f,
2041
-	0x8b, 0xbf, 0x5f, 0x73, 0x23, 0xaf, 0xc6, 0x07, 0x11, 0x61, 0xb5, 0xaf, 0x42, 0x7a, 0x4c, 0xa8,
2042
-	0x26, 0xb8, 0x35, 0x93, 0x80, 0x85, 0xfe, 0x09, 0xa1, 0xb5, 0xe8, 0xb0, 0x16, 0x46, 0xb1, 0x34,
2043
-	0x77, 0x4e, 0xc1, 0xee, 0xd3, 0x36, 0x89, 0x42, 0xdf, 0x6b, 0x0f, 0x04, 0x8d, 0x5a, 0x69, 0xb2,
2044
-	0x55, 0xad, 0xdd, 0x50, 0x76, 0xee, 0xf5, 0x08, 0xe3, 0x6e, 0x2f, 0x52, 0x08, 0xf6, 0x6f, 0x0c,
2045
-	0x28, 0xef, 0xd1, 0x7e, 0x40, 0x30, 0xf9, 0x65, 0x9f, 0x30, 0x8e, 0xae, 0x40, 0xfe, 0xc8, 0xf3,
2046
-	0x39, 0xa1, 0xa6, 0xb1, 0x96, 0x5d, 0x2f, 0x62, 0x0d, 0xa1, 0x2a, 0x64, 0x5d, 0xdf, 0x37, 0x33,
2047
-	0x6b, 0xc6, 0x7a, 0x01, 0x8b, 0x25, 0x5a, 0x87, 0xf2, 0x31, 0x21, 0x51, 0xb3, 0x4f, 0x5d, 0xee,
2048
-	0x85, 0x81, 0x99, 0x5d, 0x33, 0xd6, 0xb3, 0x8d, 0xdc, 0xab, 0xd7, 0xab, 0x06, 0x1e, 0x3b, 0x41,
2049
-	0x36, 0x14, 0x05, 0xdc, 0x18, 0x70, 0xc2, 0xcc, 0x5c, 0x02, 0x6d, 0xb4, 0x6d, 0xdf, 0x84, 0x6a,
2050
-	0xd3, 0x63, 0xc7, 0xcf, 0x98, 0xdb, 0x3d, 0x4b, 0x16, 0xfb, 0x31, 0x2c, 0x27, 0x70, 0x59, 0x14,
2051
-	0x06, 0x8c, 0xa0, 0x3b, 0x90, 0xa7, 0xa4, 0x1d, 0xd2, 0x8e, 0x44, 0x2e, 0xd5, 0x3f, 0x74, 0x26,
2052
-	0xdd, 0xc0, 0xd1, 0x04, 0x02, 0x09, 0x6b, 0x64, 0xfb, 0x8f, 0x59, 0x28, 0x25, 0xf6, 0xd1, 0x12,
2053
-	0x64, 0x76, 0x9a, 0xa6, 0xb1, 0x66, 0xac, 0x17, 0x71, 0x66, 0xa7, 0x89, 0x4c, 0x58, 0xdc, 0xed,
2054
-	0x73, 0xf7, 0xd0, 0x27, 0x5a, 0xf7, 0x18, 0x44, 0x97, 0x61, 0x61, 0x27, 0x78, 0xc6, 0x88, 0x54,
2055
-	0xbc, 0x80, 0x15, 0x80, 0x10, 0xe4, 0xf6, 0xbd, 0x5f, 0x11, 0xa5, 0x26, 0x96, 0x6b, 0x64, 0x41,
2056
-	0x7e, 0xcf, 0xa5, 0x24, 0xe0, 0xe6, 0x82, 0xe0, 0xdb, 0xc8, 0x98, 0x06, 0xd6, 0x3b, 0xa8, 0x01,
2057
-	0xc5, 0x6d, 0x4a, 0x5c, 0x4e, 0x3a, 0x5b, 0xdc, 0xcc, 0xaf, 0x19, 0xeb, 0xa5, 0xba, 0xe5, 0xa8,
2058
-	0x5b, 0x73, 0xe2, 0x5b, 0x73, 0x0e, 0xe2, 0x5b, 0x6b, 0x14, 0x5e, 0xbd, 0x5e, 0xbd, 0xf0, 0xfb,
2059
-	0x7f, 0x09, 0xdb, 0x0d, 0xc9, 0xd0, 0x43, 0x80, 0x27, 0x2e, 0xe3, 0xcf, 0x98, 0x64, 0xb2, 0x78,
2060
-	0x26, 0x93, 0x9c, 0x64, 0x90, 0xa0, 0x41, 0x2b, 0x00, 0xd2, 0x08, 0xdb, 0x61, 0x3f, 0xe0, 0x66,
2061
-	0x41, 0xca, 0x9e, 0xd8, 0x41, 0x6b, 0x50, 0x6a, 0x12, 0xd6, 0xa6, 0x5e, 0x24, 0xaf, 0xba, 0x28,
2062
-	0xcd, 0x93, 0xdc, 0x12, 0x1c, 0x94, 0x05, 0x0f, 0x06, 0x11, 0x31, 0x41, 0x22, 0x24, 0x76, 0xc4,
2063
-	0x5d, 0xee, 0xbf, 0x70, 0x29, 0xe9, 0x98, 0x25, 0x69, 0x2e, 0x0d, 0x09, 0xfb, 0x2a, 0x4b, 0x30,
2064
-	0xb3, 0x2c, 0x2f, 0x39, 0x06, 0xed, 0x5f, 0x17, 0xa0, 0xbc, 0x2f, 0x42, 0x21, 0x76, 0x87, 0x2a,
2065
-	0x64, 0x31, 0x39, 0xd2, 0x77, 0x23, 0x96, 0xc8, 0x01, 0x68, 0x92, 0x23, 0x2f, 0xf0, 0xa4, 0x54,
2066
-	0x19, 0xa9, 0xf8, 0x92, 0x13, 0x1d, 0x3a, 0xa3, 0x5d, 0x9c, 0xc0, 0x40, 0x0e, 0xa0, 0xd6, 0xcb,
2067
-	0x28, 0xa4, 0x9c, 0xd0, 0x26, 0x89, 0x28, 0x69, 0x0b, 0x03, 0xca, 0xfb, 0x2b, 0xe2, 0x94, 0x13,
2068
-	0xd4, 0x87, 0x6f, 0xc4, 0xbb, 0x5b, 0x9c, 0x53, 0x96, 0x20, 0xca, 0x49, 0x27, 0xbb, 0x3f, 0xed,
2069
-	0x64, 0x49, 0x91, 0x9d, 0x19, 0xd4, 0xad, 0x80, 0xd3, 0x01, 0x9e, 0xc5, 0x5b, 0xd8, 0x64, 0x9f,
2070
-	0x30, 0x26, 0x74, 0x92, 0x0e, 0x83, 0x63, 0x10, 0x59, 0x50, 0xf8, 0x09, 0x0d, 0x03, 0x4e, 0x82,
2071
-	0x8e, 0x74, 0x96, 0x22, 0x1e, 0xc2, 0xe8, 0x39, 0x54, 0xe2, 0xb5, 0x64, 0x68, 0x2e, 0x4a, 0x11,
2072
-	0x3f, 0x3e, 0x43, 0xc4, 0x31, 0x1a, 0x25, 0xd8, 0x38, 0x1f, 0xb4, 0x09, 0x0b, 0xdb, 0x6e, 0xfb,
2073
-	0x05, 0x91, 0x7e, 0x51, 0xaa, 0xaf, 0x4c, 0x33, 0x94, 0xc7, 0x4f, 0xa5, 0x23, 0x30, 0x19, 0xda,
2074
-	0x17, 0xb0, 0x22, 0x41, 0x3f, 0x87, 0x72, 0x2b, 0xe0, 0x1e, 0xf7, 0x49, 0x4f, 0xde, 0x71, 0x51,
2075
-	0xdc, 0x71, 0x63, 0xf3, 0xeb, 0xd7, 0xab, 0x3f, 0x98, 0x99, 0xd1, 0xfa, 0xdc, 0xf3, 0x6b, 0x24,
2076
-	0x41, 0xe5, 0x24, 0x58, 0xe0, 0x31, 0x7e, 0xe8, 0x0b, 0x58, 0x8a, 0x85, 0xdd, 0x09, 0xa2, 0x3e,
2077
-	0x67, 0x26, 0x48, 0xad, 0xeb, 0x73, 0x6a, 0xad, 0x88, 0x94, 0xda, 0x13, 0x9c, 0x84, 0xb1, 0x77,
2078
-	0x02, 0x4e, 0x68, 0xe0, 0xfa, 0xda, 0x69, 0x87, 0x30, 0xda, 0x11, 0xbe, 0x29, 0x12, 0xef, 0x9e,
2079
-	0x4c, 0xb7, 0x66, 0x59, 0x9a, 0xe6, 0xc6, 0xf4, 0x57, 0x93, 0xe9, 0xd9, 0x51, 0xc8, 0x78, 0x8c,
2080
-	0x14, 0xdd, 0x83, 0x62, 0xec, 0x08, 0xcc, 0xac, 0x48, 0xe9, 0xad, 0x69, 0x3e, 0x31, 0x0a, 0x1e,
2081
-	0x21, 0x5b, 0x8f, 0xe1, 0xea, 0x69, 0x0e, 0x26, 0x02, 0xe6, 0x98, 0x0c, 0xe2, 0x80, 0x39, 0x26,
2082
-	0x03, 0x91, 0xb3, 0x4e, 0x5c, 0xbf, 0xaf, 0x72, 0x59, 0x11, 0x2b, 0x60, 0x33, 0x73, 0xcf, 0xb0,
2083
-	0x1e, 0x02, 0x9a, 0xf6, 0x84, 0x73, 0x71, 0xf8, 0x0c, 0x2e, 0xa5, 0x58, 0x35, 0x85, 0xc5, 0xf5,
2084
-	0x24, 0x8b, 0xe9, 0x80, 0x1d, 0xb1, 0xb4, 0xff, 0x92, 0x85, 0x72, 0xd2, 0xb7, 0xd0, 0x06, 0x5c,
2085
-	0x52, 0x1a, 0x63, 0x72, 0x94, 0x08, 0x46, 0xc5, 0x3c, 0xed, 0x08, 0xd5, 0xe1, 0xf2, 0x4e, 0x4f,
2086
-	0x6f, 0x27, 0xe3, 0x37, 0x23, 0x93, 0x4d, 0xea, 0x19, 0x0a, 0xe1, 0x03, 0xc5, 0x6a, 0x32, 0xe8,
2087
-	0xb3, 0xf2, 0x76, 0x3e, 0x39, 0x3d, 0x00, 0x9c, 0x54, 0x5a, 0xe5, 0x62, 0xe9, 0x7c, 0xd1, 0x8f,
2088
-	0x60, 0x51, 0x1d, 0x30, 0x9d, 0x57, 0x3e, 0x3a, 0xfd, 0x13, 0x8a, 0x59, 0x4c, 0x23, 0xc8, 0x95,
2089
-	0x1e, 0xcc, 0x5c, 0x38, 0x07, 0xb9, 0xa6, 0xb1, 0x1e, 0x81, 0x35, 0x5b, 0xe4, 0xf3, 0xb8, 0x80,
2090
-	0xfd, 0x67, 0x03, 0x96, 0xa7, 0x3e, 0x24, 0x9e, 0x44, 0xf9, 0x28, 0x28, 0x16, 0x72, 0x8d, 0x9a,
2091
-	0xb0, 0xa0, 0x92, 0x54, 0x46, 0x0a, 0xec, 0xcc, 0x21, 0xb0, 0x93, 0xc8, 0x50, 0x8a, 0xd8, 0xba,
2092
-	0x07, 0xf0, 0x76, 0xce, 0x6a, 0xff, 0xd5, 0x80, 0x8a, 0x4e, 0x08, 0xba, 0x7e, 0x70, 0xa1, 0x3a,
2093
-	0x8c, 0x31, 0xbd, 0xa7, 0x2b, 0x89, 0x3b, 0x33, 0x73, 0x89, 0x42, 0x73, 0x26, 0xe9, 0x94, 0x8c,
2094
-	0x53, 0xec, 0xac, 0xed, 0xd8, 0xaf, 0x26, 0x50, 0xcf, 0x25, 0xf9, 0x35, 0xa8, 0xec, 0xcb, 0x3a,
2095
-	0x75, 0xe6, 0xb3, 0x68, 0xff, 0xd7, 0x80, 0xa5, 0x18, 0x47, 0x6b, 0xf7, 0x7d, 0x28, 0x9c, 0x10,
2096
-	0xca, 0xc9, 0x4b, 0xc2, 0xb4, 0x56, 0xe6, 0xb4, 0x56, 0x9f, 0x4b, 0x0c, 0x3c, 0xc4, 0x44, 0x9b,
2097
-	0x50, 0x50, 0x35, 0x31, 0x89, 0x2f, 0x6a, 0x65, 0x16, 0x95, 0xfe, 0xde, 0x10, 0x1f, 0xd5, 0x20,
2098
-	0xe7, 0x87, 0x5d, 0xa6, 0x63, 0xe6, 0x5b, 0xb3, 0xe8, 0x9e, 0x84, 0x5d, 0x2c, 0x11, 0xd1, 0x7d,
2099
-	0x28, 0x7c, 0xe5, 0xd2, 0xc0, 0x0b, 0xba, 0x71, 0x14, 0xac, 0xce, 0x22, 0x7a, 0xae, 0xf0, 0xf0,
2100
-	0x90, 0x40, 0x94, 0x71, 0x79, 0x75, 0x86, 0x1e, 0x43, 0xbe, 0xe3, 0x75, 0x09, 0xe3, 0xca, 0x24,
2101
-	0x8d, 0xba, 0x78, 0x8f, 0xbe, 0x7e, 0xbd, 0x7a, 0x33, 0xf1, 0xe0, 0x84, 0x11, 0x09, 0x44, 0xd3,
2102
-	0xe0, 0x7a, 0x01, 0xa1, 0xa2, 0x07, 0xb8, 0xad, 0x48, 0x9c, 0xa6, 0xfc, 0xc1, 0x9a, 0x83, 0xe0,
2103
-	0xe5, 0xa9, 0x67, 0x45, 0xe6, 0x8b, 0xb7, 0xe3, 0xa5, 0x38, 0x88, 0x30, 0x08, 0xdc, 0x1e, 0xd1,
2104
-	0xe5, 0x86, 0x5c, 0x8b, 0xaa, 0xa8, 0x2d, 0xfc, 0xbc, 0x23, 0xeb, 0xc5, 0x02, 0xd6, 0x10, 0xda,
2105
-	0x84, 0x45, 0xc6, 0x5d, 0x2a, 0x72, 0xce, 0xc2, 0x9c, 0xe5, 0x5c, 0x4c, 0x80, 0x1e, 0x40, 0xb1,
2106
-	0x1d, 0xf6, 0x22, 0x9f, 0x08, 0xea, 0xfc, 0x9c, 0xd4, 0x23, 0x12, 0xe1, 0x7a, 0x84, 0xd2, 0x90,
2107
-	0xca, 0x42, 0xb2, 0x88, 0x15, 0x80, 0xee, 0x42, 0x25, 0xa2, 0x61, 0x97, 0x12, 0xc6, 0x3e, 0xa5,
2108
-	0x61, 0x3f, 0xd2, 0xc5, 0xc0, 0xb2, 0x48, 0xde, 0x7b, 0xc9, 0x03, 0x3c, 0x8e, 0x67, 0xff, 0x27,
2109
-	0x03, 0xe5, 0xa4, 0x8b, 0x4c, 0x55, 0xd8, 0x8f, 0x21, 0xaf, 0x1c, 0x4e, 0xf9, 0xfa, 0xdb, 0xd9,
2110
-	0x58, 0x71, 0x48, 0xb5, 0xb1, 0x09, 0x8b, 0xed, 0x3e, 0x95, 0xe5, 0xb7, 0x2a, 0xca, 0x63, 0x50,
2111
-	0x68, 0xca, 0x43, 0xee, 0xfa, 0xd2, 0xc6, 0x59, 0xac, 0x00, 0x51, 0x91, 0x0f, 0xbb, 0xa4, 0xf3,
2112
-	0x55, 0xe4, 0x43, 0xb2, 0xe4, 0xfd, 0x2d, 0xbe, 0xd3, 0xfd, 0x15, 0xce, 0x7d, 0x7f, 0xf6, 0x3f,
2113
-	0x0c, 0x28, 0x0e, 0x63, 0x2b, 0x61, 0x5d, 0xe3, 0x9d, 0xad, 0x3b, 0x66, 0x99, 0xcc, 0xdb, 0x59,
2114
-	0xe6, 0x0a, 0xe4, 0x19, 0xa7, 0xc4, 0xed, 0xa9, 0x7e, 0x11, 0x6b, 0x48, 0x64, 0xb1, 0x1e, 0xeb,
2115
-	0xca, 0x1b, 0x2a, 0x63, 0xb1, 0xb4, 0xff, 0x67, 0x40, 0x65, 0x2c, 0xdc, 0xdf, 0xab, 0x2e, 0x97,
2116
-	0x61, 0xc1, 0x27, 0x27, 0x44, 0x75, 0xb4, 0x59, 0xac, 0x00, 0xb1, 0xcb, 0x5e, 0x84, 0x94, 0x4b,
2117
-	0xe1, 0xca, 0x58, 0x01, 0x42, 0xe6, 0x0e, 0xe1, 0xae, 0xe7, 0xcb, 0xbc, 0x54, 0xc6, 0x1a, 0x12,
2118
-	0x32, 0xf7, 0xa9, 0xaf, 0x6b, 0x74, 0xb1, 0x44, 0x36, 0xe4, 0xbc, 0xe0, 0x28, 0xd4, 0x6e, 0x23,
2119
-	0x2b, 0x1b, 0x55, 0xeb, 0xed, 0x04, 0x47, 0x21, 0x96, 0x67, 0xe8, 0x1a, 0xe4, 0xa9, 0x1b, 0x74,
2120
-	0x49, 0x5c, 0xa0, 0x17, 0x05, 0x16, 0x16, 0x3b, 0x58, 0x1f, 0xd8, 0x36, 0x94, 0x65, 0x57, 0xbc,
2121
-	0x4b, 0x98, 0xe8, 0xc1, 0x84, 0x5b, 0x77, 0x5c, 0xee, 0x4a, 0xb5, 0xcb, 0x58, 0xae, 0xed, 0x5b,
2122
-	0x80, 0x9e, 0x78, 0x8c, 0x3f, 0x97, 0x33, 0x05, 0x76, 0x56, 0xcb, 0xbc, 0x0f, 0x97, 0xc6, 0xb0,
2123
-	0xf5, 0xb3, 0xf0, 0xc3, 0x89, 0xa6, 0xf9, 0xfa, 0x74, 0xc6, 0x95, 0xa3, 0x0b, 0x47, 0x11, 0x4e,
2124
-	0xf4, 0xce, 0x15, 0x28, 0x49, 0xbd, 0xd4, 0xb7, 0x6d, 0x17, 0xca, 0x0a, 0xd4, 0xcc, 0x3f, 0x83,
2125
-	0x8b, 0x31, 0xa3, 0xcf, 0x09, 0x95, 0xed, 0x8c, 0x21, 0xed, 0xf2, 0x9d, 0x59, 0x5f, 0x69, 0x8c,
2126
-	0xa3, 0xe3, 0x49, 0x7a, 0x9b, 0xc0, 0x25, 0x89, 0xf3, 0xc8, 0x63, 0x3c, 0xa4, 0x83, 0x58, 0xeb,
2127
-	0x15, 0x80, 0xad, 0x36, 0xf7, 0x4e, 0xc8, 0xd3, 0xc0, 0x57, 0xcf, 0x68, 0x01, 0x27, 0x76, 0xe2,
2128
-	0x27, 0x32, 0x33, 0xea, 0x1c, 0xaf, 0x42, 0xb1, 0xe5, 0x52, 0x7f, 0xd0, 0x7a, 0xe9, 0x71, 0xdd,
2129
-	0xc0, 0x8f, 0x36, 0xec, 0xdf, 0x19, 0xb0, 0x9c, 0xfc, 0x4e, 0xeb, 0x44, 0xa4, 0x8b, 0xfb, 0x90,
2130
-	0xe3, 0x71, 0x1d, 0xb3, 0x94, 0xa6, 0xc4, 0x14, 0x89, 0x28, 0x75, 0xb0, 0x24, 0x4a, 0x58, 0x5a,
2131
-	0x05, 0xce, 0xf5, 0xd3, 0xc9, 0x27, 0x2c, 0xfd, 0xb7, 0x22, 0xa0, 0xe9, 0xe3, 0x94, 0x8e, 0x38,
2132
-	0xd9, 0x20, 0x66, 0x26, 0x1a, 0xc4, 0x2f, 0x27, 0x1b, 0x44, 0xf5, 0x34, 0xdf, 0x9d, 0x47, 0x92,
2133
-	0x39, 0xda, 0xc4, 0xb1, 0x3e, 0x26, 0x77, 0x8e, 0x3e, 0x06, 0xad, 0xc7, 0x2f, 0x8e, 0x7a, 0xeb,
2134
-	0x50, 0x9c, 0x53, 0x68, 0xd4, 0x76, 0x74, 0x5d, 0xa1, 0x5f, 0xa1, 0x07, 0xe7, 0x9b, 0x96, 0xe4,
2135
-	0x26, 0x27, 0x25, 0x0d, 0x28, 0x6d, 0xc7, 0x89, 0xf2, 0x1c, 0xa3, 0x92, 0x24, 0x11, 0xda, 0xd0,
2136
-	0x85, 0x8d, 0x4a, 0xcd, 0x57, 0xa7, 0x55, 0x8c, 0xc7, 0x22, 0x21, 0xd5, 0x95, 0xcd, 0x51, 0x4a,
2137
-	0x69, 0x59, 0x94, 0x06, 0xda, 0x9c, 0xcb, 0xf6, 0x73, 0xd6, 0x97, 0xe8, 0x13, 0xc8, 0x63, 0xc2,
2138
-	0xfa, 0x3e, 0x97, 0xf3, 0x97, 0x52, 0xfd, 0xda, 0x0c, 0xee, 0x0a, 0x49, 0xc6, 0xaa, 0x26, 0x40,
2139
-	0x3f, 0x85, 0x45, 0xb5, 0x62, 0x66, 0x69, 0xd6, 0xd8, 0x20, 0x45, 0x32, 0x4d, 0xa3, 0x1b, 0x0a,
2140
-	0x0d, 0x89, 0x70, 0xfc, 0x94, 0x04, 0x44, 0xcf, 0x05, 0x45, 0x6b, 0xbc, 0x80, 0x13, 0x3b, 0xa8,
2141
-	0x0e, 0x0b, 0x9c, 0xba, 0x6d, 0x62, 0x56, 0xe6, 0x30, 0xa1, 0x42, 0x15, 0x89, 0x2d, 0xf2, 0x82,
2142
-	0x80, 0x74, 0xcc, 0x25, 0x55, 0x29, 0x29, 0x08, 0x7d, 0x1b, 0x96, 0x82, 0x7e, 0x4f, 0x36, 0x0b,
2143
-	0x9d, 0x7d, 0x4e, 0x22, 0x66, 0x5e, 0x94, 0xdf, 0x9b, 0xd8, 0x45, 0xd7, 0xa1, 0x12, 0xf4, 0x7b,
2144
-	0x07, 0xe2, 0x85, 0x57, 0x68, 0x55, 0x89, 0x36, 0xbe, 0x89, 0x6e, 0xc1, 0xb2, 0xa0, 0x8b, 0x6f,
2145
-	0x5b, 0x61, 0x2e, 0x4b, 0xcc, 0xe9, 0x03, 0xd4, 0x80, 0x0a, 0x79, 0xa9, 0x06, 0x02, 0x2d, 0xe9,
2146
-	0xbf, 0x68, 0x0e, 0x7d, 0xc6, 0x49, 0xde, 0x43, 0xdf, 0xfd, 0x3e, 0xba, 0x0a, 0xeb, 0x4b, 0x28,
2147
-	0x27, 0xef, 0x32, 0x85, 0xf6, 0xee, 0x78, 0xd7, 0x3e, 0x87, 0x6f, 0x25, 0x9a, 0x96, 0x01, 0x7c,
2148
-	0xf3, 0x59, 0xd4, 0x71, 0x39, 0x49, 0xcb, 0xde, 0xd3, 0x59, 0xec, 0x0a, 0xe4, 0xf7, 0xd4, 0x65,
2149
-	0xab, 0x99, 0xab, 0x86, 0xc4, 0x7e, 0x93, 0x88, 0x0b, 0xd0, 0x29, 0x5b, 0x43, 0x32, 0xeb, 0x79,
2150
-	0x81, 0xeb, 0xc7, 0x83, 0xd7, 0x02, 0x1e, 0xc2, 0xf6, 0x55, 0xb0, 0xd2, 0x3e, 0xad, 0x0c, 0x65,
2151
-	0xff, 0x29, 0x03, 0x30, 0xba, 0x1c, 0xf4, 0x21, 0x40, 0x8f, 0x74, 0x3c, 0xf7, 0x17, 0x7c, 0xd4,
2152
-	0xb0, 0x16, 0xe5, 0x8e, 0xec, 0x5a, 0x47, 0xad, 0x45, 0xe6, 0x9d, 0x5b, 0x0b, 0x04, 0x39, 0x26,
2153
-	0xe4, 0x55, 0x65, 0x90, 0x5c, 0xa3, 0xa7, 0x50, 0x72, 0x83, 0x20, 0xe4, 0x32, 0x4c, 0xe2, 0x66,
2154
-	0xfe, 0xf6, 0x69, 0xee, 0xe4, 0x6c, 0x8d, 0xf0, 0x55, 0x14, 0x26, 0x39, 0x58, 0x0f, 0xa0, 0x3a,
2155
-	0x89, 0x70, 0xae, 0x66, 0xf3, 0xef, 0x19, 0xb8, 0x38, 0x71, 0xad, 0xe8, 0x11, 0x54, 0x15, 0x34,
2156
-	0x31, 0x80, 0x39, 0xcb, 0xf1, 0xa7, 0xa8, 0xd0, 0x43, 0x28, 0x6f, 0x71, 0x2e, 0x32, 0xad, 0xd2,
2157
-	0x57, 0xb5, 0x98, 0xa7, 0x73, 0x19, 0xa3, 0x40, 0x8f, 0x46, 0x69, 0x2b, 0x3b, 0x6b, 0x90, 0x30,
2158
-	0x21, 0x7f, 0x7a, 0xce, 0xb2, 0x7e, 0x36, 0x3b, 0x00, 0xb2, 0xca, 0x4a, 0xf5, 0xf1, 0x00, 0x38,
2159
-	0x23, 0x6b, 0x8d, 0x6c, 0xf8, 0x07, 0x03, 0x0a, 0x71, 0x80, 0xa6, 0xce, 0x42, 0xee, 0x8f, 0xcf,
2160
-	0x42, 0x6e, 0xcc, 0x7e, 0x34, 0xdf, 0xe7, 0x08, 0xe4, 0xe6, 0x8f, 0xe1, 0x83, 0xd4, 0x82, 0x05,
2161
-	0x95, 0x60, 0x71, 0xff, 0x60, 0x0b, 0x1f, 0xb4, 0x9a, 0xd5, 0x0b, 0xa8, 0x0c, 0x85, 0xed, 0xa7,
2162
-	0xbb, 0x7b, 0x4f, 0x5a, 0x07, 0xad, 0xaa, 0x21, 0x8e, 0x9a, 0x2d, 0xb1, 0x6e, 0x56, 0x33, 0xf5,
2163
-	0xdf, 0xe6, 0x61, 0x71, 0x5b, 0xfd, 0xf3, 0x86, 0x0e, 0xa0, 0x38, 0xfc, 0x4b, 0x06, 0xd9, 0x29,
2164
-	0xa6, 0x99, 0xf8, 0x6f, 0xc7, 0xfa, 0xe8, 0x54, 0x1c, 0xfd, 0xa0, 0x3d, 0x82, 0x05, 0xf9, 0xe7,
2165
-	0x14, 0x4a, 0x19, 0x3b, 0x24, 0xff, 0xb5, 0xb2, 0x4e, 0xff, 0xb3, 0x67, 0xc3, 0x10, 0x9c, 0xe4,
2166
-	0xcc, 0x26, 0x8d, 0x53, 0x72, 0x30, 0x6c, 0xad, 0x9e, 0x31, 0xec, 0x41, 0xbb, 0x90, 0xd7, 0x8d,
2167
-	0x6c, 0x1a, 0x6a, 0x72, 0x32, 0x63, 0xad, 0xcd, 0x46, 0x50, 0xcc, 0x36, 0x0c, 0xb4, 0x3b, 0x9c,
2168
-	0xf5, 0xa7, 0x89, 0x96, 0xec, 0x02, 0xac, 0x33, 0xce, 0xd7, 0x8d, 0x0d, 0x03, 0x7d, 0x01, 0xa5,
2169
-	0x44, 0x9d, 0x8f, 0x52, 0xaa, 0xcc, 0xe9, 0xa6, 0xc1, 0xba, 0x71, 0x06, 0x96, 0xd6, 0xbc, 0x05,
2170
-	0x39, 0x99, 0x00, 0x52, 0x8c, 0x9d, 0x68, 0x03, 0xd2, 0xc4, 0x1c, 0x6b, 0x0b, 0x0e, 0x55, 0xe3,
2171
-	0x42, 0x82, 0xa4, 0xf7, 0xa1, 0x1b, 0x67, 0xd5, 0x1b, 0x33, 0xdd, 0x66, 0xca, 0x89, 0x37, 0x0c,
2172
-	0x14, 0x02, 0x9a, 0x4e, 0xfa, 0xe8, 0xbb, 0x29, 0x5e, 0x32, 0xeb, 0x55, 0xb2, 0x6e, 0xcd, 0x87,
2173
-	0xac, 0x94, 0x6a, 0x94, 0x5f, 0xbd, 0x59, 0x31, 0xfe, 0xf9, 0x66, 0xc5, 0xf8, 0xf7, 0x9b, 0x15,
2174
-	0xe3, 0x30, 0x2f, 0x2b, 0xc9, 0xef, 0xfd, 0x3f, 0x00, 0x00, 0xff, 0xff, 0x12, 0xae, 0x41, 0x43,
2175
-	0x99, 0x1e, 0x00, 0x00,
2033
+	0x37, 0xe2, 0xc4, 0x89, 0x2a, 0x2e, 0x14, 0x17, 0x8a, 0x0b, 0x77, 0x4e, 0x9c, 0x39, 0x73, 0xa0,
2034
+	0x2a, 0x47, 0xce, 0x7b, 0xc8, 0x52, 0xf9, 0x01, 0x14, 0x47, 0x8e, 0xd4, 0xfb, 0x18, 0x69, 0x24,
2035
+	0x8d, 0x6c, 0x39, 0xc9, 0x49, 0xaf, 0xdf, 0xeb, 0xee, 0xe9, 0xee, 0xd7, 0xdd, 0xaf, 0xbb, 0x05,
2036
+	0x95, 0x76, 0x18, 0x70, 0x1a, 0xfa, 0x4e, 0x44, 0x43, 0x1e, 0xa2, 0x6a, 0x2f, 0x3c, 0x1c, 0x38,
2037
+	0x87, 0x7d, 0xcf, 0xef, 0x1c, 0x7b, 0xdc, 0x39, 0xf9, 0xd8, 0xaa, 0x77, 0x3d, 0xfe, 0xa2, 0x7f,
2038
+	0xe8, 0xb4, 0xc3, 0x5e, 0xad, 0x1b, 0x76, 0xc3, 0x5a, 0x37, 0x0c, 0xbb, 0x3e, 0x71, 0x23, 0x8f,
2039
+	0xe9, 0x65, 0x8d, 0x46, 0xed, 0x1a, 0xe3, 0x2e, 0xef, 0x33, 0xc5, 0xc5, 0xba, 0x3d, 0x49, 0x23,
2040
+	0xb7, 0x0f, 0xfb, 0x47, 0x12, 0x92, 0x80, 0x5c, 0x69, 0xf4, 0x5a, 0x02, 0x5d, 0x7c, 0xbf, 0x16,
2041
+	0x7f, 0xbf, 0xe6, 0x46, 0x5e, 0x8d, 0x0f, 0x22, 0xc2, 0x6a, 0x5f, 0x85, 0xf4, 0x98, 0x50, 0x4d,
2042
+	0x70, 0x6b, 0x26, 0x01, 0x0b, 0xfd, 0x13, 0x42, 0x6b, 0xd1, 0x61, 0x2d, 0x8c, 0x62, 0x69, 0xee,
2043
+	0x9c, 0x82, 0xdd, 0xa7, 0x6d, 0x12, 0x85, 0xbe, 0xd7, 0x1e, 0x08, 0x1a, 0xb5, 0xd2, 0x64, 0xab,
2044
+	0x5a, 0xbb, 0xa1, 0xec, 0xdc, 0xeb, 0x11, 0xc6, 0xdd, 0x5e, 0xa4, 0x10, 0xec, 0xdf, 0x19, 0x50,
2045
+	0xde, 0xa3, 0xfd, 0x80, 0x60, 0xf2, 0xeb, 0x3e, 0x61, 0x1c, 0x5d, 0x81, 0xfc, 0x91, 0xe7, 0x73,
2046
+	0x42, 0x4d, 0x63, 0x2d, 0xbb, 0x5e, 0xc4, 0x1a, 0x42, 0x55, 0xc8, 0xba, 0xbe, 0x6f, 0x66, 0xd6,
2047
+	0x8c, 0xf5, 0x02, 0x16, 0x4b, 0xb4, 0x0e, 0xe5, 0x63, 0x42, 0xa2, 0x66, 0x9f, 0xba, 0xdc, 0x0b,
2048
+	0x03, 0x33, 0xbb, 0x66, 0xac, 0x67, 0x1b, 0xb9, 0x57, 0xaf, 0x57, 0x0d, 0x3c, 0x76, 0x82, 0x6c,
2049
+	0x28, 0x0a, 0xb8, 0x31, 0xe0, 0x84, 0x99, 0xb9, 0x04, 0xda, 0x68, 0xdb, 0xbe, 0x09, 0xd5, 0xa6,
2050
+	0xc7, 0x8e, 0x9f, 0x31, 0xb7, 0x7b, 0x96, 0x2c, 0xf6, 0x63, 0x58, 0x4e, 0xe0, 0xb2, 0x28, 0x0c,
2051
+	0x18, 0x41, 0x77, 0x20, 0x4f, 0x49, 0x3b, 0xa4, 0x1d, 0x89, 0x5c, 0xaa, 0x7f, 0xe8, 0x4c, 0xba,
2052
+	0x81, 0xa3, 0x09, 0x04, 0x12, 0xd6, 0xc8, 0xf6, 0x9f, 0xb3, 0x50, 0x4a, 0xec, 0xa3, 0x25, 0xc8,
2053
+	0xec, 0x34, 0x4d, 0x63, 0xcd, 0x58, 0x2f, 0xe2, 0xcc, 0x4e, 0x13, 0x99, 0xb0, 0xb8, 0xdb, 0xe7,
2054
+	0xee, 0xa1, 0x4f, 0xb4, 0xee, 0x31, 0x88, 0x2e, 0xc3, 0xc2, 0x4e, 0xf0, 0x8c, 0x11, 0xa9, 0x78,
2055
+	0x01, 0x2b, 0x00, 0x21, 0xc8, 0xed, 0x7b, 0xbf, 0x21, 0x4a, 0x4d, 0x2c, 0xd7, 0xc8, 0x82, 0xfc,
2056
+	0x9e, 0x4b, 0x49, 0xc0, 0xcd, 0x05, 0xc1, 0xb7, 0x91, 0x31, 0x0d, 0xac, 0x77, 0x50, 0x03, 0x8a,
2057
+	0xdb, 0x94, 0xb8, 0x9c, 0x74, 0xb6, 0xb8, 0x99, 0x5f, 0x33, 0xd6, 0x4b, 0x75, 0xcb, 0x51, 0xb7,
2058
+	0xe6, 0xc4, 0xb7, 0xe6, 0x1c, 0xc4, 0xb7, 0xd6, 0x28, 0xbc, 0x7a, 0xbd, 0x7a, 0xe1, 0x8f, 0xdf,
2059
+	0x08, 0xdb, 0x0d, 0xc9, 0xd0, 0x43, 0x80, 0x27, 0x2e, 0xe3, 0xcf, 0x98, 0x64, 0xb2, 0x78, 0x26,
2060
+	0x93, 0x9c, 0x64, 0x90, 0xa0, 0x41, 0x2b, 0x00, 0xd2, 0x08, 0xdb, 0x61, 0x3f, 0xe0, 0x66, 0x41,
2061
+	0xca, 0x9e, 0xd8, 0x41, 0x6b, 0x50, 0x6a, 0x12, 0xd6, 0xa6, 0x5e, 0x24, 0xaf, 0xba, 0x28, 0xcd,
2062
+	0x93, 0xdc, 0x12, 0x1c, 0x94, 0x05, 0x0f, 0x06, 0x11, 0x31, 0x41, 0x22, 0x24, 0x76, 0xc4, 0x5d,
2063
+	0xee, 0xbf, 0x70, 0x29, 0xe9, 0x98, 0x25, 0x69, 0x2e, 0x0d, 0x09, 0xfb, 0x2a, 0x4b, 0x30, 0xb3,
2064
+	0x2c, 0x2f, 0x39, 0x06, 0xed, 0xdf, 0x16, 0xa0, 0xbc, 0x2f, 0x42, 0x21, 0x76, 0x87, 0x2a, 0x64,
2065
+	0x31, 0x39, 0xd2, 0x77, 0x23, 0x96, 0xc8, 0x01, 0x68, 0x92, 0x23, 0x2f, 0xf0, 0xa4, 0x54, 0x19,
2066
+	0xa9, 0xf8, 0x92, 0x13, 0x1d, 0x3a, 0xa3, 0x5d, 0x9c, 0xc0, 0x40, 0x0e, 0xa0, 0xd6, 0xcb, 0x28,
2067
+	0xa4, 0x9c, 0xd0, 0x26, 0x89, 0x28, 0x69, 0x0b, 0x03, 0xca, 0xfb, 0x2b, 0xe2, 0x94, 0x13, 0xd4,
2068
+	0x87, 0x6f, 0xc5, 0xbb, 0x5b, 0x9c, 0x53, 0x96, 0x20, 0xca, 0x49, 0x27, 0xbb, 0x3f, 0xed, 0x64,
2069
+	0x49, 0x91, 0x9d, 0x19, 0xd4, 0xad, 0x80, 0xd3, 0x01, 0x9e, 0xc5, 0x5b, 0xd8, 0x64, 0x9f, 0x30,
2070
+	0x26, 0x74, 0x92, 0x0e, 0x83, 0x63, 0x10, 0x59, 0x50, 0xf8, 0x19, 0x0d, 0x03, 0x4e, 0x82, 0x8e,
2071
+	0x74, 0x96, 0x22, 0x1e, 0xc2, 0xe8, 0x39, 0x54, 0xe2, 0xb5, 0x64, 0x68, 0x2e, 0x4a, 0x11, 0x3f,
2072
+	0x3e, 0x43, 0xc4, 0x31, 0x1a, 0x25, 0xd8, 0x38, 0x1f, 0xb4, 0x09, 0x0b, 0xdb, 0x6e, 0xfb, 0x05,
2073
+	0x91, 0x7e, 0x51, 0xaa, 0xaf, 0x4c, 0x33, 0x94, 0xc7, 0x4f, 0xa5, 0x23, 0x30, 0x19, 0xda, 0x17,
2074
+	0xb0, 0x22, 0x41, 0xbf, 0x84, 0x72, 0x2b, 0xe0, 0x1e, 0xf7, 0x49, 0x4f, 0xde, 0x71, 0x51, 0xdc,
2075
+	0x71, 0x63, 0xf3, 0xeb, 0xd7, 0xab, 0x3f, 0x9a, 0x99, 0xd1, 0xfa, 0xdc, 0xf3, 0x6b, 0x24, 0x41,
2076
+	0xe5, 0x24, 0x58, 0xe0, 0x31, 0x7e, 0xe8, 0x0b, 0x58, 0x8a, 0x85, 0xdd, 0x09, 0xa2, 0x3e, 0x67,
2077
+	0x26, 0x48, 0xad, 0xeb, 0x73, 0x6a, 0xad, 0x88, 0x94, 0xda, 0x13, 0x9c, 0x84, 0xb1, 0x77, 0x02,
2078
+	0x4e, 0x68, 0xe0, 0xfa, 0xda, 0x69, 0x87, 0x30, 0xda, 0x11, 0xbe, 0x29, 0x12, 0xef, 0x9e, 0x4c,
2079
+	0xb7, 0x66, 0x59, 0x9a, 0xe6, 0xc6, 0xf4, 0x57, 0x93, 0xe9, 0xd9, 0x51, 0xc8, 0x78, 0x8c, 0x14,
2080
+	0xdd, 0x83, 0x62, 0xec, 0x08, 0xcc, 0xac, 0x48, 0xe9, 0xad, 0x69, 0x3e, 0x31, 0x0a, 0x1e, 0x21,
2081
+	0x5b, 0x8f, 0xe1, 0xea, 0x69, 0x0e, 0x26, 0x02, 0xe6, 0x98, 0x0c, 0xe2, 0x80, 0x39, 0x26, 0x03,
2082
+	0x91, 0xb3, 0x4e, 0x5c, 0xbf, 0xaf, 0x72, 0x59, 0x11, 0x2b, 0x60, 0x33, 0x73, 0xcf, 0xb0, 0x1e,
2083
+	0x02, 0x9a, 0xf6, 0x84, 0x73, 0x71, 0xf8, 0x0c, 0x2e, 0xa5, 0x58, 0x35, 0x85, 0xc5, 0xf5, 0x24,
2084
+	0x8b, 0xe9, 0x80, 0x1d, 0xb1, 0xb4, 0xff, 0x96, 0x85, 0x72, 0xd2, 0xb7, 0xd0, 0x06, 0x5c, 0x52,
2085
+	0x1a, 0x63, 0x72, 0x94, 0x08, 0x46, 0xc5, 0x3c, 0xed, 0x08, 0xd5, 0xe1, 0xf2, 0x4e, 0x4f, 0x6f,
2086
+	0x27, 0xe3, 0x37, 0x23, 0x93, 0x4d, 0xea, 0x19, 0x0a, 0xe1, 0x03, 0xc5, 0x6a, 0x32, 0xe8, 0xb3,
2087
+	0xf2, 0x76, 0x3e, 0x39, 0x3d, 0x00, 0x9c, 0x54, 0x5a, 0xe5, 0x62, 0xe9, 0x7c, 0xd1, 0x4f, 0x60,
2088
+	0x51, 0x1d, 0x30, 0x9d, 0x57, 0x3e, 0x3a, 0xfd, 0x13, 0x8a, 0x59, 0x4c, 0x23, 0xc8, 0x95, 0x1e,
2089
+	0xcc, 0x5c, 0x38, 0x07, 0xb9, 0xa6, 0xb1, 0x1e, 0x81, 0x35, 0x5b, 0xe4, 0xf3, 0xb8, 0x80, 0xfd,
2090
+	0x57, 0x03, 0x96, 0xa7, 0x3e, 0x24, 0x9e, 0x44, 0xf9, 0x28, 0x28, 0x16, 0x72, 0x8d, 0x9a, 0xb0,
2091
+	0xa0, 0x92, 0x54, 0x46, 0x0a, 0xec, 0xcc, 0x21, 0xb0, 0x93, 0xc8, 0x50, 0x8a, 0xd8, 0xba, 0x07,
2092
+	0xf0, 0x76, 0xce, 0x6a, 0xff, 0xdd, 0x80, 0x8a, 0x4e, 0x08, 0xba, 0x7e, 0x70, 0xa1, 0x3a, 0x8c,
2093
+	0x31, 0xbd, 0xa7, 0x2b, 0x89, 0x3b, 0x33, 0x73, 0x89, 0x42, 0x73, 0x26, 0xe9, 0x94, 0x8c, 0x53,
2094
+	0xec, 0xac, 0xed, 0xd8, 0xaf, 0x26, 0x50, 0xcf, 0x25, 0xf9, 0x35, 0xa8, 0xec, 0xcb, 0x3a, 0x75,
2095
+	0xe6, 0xb3, 0x68, 0xff, 0xd7, 0x80, 0xa5, 0x18, 0x47, 0x6b, 0xf7, 0x43, 0x28, 0x9c, 0x10, 0xca,
2096
+	0xc9, 0x4b, 0xc2, 0xb4, 0x56, 0xe6, 0xb4, 0x56, 0x9f, 0x4b, 0x0c, 0x3c, 0xc4, 0x44, 0x9b, 0x50,
2097
+	0x50, 0x35, 0x31, 0x89, 0x2f, 0x6a, 0x65, 0x16, 0x95, 0xfe, 0xde, 0x10, 0x1f, 0xd5, 0x20, 0xe7,
2098
+	0x87, 0x5d, 0xa6, 0x63, 0xe6, 0x3b, 0xb3, 0xe8, 0x9e, 0x84, 0x5d, 0x2c, 0x11, 0xd1, 0x7d, 0x28,
2099
+	0x7c, 0xe5, 0xd2, 0xc0, 0x0b, 0xba, 0x71, 0x14, 0xac, 0xce, 0x22, 0x7a, 0xae, 0xf0, 0xf0, 0x90,
2100
+	0x40, 0x94, 0x71, 0x79, 0x75, 0x86, 0x1e, 0x43, 0xbe, 0xe3, 0x75, 0x09, 0xe3, 0xca, 0x24, 0x8d,
2101
+	0xba, 0x78, 0x8f, 0xbe, 0x7e, 0xbd, 0x7a, 0x33, 0xf1, 0xe0, 0x84, 0x11, 0x09, 0x44, 0xd3, 0xe0,
2102
+	0x7a, 0x01, 0xa1, 0xa2, 0x07, 0xb8, 0xad, 0x48, 0x9c, 0xa6, 0xfc, 0xc1, 0x9a, 0x83, 0xe0, 0xe5,
2103
+	0xa9, 0x67, 0x45, 0xe6, 0x8b, 0xb7, 0xe3, 0xa5, 0x38, 0x88, 0x30, 0x08, 0xdc, 0x1e, 0xd1, 0xe5,
2104
+	0x86, 0x5c, 0x8b, 0xaa, 0xa8, 0x2d, 0xfc, 0xbc, 0x23, 0xeb, 0xc5, 0x02, 0xd6, 0x10, 0xda, 0x84,
2105
+	0x45, 0xc6, 0x5d, 0x2a, 0x72, 0xce, 0xc2, 0x9c, 0xe5, 0x5c, 0x4c, 0x80, 0x1e, 0x40, 0xb1, 0x1d,
2106
+	0xf6, 0x22, 0x9f, 0x08, 0xea, 0xfc, 0x9c, 0xd4, 0x23, 0x12, 0xe1, 0x7a, 0x84, 0xd2, 0x90, 0xca,
2107
+	0x42, 0xb2, 0x88, 0x15, 0x80, 0xee, 0x42, 0x25, 0xa2, 0x61, 0x97, 0x12, 0xc6, 0x3e, 0xa5, 0x61,
2108
+	0x3f, 0xd2, 0xc5, 0xc0, 0xb2, 0x48, 0xde, 0x7b, 0xc9, 0x03, 0x3c, 0x8e, 0x67, 0xff, 0x27, 0x03,
2109
+	0xe5, 0xa4, 0x8b, 0x4c, 0x55, 0xd8, 0x8f, 0x21, 0xaf, 0x1c, 0x4e, 0xf9, 0xfa, 0xdb, 0xd9, 0x58,
2110
+	0x71, 0x48, 0xb5, 0xb1, 0x09, 0x8b, 0xed, 0x3e, 0x95, 0xe5, 0xb7, 0x2a, 0xca, 0x63, 0x50, 0x68,
2111
+	0xca, 0x43, 0xee, 0xfa, 0xd2, 0xc6, 0x59, 0xac, 0x00, 0x51, 0x91, 0x0f, 0xbb, 0xa4, 0xf3, 0x55,
2112
+	0xe4, 0x43, 0xb2, 0xe4, 0xfd, 0x2d, 0xbe, 0xd3, 0xfd, 0x15, 0xce, 0x7d, 0x7f, 0xf6, 0x3f, 0x0d,
2113
+	0x28, 0x0e, 0x63, 0x2b, 0x61, 0x5d, 0xe3, 0x9d, 0xad, 0x3b, 0x66, 0x99, 0xcc, 0xdb, 0x59, 0xe6,
2114
+	0x0a, 0xe4, 0x19, 0xa7, 0xc4, 0xed, 0xa9, 0x7e, 0x11, 0x6b, 0x48, 0x64, 0xb1, 0x1e, 0xeb, 0xca,
2115
+	0x1b, 0x2a, 0x63, 0xb1, 0xb4, 0xff, 0x67, 0x40, 0x65, 0x2c, 0xdc, 0xdf, 0xab, 0x2e, 0x97, 0x61,
2116
+	0xc1, 0x27, 0x27, 0x44, 0x75, 0xb4, 0x59, 0xac, 0x00, 0xb1, 0xcb, 0x5e, 0x84, 0x94, 0x4b, 0xe1,
2117
+	0xca, 0x58, 0x01, 0x42, 0xe6, 0x0e, 0xe1, 0xae, 0xe7, 0xcb, 0xbc, 0x54, 0xc6, 0x1a, 0x12, 0x32,
2118
+	0xf7, 0xa9, 0xaf, 0x6b, 0x74, 0xb1, 0x44, 0x36, 0xe4, 0xbc, 0xe0, 0x28, 0xd4, 0x6e, 0x23, 0x2b,
2119
+	0x1b, 0x55, 0xeb, 0xed, 0x04, 0x47, 0x21, 0x96, 0x67, 0xe8, 0x1a, 0xe4, 0xa9, 0x1b, 0x74, 0x49,
2120
+	0x5c, 0xa0, 0x17, 0x05, 0x16, 0x16, 0x3b, 0x58, 0x1f, 0xd8, 0x36, 0x94, 0x65, 0x57, 0xbc, 0x4b,
2121
+	0x98, 0xe8, 0xc1, 0x84, 0x5b, 0x77, 0x5c, 0xee, 0x4a, 0xb5, 0xcb, 0x58, 0xae, 0xed, 0x5b, 0x80,
2122
+	0x9e, 0x78, 0x8c, 0x3f, 0x97, 0x33, 0x05, 0x76, 0x56, 0xcb, 0xbc, 0x0f, 0x97, 0xc6, 0xb0, 0xf5,
2123
+	0xb3, 0xf0, 0xe3, 0x89, 0xa6, 0xf9, 0xfa, 0x74, 0xc6, 0x95, 0xa3, 0x0b, 0x47, 0x11, 0x4e, 0xf4,
2124
+	0xce, 0x15, 0x28, 0x49, 0xbd, 0xd4, 0xb7, 0x6d, 0x17, 0xca, 0x0a, 0xd4, 0xcc, 0x3f, 0x83, 0x8b,
2125
+	0x31, 0xa3, 0xcf, 0x09, 0x95, 0xed, 0x8c, 0x21, 0xed, 0xf2, 0xbd, 0x59, 0x5f, 0x69, 0x8c, 0xa3,
2126
+	0xe3, 0x49, 0x7a, 0x9b, 0xc0, 0x25, 0x89, 0xf3, 0xc8, 0x63, 0x3c, 0xa4, 0x83, 0x58, 0xeb, 0x15,
2127
+	0x80, 0xad, 0x36, 0xf7, 0x4e, 0xc8, 0xd3, 0xc0, 0x57, 0xcf, 0x68, 0x01, 0x27, 0x76, 0xe2, 0x27,
2128
+	0x32, 0x33, 0xea, 0x1c, 0xaf, 0x42, 0xb1, 0xe5, 0x52, 0x7f, 0xd0, 0x7a, 0xe9, 0x71, 0xdd, 0xc0,
2129
+	0x8f, 0x36, 0xec, 0x3f, 0x18, 0xb0, 0x9c, 0xfc, 0x4e, 0xeb, 0x44, 0xa4, 0x8b, 0xfb, 0x90, 0xe3,
2130
+	0x71, 0x1d, 0xb3, 0x94, 0xa6, 0xc4, 0x14, 0x89, 0x28, 0x75, 0xb0, 0x24, 0x4a, 0x58, 0x5a, 0x05,
2131
+	0xce, 0xf5, 0xd3, 0xc9, 0x27, 0x2c, 0xfd, 0x4d, 0x11, 0xd0, 0xf4, 0x71, 0x4a, 0x47, 0x9c, 0x6c,
2132
+	0x10, 0x33, 0x13, 0x0d, 0xe2, 0x97, 0x93, 0x0d, 0xa2, 0x7a, 0x9a, 0xef, 0xce, 0x23, 0xc9, 0x1c,
2133
+	0x6d, 0xe2, 0x58, 0x1f, 0x93, 0x3b, 0x47, 0x1f, 0x83, 0xd6, 0xe3, 0x17, 0x47, 0xbd, 0x75, 0x28,
2134
+	0xce, 0x29, 0x34, 0x6a, 0x3b, 0xba, 0xae, 0xd0, 0xaf, 0xd0, 0x83, 0xf3, 0x4d, 0x4b, 0x72, 0x93,
2135
+	0x93, 0x92, 0x06, 0x94, 0xb6, 0xe3, 0x44, 0x79, 0x8e, 0x51, 0x49, 0x92, 0x08, 0x6d, 0xe8, 0xc2,
2136
+	0x46, 0xa5, 0xe6, 0xab, 0xd3, 0x2a, 0xc6, 0x63, 0x91, 0x90, 0xea, 0xca, 0xe6, 0x28, 0xa5, 0xb4,
2137
+	0x2c, 0x4a, 0x03, 0x6d, 0xce, 0x65, 0xfb, 0x39, 0xeb, 0x4b, 0xf4, 0x09, 0xe4, 0x31, 0x61, 0x7d,
2138
+	0x9f, 0xcb, 0xf9, 0x4b, 0xa9, 0x7e, 0x6d, 0x06, 0x77, 0x85, 0x24, 0x63, 0x55, 0x13, 0xa0, 0x9f,
2139
+	0xc3, 0xa2, 0x5a, 0x31, 0xb3, 0x34, 0x6b, 0x6c, 0x90, 0x22, 0x99, 0xa6, 0xd1, 0x0d, 0x85, 0x86,
2140
+	0x44, 0x38, 0x7e, 0x4a, 0x02, 0xa2, 0xe7, 0x82, 0xa2, 0x35, 0x5e, 0xc0, 0x89, 0x1d, 0x54, 0x87,
2141
+	0x05, 0x4e, 0xdd, 0x36, 0x31, 0x2b, 0x73, 0x98, 0x50, 0xa1, 0x8a, 0xc4, 0x16, 0x79, 0x41, 0x40,
2142
+	0x3a, 0xe6, 0x92, 0xaa, 0x94, 0x14, 0x84, 0xbe, 0x0b, 0x4b, 0x41, 0xbf, 0x27, 0x9b, 0x85, 0xce,
2143
+	0x3e, 0x27, 0x11, 0x33, 0x2f, 0xca, 0xef, 0x4d, 0xec, 0xa2, 0xeb, 0x50, 0x09, 0xfa, 0xbd, 0x03,
2144
+	0xf1, 0xc2, 0x2b, 0xb4, 0xaa, 0x44, 0x1b, 0xdf, 0x44, 0xb7, 0x60, 0x59, 0xd0, 0xc5, 0xb7, 0xad,
2145
+	0x30, 0x97, 0x25, 0xe6, 0xf4, 0x01, 0x6a, 0x40, 0x85, 0xbc, 0x54, 0x03, 0x81, 0x96, 0xf4, 0x5f,
2146
+	0x34, 0x87, 0x3e, 0xe3, 0x24, 0x68, 0x0d, 0x4a, 0x41, 0xbf, 0xf7, 0x3c, 0x2e, 0x7c, 0x2f, 0xc9,
2147
+	0x6f, 0x25, 0xb7, 0xde, 0x43, 0x67, 0xfe, 0x3e, 0xfa, 0x0e, 0xeb, 0x4b, 0x28, 0x27, 0x6f, 0x3b,
2148
+	0x85, 0xf6, 0xee, 0x78, 0x5f, 0x3f, 0x87, 0xf7, 0x25, 0xda, 0x9a, 0x01, 0x7c, 0xfb, 0x59, 0xd4,
2149
+	0x71, 0x39, 0x49, 0xcb, 0xef, 0xd3, 0x79, 0xee, 0x0a, 0xe4, 0xf7, 0x94, 0x3b, 0xa8, 0xa9, 0xac,
2150
+	0x86, 0xc4, 0x7e, 0x93, 0x88, 0x2b, 0xd2, 0x49, 0x5d, 0x43, 0x32, 0x2f, 0x7a, 0x81, 0xeb, 0xc7,
2151
+	0xa3, 0xd9, 0x02, 0x1e, 0xc2, 0xf6, 0x55, 0xb0, 0xd2, 0x3e, 0xad, 0x0c, 0x65, 0xff, 0x25, 0x03,
2152
+	0x30, 0xba, 0x3e, 0xf4, 0x21, 0x40, 0x8f, 0x74, 0x3c, 0xf7, 0x57, 0x7c, 0xd4, 0xd2, 0x16, 0xe5,
2153
+	0x8e, 0xec, 0x6b, 0x47, 0xcd, 0x47, 0xe6, 0x9d, 0x9b, 0x0f, 0x04, 0x39, 0x26, 0xe4, 0x55, 0x85,
2154
+	0x92, 0x5c, 0xa3, 0xa7, 0x50, 0x72, 0x83, 0x20, 0xe4, 0x32, 0x90, 0xe2, 0x76, 0xff, 0xf6, 0x69,
2155
+	0x0e, 0xe7, 0x6c, 0x8d, 0xf0, 0x55, 0x9c, 0x26, 0x39, 0x58, 0x0f, 0xa0, 0x3a, 0x89, 0x70, 0xae,
2156
+	0x76, 0xf4, 0x1f, 0x19, 0xb8, 0x38, 0x71, 0xad, 0xe8, 0x11, 0x54, 0x15, 0x34, 0x31, 0xa2, 0x39,
2157
+	0x2b, 0x34, 0xa6, 0xa8, 0xd0, 0x43, 0x28, 0x6f, 0x71, 0x2e, 0x72, 0xb1, 0xd2, 0x57, 0x35, 0xa1,
2158
+	0xa7, 0x73, 0x19, 0xa3, 0x40, 0x8f, 0x46, 0x89, 0x2d, 0x3b, 0x6b, 0xd4, 0x30, 0x21, 0x7f, 0x7a,
2159
+	0x56, 0xb3, 0x7e, 0x31, 0x3b, 0x00, 0xb2, 0xca, 0x4a, 0xf5, 0xf1, 0x00, 0x38, 0x23, 0xaf, 0x8d,
2160
+	0x6c, 0xf8, 0x27, 0x03, 0x0a, 0x71, 0x80, 0xa6, 0x4e, 0x4b, 0xee, 0x8f, 0x4f, 0x4b, 0x6e, 0xcc,
2161
+	0x7e, 0x56, 0xdf, 0xe7, 0x90, 0xe4, 0xe6, 0x4f, 0xe1, 0x83, 0xd4, 0x92, 0x06, 0x95, 0x60, 0x71,
2162
+	0xff, 0x60, 0x0b, 0x1f, 0xb4, 0x9a, 0xd5, 0x0b, 0xa8, 0x0c, 0x85, 0xed, 0xa7, 0xbb, 0x7b, 0x4f,
2163
+	0x5a, 0x07, 0xad, 0xaa, 0x21, 0x8e, 0x9a, 0x2d, 0xb1, 0x6e, 0x56, 0x33, 0xf5, 0xdf, 0xe7, 0x61,
2164
+	0x71, 0x5b, 0xfd, 0x37, 0x87, 0x0e, 0xa0, 0x38, 0xfc, 0xd3, 0x06, 0xd9, 0x29, 0xa6, 0x99, 0xf8,
2165
+	0xf7, 0xc7, 0xfa, 0xe8, 0x54, 0x1c, 0xfd, 0xe4, 0x3d, 0x82, 0x05, 0xf9, 0xf7, 0x15, 0x4a, 0x19,
2166
+	0x4c, 0x24, 0xff, 0xd7, 0xb2, 0x4e, 0xff, 0x3b, 0x68, 0xc3, 0x10, 0x9c, 0xe4, 0x54, 0x27, 0x8d,
2167
+	0x53, 0x72, 0x74, 0x6c, 0xad, 0x9e, 0x31, 0x0e, 0x42, 0xbb, 0x90, 0xd7, 0xad, 0x6e, 0x1a, 0x6a,
2168
+	0x72, 0x76, 0x63, 0xad, 0xcd, 0x46, 0x50, 0xcc, 0x36, 0x0c, 0xb4, 0x3b, 0xfc, 0x37, 0x20, 0x4d,
2169
+	0xb4, 0x64, 0x9f, 0x60, 0x9d, 0x71, 0xbe, 0x6e, 0x6c, 0x18, 0xe8, 0x0b, 0x28, 0x25, 0x3a, 0x01,
2170
+	0x94, 0x52, 0x87, 0x4e, 0xb7, 0x15, 0xd6, 0x8d, 0x33, 0xb0, 0xb4, 0xe6, 0x2d, 0xc8, 0xc9, 0x04,
2171
+	0x90, 0x62, 0xec, 0x44, 0xa3, 0x90, 0x26, 0xe6, 0x58, 0xe3, 0x70, 0xa8, 0x5a, 0x1b, 0x12, 0x24,
2172
+	0xbd, 0x0f, 0xdd, 0x38, 0xab, 0x22, 0x99, 0xe9, 0x36, 0x53, 0x4e, 0xbc, 0x61, 0xa0, 0x10, 0xd0,
2173
+	0x74, 0xd2, 0x47, 0xdf, 0x4f, 0xf1, 0x92, 0x59, 0xaf, 0x92, 0x75, 0x6b, 0x3e, 0x64, 0xa5, 0x54,
2174
+	0xa3, 0xfc, 0xea, 0xcd, 0x8a, 0xf1, 0xaf, 0x37, 0x2b, 0xc6, 0xbf, 0xdf, 0xac, 0x18, 0x87, 0x79,
2175
+	0x59, 0x6b, 0xfe, 0xe0, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xaa, 0x06, 0xac, 0x18, 0xbb, 0x1e,
2176
+	0x00, 0x00,
2176 2177
 }
2177 2178
 
2178 2179
 // Reference imports to suppress errors if they are not otherwise used.
... ...
@@ -4030,6 +4039,13 @@ func (m *BuildHistoryRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) {
4030 4030
 		i -= len(m.XXX_unrecognized)
4031 4031
 		copy(dAtA[i:], m.XXX_unrecognized)
4032 4032
 	}
4033
+	if m.NumWarnings != 0 {
4034
+		i = encodeVarintControl(dAtA, i, uint64(m.NumWarnings))
4035
+		i--
4036
+		dAtA[i] = 0x1
4037
+		i--
4038
+		dAtA[i] = 0x98
4039
+	}
4033 4040
 	if m.ExternalError != nil {
4034 4041
 		{
4035 4042
 			size, err := m.ExternalError.MarshalToSizedBuffer(dAtA[:i])
... ...
@@ -5242,6 +5258,9 @@ func (m *BuildHistoryRecord) Size() (n int) {
5242 5242
 		l = m.ExternalError.Size()
5243 5243
 		n += 2 + l + sovControl(uint64(l))
5244 5244
 	}
5245
+	if m.NumWarnings != 0 {
5246
+		n += 2 + sovControl(uint64(m.NumWarnings))
5247
+	}
5245 5248
 	if m.XXX_unrecognized != nil {
5246 5249
 		n += len(m.XXX_unrecognized)
5247 5250
 	}
... ...
@@ -10303,6 +10322,25 @@ func (m *BuildHistoryRecord) Unmarshal(dAtA []byte) error {
10303 10303
 				return err
10304 10304
 			}
10305 10305
 			iNdEx = postIndex
10306
+		case 19:
10307
+			if wireType != 0 {
10308
+				return fmt.Errorf("proto: wrong wireType = %d for field NumWarnings", wireType)
10309
+			}
10310
+			m.NumWarnings = 0
10311
+			for shift := uint(0); ; shift += 7 {
10312
+				if shift >= 64 {
10313
+					return ErrIntOverflowControl
10314
+				}
10315
+				if iNdEx >= l {
10316
+					return io.ErrUnexpectedEOF
10317
+				}
10318
+				b := dAtA[iNdEx]
10319
+				iNdEx++
10320
+				m.NumWarnings |= int32(b&0x7F) << shift
10321
+				if b < 0x80 {
10322
+					break
10323
+				}
10324
+			}
10306 10325
 		default:
10307 10326
 			iNdEx = preIndex
10308 10327
 			skippy, err := skipControl(dAtA[iNdEx:])
... ...
@@ -212,6 +212,7 @@ message BuildHistoryRecord {
212 212
 	int32 numTotalSteps = 16;
213 213
 	int32 numCompletedSteps = 17;
214 214
 	Descriptor externalError = 18;
215
+	int32 numWarnings = 19;
215 216
 	// TODO: tags
216 217
 	// TODO: unclipped logs
217 218
 }
... ...
@@ -37,10 +37,10 @@ func v0TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) {
37 37
 
38 38
 func v1TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) {
39 39
 	pax := h.PAXRecords
40
-	if len(h.Xattrs) > 0 { //nolint:staticcheck // field deprecated in stdlib
40
+	if len(h.Xattrs) > 0 { // field deprecated in stdlib
41 41
 		if pax == nil {
42 42
 			pax = map[string]string{}
43
-			for k, v := range h.Xattrs { //nolint:staticcheck // field deprecated in stdlib
43
+			for k, v := range h.Xattrs { // field deprecated in stdlib
44 44
 				pax["SCHILY.xattr."+k] = v
45 45
 			}
46 46
 		}
... ...
@@ -8,6 +8,8 @@ import (
8 8
 	"sync"
9 9
 
10 10
 	"github.com/moby/buildkit/util/bklog"
11
+	"github.com/moby/buildkit/util/db"
12
+	"github.com/moby/buildkit/util/db/boltutil"
11 13
 	"github.com/pkg/errors"
12 14
 	bolt "go.etcd.io/bbolt"
13 15
 )
... ...
@@ -21,18 +23,18 @@ const (
21 21
 var errNotFound = errors.Errorf("not found")
22 22
 
23 23
 type Store struct {
24
-	db *bolt.DB
24
+	db db.DB
25 25
 }
26 26
 
27 27
 func NewStore(dbPath string) (*Store, error) {
28
-	db, err := bolt.Open(dbPath, 0600, nil)
28
+	db, err := boltutil.Open(dbPath, 0600, nil)
29 29
 	if err != nil {
30 30
 		return nil, errors.Wrapf(err, "failed to open database file %s", dbPath)
31 31
 	}
32 32
 	return &Store{db: db}, nil
33 33
 }
34 34
 
35
-func (s *Store) DB() *bolt.DB {
35
+func (s *Store) DB() db.Transactor {
36 36
 	return s.db
37 37
 }
38 38
 
... ...
@@ -183,21 +185,28 @@ func (s *Store) Get(id string) (*StorageItem, bool) {
183 183
 		si, _ := newStorageItem(id, nil, s)
184 184
 		return si
185 185
 	}
186
-	tx, err := s.db.Begin(false)
187
-	if err != nil {
188
-		return empty(), false
189
-	}
190
-	defer tx.Rollback()
191
-	b := tx.Bucket([]byte(mainBucket))
192
-	if b == nil {
186
+
187
+	var si *StorageItem
188
+	if err := s.db.Update(func(tx *bolt.Tx) error {
189
+		b := tx.Bucket([]byte(mainBucket))
190
+		if b == nil {
191
+			return nil
192
+		}
193
+		b = b.Bucket([]byte(id))
194
+		if b == nil {
195
+			return nil
196
+		}
197
+		si, _ = newStorageItem(id, b, s)
198
+		return nil
199
+	}); err != nil {
193 200
 		return empty(), false
194 201
 	}
195
-	b = b.Bucket([]byte(id))
196
-	if b == nil {
197
-		return empty(), false
202
+
203
+	if si != nil {
204
+		return si, true
198 205
 	}
199
-	si, _ := newStorageItem(id, b, s)
200
-	return si, true
206
+
207
+	return empty(), false
201 208
 }
202 209
 
203 210
 func (s *Store) Close() error {
... ...
@@ -15,7 +15,6 @@ import (
15 15
 	"github.com/containerd/containerd/labels"
16 16
 	"github.com/containerd/containerd/leases"
17 17
 	"github.com/containerd/containerd/mount"
18
-	"github.com/containerd/containerd/pkg/userns"
19 18
 	"github.com/containerd/containerd/snapshots"
20 19
 	cerrdefs "github.com/containerd/errdefs"
21 20
 	"github.com/docker/docker/pkg/idtools"
... ...
@@ -34,6 +33,7 @@ import (
34 34
 	rootlessmountopts "github.com/moby/buildkit/util/rootless/mountopts"
35 35
 	"github.com/moby/buildkit/util/winlayers"
36 36
 	"github.com/moby/sys/mountinfo"
37
+	"github.com/moby/sys/userns"
37 38
 	digest "github.com/opencontainers/go-digest"
38 39
 	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
39 40
 	"github.com/pkg/errors"
... ...
@@ -131,16 +131,24 @@ func StatFile(ctx context.Context, mount snapshot.Mountable, path string) (*fsty
131 131
 			// The filename here is internal to the mount, so we can restore
132 132
 			// the request base path for error reporting.
133 133
 			// See os.DirFS.Open for details.
134
-			err1 := err
135
-			if err := errors.Cause(err); err != nil {
136
-				err1 = err
137
-			}
138
-			if pe, ok := err1.(*os.PathError); ok {
139
-				pe.Path = path
140
-			}
134
+			replaceErrorPath(err, path)
141 135
 			return errors.WithStack(err)
142 136
 		}
143 137
 		return nil
144 138
 	})
145 139
 	return st, err
146 140
 }
141
+
142
+// replaceErrorPath will override the path in an os.PathError in the error chain.
143
+// This works with the fsutil library, but it isn't necessarily the correct
144
+// way to do this because the error message of wrapped errors doesn't necessarily
145
+// update or change when a wrapped error is changed.
146
+//
147
+// Still, this method of updating the path works with the way this specific
148
+// library returns errors.
149
+func replaceErrorPath(err error, path string) {
150
+	var pe *os.PathError
151
+	if errors.As(err, &pe) {
152
+		pe.Path = path
153
+	}
154
+}
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"fmt"
7 7
 	"net"
8 8
 	"sort"
9
+	"strings"
9 10
 
10 11
 	"github.com/moby/buildkit/solver/pb"
11 12
 	"github.com/moby/buildkit/util/system"
... ...
@@ -290,7 +291,7 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, []
290 290
 	if len(e.secrets) > 0 {
291 291
 		addCap(&e.constraints, pb.CapExecMountSecret)
292 292
 		for _, s := range e.secrets {
293
-			if s.IsEnv {
293
+			if s.Env != nil {
294 294
 				addCap(&e.constraints, pb.CapExecSecretEnv)
295 295
 				break
296 296
 			}
... ...
@@ -388,16 +389,17 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, []
388 388
 	}
389 389
 
390 390
 	for _, s := range e.secrets {
391
-		if s.IsEnv {
391
+		if s.Env != nil {
392 392
 			peo.Secretenv = append(peo.Secretenv, &pb.SecretEnv{
393 393
 				ID:       s.ID,
394
-				Name:     s.Target,
394
+				Name:     *s.Env,
395 395
 				Optional: s.Optional,
396 396
 			})
397
-		} else {
397
+		}
398
+		if s.Target != nil {
398 399
 			pm := &pb.Mount{
399 400
 				Input:     pb.Empty,
400
-				Dest:      s.Target,
401
+				Dest:      *s.Target,
401 402
 				MountType: pb.MountType_SECRET,
402 403
 				SecretOpt: &pb.SecretOpt{
403 404
 					ID:       s.ID,
... ...
@@ -680,7 +682,19 @@ type SSHInfo struct {
680 680
 // AddSecret is a RunOption that adds a secret to the exec.
681 681
 func AddSecret(dest string, opts ...SecretOption) RunOption {
682 682
 	return runOptionFunc(func(ei *ExecInfo) {
683
-		s := &SecretInfo{ID: dest, Target: dest, Mode: 0400}
683
+		s := &SecretInfo{ID: dest, Target: &dest, Mode: 0400}
684
+		for _, opt := range opts {
685
+			opt.SetSecretOption(s)
686
+		}
687
+		ei.Secrets = append(ei.Secrets, *s)
688
+	})
689
+}
690
+
691
+// AddSecretWithDest is a RunOption that adds a secret to the exec
692
+// with an optional destination.
693
+func AddSecretWithDest(src string, dest *string, opts ...SecretOption) RunOption {
694
+	return runOptionFunc(func(ei *ExecInfo) {
695
+		s := &SecretInfo{ID: src, Target: dest, Mode: 0400}
684 696
 		for _, opt := range opts {
685 697
 			opt.SetSecretOption(s)
686 698
 		}
... ...
@@ -699,13 +713,15 @@ func (fn secretOptionFunc) SetSecretOption(si *SecretInfo) {
699 699
 }
700 700
 
701 701
 type SecretInfo struct {
702
-	ID       string
703
-	Target   string
702
+	ID string
703
+	// Target optionally specifies the target for the secret mount
704
+	Target *string
705
+	// Env optionally names the environment variable for the secret
706
+	Env      *string
704 707
 	Mode     int
705 708
 	UID      int
706 709
 	GID      int
707 710
 	Optional bool
708
-	IsEnv    bool
709 711
 }
710 712
 
711 713
 var SecretOptional = secretOptionFunc(func(si *SecretInfo) {
... ...
@@ -721,7 +737,24 @@ func SecretID(id string) SecretOption {
721 721
 // SecretAsEnv defines if the secret should be added as an environment variable
722 722
 func SecretAsEnv(v bool) SecretOption {
723 723
 	return secretOptionFunc(func(si *SecretInfo) {
724
-		si.IsEnv = v
724
+		if !v {
725
+			si.Env = nil
726
+			return
727
+		}
728
+		if si.Target == nil {
729
+			return
730
+		}
731
+		target := strings.Clone(*si.Target)
732
+		si.Env = &target
733
+		si.Target = nil
734
+	})
735
+}
736
+
737
+// SecretAsEnvName defines if the secret should be added as an environment variable
738
+// with the specified name
739
+func SecretAsEnvName(v string) SecretOption {
740
+	return secretOptionFunc(func(si *SecretInfo) {
741
+		si.Env = &v
725 742
 	})
726 743
 }
727 744
 
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"github.com/moby/buildkit/client/llb/sourceresolver"
13 13
 	"github.com/moby/buildkit/util/contentutil"
14 14
 	"github.com/moby/buildkit/util/imageutil"
15
+	"github.com/moby/buildkit/util/tracing"
15 16
 	"github.com/moby/buildkit/version"
16 17
 	"github.com/moby/locker"
17 18
 	digest "github.com/opencontainers/go-digest"
... ...
@@ -75,7 +76,12 @@ type resolveResult struct {
75 75
 	dgst   digest.Digest
76 76
 }
77 77
 
78
-func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt) (string, digest.Digest, []byte, error) {
78
+func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt) (resolvedRef string, digest digest.Digest, config []byte, retErr error) {
79
+	span, ctx := tracing.StartSpan(ctx, "resolving "+ref)
80
+	defer func() {
81
+		tracing.FinishWithError(span, retErr)
82
+	}()
83
+
79 84
 	imr.locker.Lock(ref)
80 85
 	defer imr.locker.Unlock(ref)
81 86
 
... ...
@@ -7,7 +7,6 @@ import (
7 7
 	"io"
8 8
 	"maps"
9 9
 	"os"
10
-	"path/filepath"
11 10
 	"strings"
12 11
 	"time"
13 12
 
... ...
@@ -120,7 +119,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
120 120
 		if opt.SessionPreInitialized {
121 121
 			return nil, errors.Errorf("no session provided for preinitialized option")
122 122
 		}
123
-		s, err = session.NewSession(statusContext, defaultSessionName(), opt.SharedKey)
123
+		s, err = session.NewSession(statusContext, opt.SharedKey)
124 124
 		if err != nil {
125 125
 			return nil, errors.Wrap(err, "failed to create session")
126 126
 		}
... ...
@@ -419,14 +418,6 @@ func prepareSyncedFiles(def *llb.Definition, localMounts map[string]fsutil.FS) (
419 419
 	return result, nil
420 420
 }
421 421
 
422
-func defaultSessionName() string {
423
-	wd, err := os.Getwd()
424
-	if err != nil {
425
-		return "unknown"
426
-	}
427
-	return filepath.Base(wd)
428
-}
429
-
430 422
 type cacheOptions struct {
431 423
 	options        controlapi.CacheOptions
432 424
 	contentStores  map[string]content.Store // key: ID of content store ("local:" + csDir)
... ...
@@ -35,6 +35,7 @@ import (
35 35
 	"github.com/moby/buildkit/solver/llbsolver/proc"
36 36
 	"github.com/moby/buildkit/solver/pb"
37 37
 	"github.com/moby/buildkit/util/bklog"
38
+	"github.com/moby/buildkit/util/db"
38 39
 	"github.com/moby/buildkit/util/imageutil"
39 40
 	"github.com/moby/buildkit/util/leaseutil"
40 41
 	"github.com/moby/buildkit/util/throttle"
... ...
@@ -43,7 +44,6 @@ import (
43 43
 	"github.com/moby/buildkit/worker"
44 44
 	digest "github.com/opencontainers/go-digest"
45 45
 	"github.com/pkg/errors"
46
-	"go.etcd.io/bbolt"
47 46
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
48 47
 	tracev1 "go.opentelemetry.io/proto/otlp/collector/trace/v1"
49 48
 	"golang.org/x/sync/errgroup"
... ...
@@ -62,7 +62,7 @@ type Opt struct {
62 62
 	ResolveCacheImporterFuncs map[string]remotecache.ResolveCacheImporterFunc
63 63
 	Entitlements              []string
64 64
 	TraceCollector            sdktrace.SpanExporter
65
-	HistoryDB                 *bbolt.DB
65
+	HistoryDB                 db.DB
66 66
 	CacheStore                *bboltcachestorage.Store
67 67
 	LeaseManager              *leaseutil.Manager
68 68
 	ContentStore              *containerdsnapshot.Store
69 69
new file mode 100644
... ...
@@ -0,0 +1,59 @@
0
+package errdefs
1
+
2
+import (
3
+	"errors"
4
+	"syscall"
5
+)
6
+
7
+type internalErr struct {
8
+	error
9
+}
10
+
11
+func (internalErr) System() {}
12
+
13
+func (err internalErr) Unwrap() error {
14
+	return err.error
15
+}
16
+
17
+type system interface {
18
+	System()
19
+}
20
+
21
+var _ system = internalErr{}
22
+
23
+func Internal(err error) error {
24
+	if err == nil {
25
+		return nil
26
+	}
27
+	return internalErr{err}
28
+}
29
+
30
+func IsInternal(err error) bool {
31
+	var s system
32
+	if errors.As(err, &s) {
33
+		return true
34
+	}
35
+
36
+	var errno syscall.Errno
37
+	if errors.As(err, &errno) {
38
+		if _, ok := isInternalSyscall(errno); ok {
39
+			return true
40
+		}
41
+	}
42
+	return false
43
+}
44
+
45
+func IsResourceExhausted(err error) bool {
46
+	var errno syscall.Errno
47
+	if errors.As(err, &errno) {
48
+		if v, ok := isInternalSyscall(errno); ok && v {
49
+			return v
50
+		}
51
+	}
52
+	return false
53
+}
54
+
55
+func isInternalSyscall(err syscall.Errno) (bool, bool) {
56
+	v, ok := syscallErrors()[err]
57
+	return v, ok
58
+}
0 59
new file mode 100644
... ...
@@ -0,0 +1,23 @@
0
+//go:build linux
1
+// +build linux
2
+
3
+package errdefs
4
+
5
+import (
6
+	"syscall"
7
+
8
+	"golang.org/x/sys/unix"
9
+)
10
+
11
+// syscallErrors returns a map of syscall errors that are considered internal.
12
+// value is true if the error is of type resource exhaustion, false otherwise.
13
+func syscallErrors() map[syscall.Errno]bool {
14
+	return map[syscall.Errno]bool{
15
+		unix.EIO:             false, // I/O error
16
+		unix.ENOMEM:          true,  // Out of memory
17
+		unix.EFAULT:          false, // Bad address
18
+		unix.ENOSPC:          true,  // No space left on device
19
+		unix.ENOTRECOVERABLE: false, // State not recoverable
20
+		unix.EHWPOISON:       false, // Memory page has hardware error
21
+	}
22
+}
0 23
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+//go:build !linux
1
+// +build !linux
2
+
3
+package errdefs
4
+
5
+import "syscall"
6
+
7
+func syscallErrors() map[syscall.Errno]bool {
8
+	return nil
9
+}
... ...
@@ -40,34 +40,34 @@ func makeHostsFile(stateDir string, extraHosts []executor.HostIP, idmap *idtools
40 40
 		return "", func() {}, nil
41 41
 	}
42 42
 	if !errors.Is(err, os.ErrNotExist) {
43
-		return "", nil, err
43
+		return "", nil, errors.WithStack(err)
44 44
 	}
45 45
 
46 46
 	b := &bytes.Buffer{}
47 47
 	if _, err := b.Write([]byte(initHostsFile(hostname))); err != nil {
48
-		return "", nil, err
48
+		return "", nil, errors.WithStack(err)
49 49
 	}
50 50
 
51 51
 	for _, h := range extraHosts {
52 52
 		if _, err := b.Write([]byte(fmt.Sprintf("%s\t%s\n", h.IP.String(), h.Host))); err != nil {
53
-			return "", nil, err
53
+			return "", nil, errors.WithStack(err)
54 54
 		}
55 55
 	}
56 56
 
57 57
 	tmpPath := p + ".tmp"
58 58
 	if err := os.WriteFile(tmpPath, b.Bytes(), 0644); err != nil {
59
-		return "", nil, err
59
+		return "", nil, errors.WithStack(err)
60 60
 	}
61 61
 
62 62
 	if idmap != nil {
63 63
 		root := idmap.RootPair()
64 64
 		if err := os.Chown(tmpPath, root.UID, root.GID); err != nil {
65
-			return "", nil, err
65
+			return "", nil, errors.WithStack(err)
66 66
 		}
67 67
 	}
68 68
 
69 69
 	if err := os.Rename(tmpPath, p); err != nil {
70
-		return "", nil, err
70
+		return "", nil, errors.WithStack(err)
71 71
 	}
72 72
 	return p, func() {
73 73
 		os.RemoveAll(p)
... ...
@@ -17,7 +17,18 @@ var notFirstRun bool
17 17
 var lastNotEmpty bool
18 18
 
19 19
 // overridden by tests
20
-var resolvconfPath = resolvconf.Path
20
+var resolvconfPath = func(netMode pb.NetMode) string {
21
+	// The implementation of resolvconf.Path checks if systemd resolved is activated and chooses the internal
22
+	// resolv.conf (/run/systemd/resolve/resolv.conf) in such a case - see resolvconf_path.go of libnetwork.
23
+	// This, however, can be problematic, see https://github.com/moby/buildkit/issues/2404 and is not necessary
24
+	// in case the networking mode is set to host since the locally (127.0.0.53) running resolved daemon is
25
+	// accessible from inside a host networked container.
26
+	// For details of the implementation see https://github.com/moby/buildkit/pull/5207#discussion_r1705362230.
27
+	if netMode == pb.NetMode_HOST {
28
+		return "/etc/resolv.conf"
29
+	}
30
+	return resolvconf.Path()
31
+}
21 32
 
22 33
 type DNSConfig struct {
23 34
 	Nameservers   []string
... ...
@@ -39,12 +50,12 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity
39 39
 			fi, err := os.Stat(p)
40 40
 			if err != nil {
41 41
 				if !errors.Is(err, os.ErrNotExist) {
42
-					return struct{}{}, err
42
+					return struct{}{}, errors.WithStack(err)
43 43
 				}
44 44
 				generate = true
45 45
 			}
46 46
 			if !generate {
47
-				fiMain, err := os.Stat(resolvconfPath())
47
+				fiMain, err := os.Stat(resolvconfPath(netMode))
48 48
 				if err != nil {
49 49
 					if !errors.Is(err, os.ErrNotExist) {
50 50
 						return struct{}{}, err
... ...
@@ -63,9 +74,9 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity
63 63
 			return struct{}{}, nil
64 64
 		}
65 65
 
66
-		dt, err := os.ReadFile(resolvconfPath())
66
+		dt, err := os.ReadFile(resolvconfPath(netMode))
67 67
 		if err != nil && !errors.Is(err, os.ErrNotExist) {
68
-			return struct{}{}, err
68
+			return struct{}{}, errors.WithStack(err)
69 69
 		}
70 70
 
71 71
 		tmpPath := p + ".tmp"
... ...
@@ -87,7 +98,7 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity
87 87
 
88 88
 			f, err := resolvconf.Build(tmpPath, dnsNameservers, dnsSearchDomains, dnsOptions)
89 89
 			if err != nil {
90
-				return struct{}{}, err
90
+				return struct{}{}, errors.WithStack(err)
91 91
 			}
92 92
 			dt = f.Content
93 93
 		}
... ...
@@ -95,24 +106,24 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity
95 95
 		if netMode != pb.NetMode_HOST || len(resolvconf.GetNameservers(dt, resolvconf.IP)) == 0 {
96 96
 			f, err := resolvconf.FilterResolvDNS(dt, true)
97 97
 			if err != nil {
98
-				return struct{}{}, err
98
+				return struct{}{}, errors.WithStack(err)
99 99
 			}
100 100
 			dt = f.Content
101 101
 		}
102 102
 
103 103
 		if err := os.WriteFile(tmpPath, dt, 0644); err != nil {
104
-			return struct{}{}, err
104
+			return struct{}{}, errors.WithStack(err)
105 105
 		}
106 106
 
107 107
 		if idmap != nil {
108 108
 			root := idmap.RootPair()
109 109
 			if err := os.Chown(tmpPath, root.UID, root.GID); err != nil {
110
-				return struct{}{}, err
110
+				return struct{}{}, errors.WithStack(err)
111 111
 			}
112 112
 		}
113 113
 
114 114
 		if err := os.Rename(tmpPath, p); err != nil {
115
-			return struct{}{}, err
115
+			return struct{}{}, errors.WithStack(err)
116 116
 		}
117 117
 		return struct{}{}, nil
118 118
 	})
... ...
@@ -13,7 +13,6 @@ import (
13 13
 	"github.com/containerd/containerd/mount"
14 14
 	"github.com/containerd/containerd/namespaces"
15 15
 	"github.com/containerd/containerd/oci"
16
-	"github.com/containerd/containerd/pkg/userns"
17 16
 	"github.com/docker/docker/pkg/idtools"
18 17
 	"github.com/mitchellh/hashstructure/v2"
19 18
 	"github.com/moby/buildkit/executor"
... ...
@@ -21,6 +20,7 @@ import (
21 21
 	"github.com/moby/buildkit/util/network"
22 22
 	rootlessmountopts "github.com/moby/buildkit/util/rootless/mountopts"
23 23
 	traceexec "github.com/moby/buildkit/util/tracing/exec"
24
+	"github.com/moby/sys/userns"
24 25
 	specs "github.com/opencontainers/runtime-spec/specs-go"
25 26
 	"github.com/opencontainers/selinux/go-selinux"
26 27
 	"github.com/pkg/errors"
... ...
@@ -84,11 +84,7 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
84 84
 		ctx = namespaces.WithNamespace(ctx, "buildkit")
85 85
 	}
86 86
 
87
-	if mountOpts, err := generateMountOpts(resolvConf, hostsFile); err == nil {
88
-		opts = append(opts, mountOpts...)
89
-	} else {
90
-		return nil, nil, err
91
-	}
87
+	opts = append(opts, generateMountOpts(resolvConf, hostsFile)...)
92 88
 
93 89
 	if securityOpts, err := generateSecurityOpts(meta.SecurityMode, apparmorProfile, selinuxB); err == nil {
94 90
 		opts = append(opts, securityOpts...)
... ...
@@ -135,7 +131,7 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
135 135
 
136 136
 	s, err := oci.GenerateSpec(ctx, nil, c, opts...)
137 137
 	if err != nil {
138
-		return nil, nil, err
138
+		return nil, nil, errors.WithStack(err)
139 139
 	}
140 140
 
141 141
 	if cgroupV2NamespaceSupported() {
... ...
@@ -151,7 +147,7 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
151 151
 
152 152
 	// set the networking information on the spec
153 153
 	if err := namespace.Set(s); err != nil {
154
-		return nil, nil, err
154
+		return nil, nil, errors.WithStack(err)
155 155
 	}
156 156
 
157 157
 	sm := &submounts{}
... ...
@@ -196,6 +192,12 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
196 196
 			mount, err = sm.subMount(mount, m.Selector)
197 197
 			if err != nil {
198 198
 				releaseAll()
199
+				var os *os.PathError
200
+				if errors.As(err, &os) {
201
+					if strings.HasSuffix(os.Path, m.Selector) {
202
+						os.Path = m.Selector
203
+					}
204
+				}
199 205
 				return nil, nil, err
200 206
 			}
201 207
 			s.Mounts = append(s.Mounts, specs.Mount{
... ...
@@ -248,7 +250,7 @@ func (s *submounts) subMount(m mount.Mount, subPath string) (mount.Mount, error)
248 248
 	}
249 249
 	h, err := hashstructure.Hash(m, hashstructure.FormatV2, nil)
250 250
 	if err != nil {
251
-		return mount.Mount{}, err
251
+		return mount.Mount{}, errors.WithStack(err)
252 252
 	}
253 253
 	if mr, ok := s.m[h]; ok {
254 254
 		if sm, ok := mr.subRefs[subPath]; ok {
... ...
@@ -14,8 +14,8 @@ func withProcessArgs(args ...string) oci.SpecOpts {
14 14
 	return oci.WithProcessArgs(args...)
15 15
 }
16 16
 
17
-func generateMountOpts(_, _ string) ([]oci.SpecOpts, error) {
18
-	return nil, nil
17
+func generateMountOpts(_, _ string) []oci.SpecOpts {
18
+	return nil
19 19
 }
20 20
 
21 21
 // generateSecurityOpts may affect mounts, so must be called after generateMountOpts
... ...
@@ -38,14 +38,14 @@ func withProcessArgs(args ...string) oci.SpecOpts {
38 38
 	return oci.WithProcessArgs(args...)
39 39
 }
40 40
 
41
-func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
41
+func generateMountOpts(resolvConf, hostsFile string) []oci.SpecOpts {
42 42
 	return []oci.SpecOpts{
43 43
 		// https://github.com/moby/buildkit/issues/429
44 44
 		withRemovedMount("/run"),
45 45
 		withROBind(resolvConf, "/etc/resolv.conf"),
46 46
 		withROBind(hostsFile, "/etc/hosts"),
47 47
 		withCGroup(),
48
-	}, nil
48
+	}
49 49
 }
50 50
 
51 51
 // generateSecurityOpts may affect mounts, so must be called after generateMountOpts
... ...
@@ -260,13 +260,13 @@ func sub(m mount.Mount, subPath string) (mount.Mount, func() error, error) {
260 260
 		// similar to runc.WithProcfd
261 261
 		fh, err := os.OpenFile(src, unix.O_PATH|unix.O_CLOEXEC, 0)
262 262
 		if err != nil {
263
-			return mount.Mount{}, nil, err
263
+			return mount.Mount{}, nil, errors.WithStack(err)
264 264
 		}
265 265
 
266 266
 		fdPath := "/proc/self/fd/" + strconv.Itoa(int(fh.Fd()))
267 267
 		if resolved, err := os.Readlink(fdPath); err != nil {
268 268
 			fh.Close()
269
-			return mount.Mount{}, nil, err
269
+			return mount.Mount{}, nil, errors.WithStack(err)
270 270
 		} else if resolved != src {
271 271
 			retries--
272 272
 			if retries <= 0 {
... ...
@@ -51,10 +51,10 @@ func withGetUserInfoMount() oci.SpecOpts {
51 51
 	}
52 52
 }
53 53
 
54
-func generateMountOpts(_, _ string) ([]oci.SpecOpts, error) {
54
+func generateMountOpts(_, _ string) []oci.SpecOpts {
55 55
 	return []oci.SpecOpts{
56 56
 		withGetUserInfoMount(),
57
-	}, nil
57
+	}
58 58
 }
59 59
 
60 60
 // generateSecurityOpts may affect mounts, so must be called after generateMountOpts
... ...
@@ -219,7 +219,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
219 219
 	bundle := filepath.Join(w.root, id)
220 220
 
221 221
 	if err := os.Mkdir(bundle, 0o711); err != nil {
222
-		return nil, err
222
+		return nil, errors.WithStack(err)
223 223
 	}
224 224
 	defer os.RemoveAll(bundle)
225 225
 
... ...
@@ -230,10 +230,10 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
230 230
 
231 231
 	rootFSPath := filepath.Join(bundle, "rootfs")
232 232
 	if err := idtools.MkdirAllAndChown(rootFSPath, 0o700, identity); err != nil {
233
-		return nil, err
233
+		return nil, errors.WithStack(err)
234 234
 	}
235 235
 	if err := mount.All(rootMount, rootFSPath); err != nil {
236
-		return nil, err
236
+		return nil, errors.WithStack(err)
237 237
 	}
238 238
 	defer mount.Unmount(rootFSPath, 0)
239 239
 
... ...
@@ -241,12 +241,12 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
241 241
 
242 242
 	uid, gid, sgids, err := oci.GetUser(rootFSPath, meta.User)
243 243
 	if err != nil {
244
-		return nil, err
244
+		return nil, errors.WithStack(err)
245 245
 	}
246 246
 
247 247
 	f, err := os.Create(filepath.Join(bundle, "config.json"))
248 248
 	if err != nil {
249
-		return nil, err
249
+		return nil, errors.WithStack(err)
250 250
 	}
251 251
 	defer f.Close()
252 252
 
... ...
@@ -297,7 +297,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
297 297
 	}
298 298
 
299 299
 	if err := json.NewEncoder(f).Encode(spec); err != nil {
300
-		return nil, err
300
+		return nil, errors.WithStack(err)
301 301
 	}
302 302
 
303 303
 	bklog.G(ctx).Debugf("> creating %s %v", id, meta.Args)
... ...
@@ -335,7 +335,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
335 335
 	}
336 336
 	doReleaseNetwork = false
337 337
 
338
-	err = exitError(ctx, err)
338
+	err = exitError(ctx, cgroupPath, err)
339 339
 	if err != nil {
340 340
 		if rec != nil {
341 341
 			rec.Close()
... ...
@@ -351,7 +351,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
351 351
 	return rec, rec.CloseAsync(releaseContainer)
352 352
 }
353 353
 
354
-func exitError(ctx context.Context, err error) error {
354
+func exitError(ctx context.Context, cgroupPath string, err error) error {
355 355
 	if err != nil {
356 356
 		exitErr := &gatewayapi.ExitError{
357 357
 			ExitCode: gatewayapi.UnknownExitStatus,
... ...
@@ -363,6 +363,9 @@ func exitError(ctx context.Context, err error) error {
363 363
 				ExitCode: uint32(runcExitError.Status),
364 364
 			}
365 365
 		}
366
+
367
+		detectOOM(ctx, cgroupPath, exitErr)
368
+
366 369
 		trace.SpanFromContext(ctx).AddEvent(
367 370
 			"Container exited",
368 371
 			trace.WithAttributes(
... ...
@@ -371,7 +374,7 @@ func exitError(ctx context.Context, err error) error {
371 371
 		)
372 372
 		select {
373 373
 		case <-ctx.Done():
374
-			exitErr.Err = errors.Wrapf(context.Cause(ctx), exitErr.Error())
374
+			exitErr.Err = errors.Wrap(context.Cause(ctx), exitErr.Error())
375 375
 			return exitErr
376 376
 		default:
377 377
 			return stack.Enable(exitErr)
... ...
@@ -453,7 +456,7 @@ func (w *runcExecutor) Exec(ctx context.Context, id string, process executor.Pro
453 453
 	}
454 454
 
455 455
 	err = w.exec(ctx, id, spec.Process, process, nil)
456
-	return exitError(ctx, err)
456
+	return exitError(ctx, "", err)
457 457
 }
458 458
 
459 459
 type forwardIO struct {
... ...
@@ -1,14 +1,19 @@
1 1
 package runcexecutor
2 2
 
3 3
 import (
4
+	"bufio"
4 5
 	"context"
5 6
 	"io"
6 7
 	"os"
8
+	"path/filepath"
9
+	"strconv"
10
+	"strings"
7 11
 	"syscall"
8 12
 
9 13
 	"github.com/containerd/console"
10 14
 	runc "github.com/containerd/go-runc"
11 15
 	"github.com/moby/buildkit/executor"
16
+	gatewayapi "github.com/moby/buildkit/frontend/gateway/pb"
12 17
 	"github.com/moby/buildkit/util/bklog"
13 18
 	"github.com/moby/sys/signal"
14 19
 	"github.com/opencontainers/runtime-spec/specs-go"
... ...
@@ -172,3 +177,44 @@ func (w *runcExecutor) callWithIO(ctx context.Context, process executor.ProcessI
172 172
 
173 173
 	return call(ctx, startedCh, runcIO, killer.pidfile)
174 174
 }
175
+
176
+func detectOOM(ctx context.Context, ns string, gwErr *gatewayapi.ExitError) {
177
+	const defaultCgroupMountpoint = "/sys/fs/cgroup"
178
+
179
+	if ns == "" {
180
+		return
181
+	}
182
+
183
+	count, err := readMemoryEvent(filepath.Join(defaultCgroupMountpoint, ns), "oom_kill")
184
+	if err != nil {
185
+		bklog.G(ctx).WithError(err).Warn("failed to read oom_kill event")
186
+		return
187
+	}
188
+	if count > 0 {
189
+		gwErr.Err = syscall.ENOMEM
190
+	}
191
+}
192
+
193
+func readMemoryEvent(fp string, event string) (uint64, error) {
194
+	f, err := os.Open(filepath.Join(fp, "memory.events"))
195
+	if err != nil {
196
+		return 0, err
197
+	}
198
+	defer f.Close()
199
+
200
+	s := bufio.NewScanner(f)
201
+	for s.Scan() {
202
+		parts := strings.Fields(s.Text())
203
+		if len(parts) != 2 {
204
+			continue
205
+		}
206
+		if parts[0] != event {
207
+			continue
208
+		}
209
+		v, err := strconv.ParseUint(parts[1], 10, 64)
210
+		if err == nil {
211
+			return v, nil
212
+		}
213
+	}
214
+	return 0, s.Err()
215
+}
... ...
@@ -251,8 +251,6 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
251 251
 		}
252 252
 	}
253 253
 
254
-	validateCommandCasing(dockerfile, lint)
255
-
256 254
 	proxyEnv := proxyEnvFromBuildArgs(opt.BuildArgs)
257 255
 
258 256
 	stages, metaArgs, err := instructions.Parse(dockerfile.AST, lint)
... ...
@@ -263,6 +261,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
263 263
 		return nil, errors.New("dockerfile contains no stages to build")
264 264
 	}
265 265
 	validateStageNames(stages, lint)
266
+	validateCommandCasing(stages, lint)
266 267
 
267 268
 	shlex := shell.NewLex(dockerfile.EscapeToken)
268 269
 	outline := newOutlineCapture()
... ...
@@ -596,7 +595,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
596 596
 	ctxPaths := map[string]struct{}{}
597 597
 
598 598
 	var dockerIgnoreMatcher *patternmatcher.PatternMatcher
599
-	if opt.Client != nil && opt.Client.CopyIgnoredCheckEnabled {
599
+	if opt.Client != nil {
600 600
 		dockerIgnorePatterns, err := opt.Client.DockerIgnorePatterns(ctx)
601 601
 		if err != nil {
602 602
 			return nil, err
... ...
@@ -1363,10 +1362,11 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error {
1363 1363
 	var mode *os.FileMode
1364 1364
 	if cfg.chmod != "" {
1365 1365
 		p, err := strconv.ParseUint(cfg.chmod, 8, 32)
1366
-		if err == nil {
1367
-			perm := os.FileMode(p)
1368
-			mode = &perm
1366
+		if err != nil || p > 0o7777 {
1367
+			return errors.Errorf("invalid chmod parameter: '%v'. it should be octal string and between 0 and 07777", cfg.chmod)
1369 1368
 		}
1369
+		perm := os.FileMode(p)
1370
+		mode = &perm
1370 1371
 	}
1371 1372
 
1372 1373
 	if cfg.checksum != "" {
... ...
@@ -2198,32 +2198,49 @@ func isSelfConsistentCasing(s string) bool {
2198 2198
 	return s == strings.ToLower(s) || s == strings.ToUpper(s)
2199 2199
 }
2200 2200
 
2201
-func validateCommandCasing(dockerfile *parser.Result, lint *linter.Linter) {
2201
+func validateCaseMatch(name string, isMajorityLower bool, location []parser.Range, lint *linter.Linter) {
2202
+	var correctCasing string
2203
+	if isMajorityLower && strings.ToLower(name) != name {
2204
+		correctCasing = "lowercase"
2205
+	} else if !isMajorityLower && strings.ToUpper(name) != name {
2206
+		correctCasing = "uppercase"
2207
+	}
2208
+	if correctCasing != "" {
2209
+		msg := linter.RuleConsistentInstructionCasing.Format(name, correctCasing)
2210
+		lint.Run(&linter.RuleConsistentInstructionCasing, location, msg)
2211
+	}
2212
+}
2213
+
2214
+func validateCommandCasing(stages []instructions.Stage, lint *linter.Linter) {
2202 2215
 	var lowerCount, upperCount int
2203
-	for _, node := range dockerfile.AST.Children {
2204
-		if isSelfConsistentCasing(node.Value) {
2205
-			if strings.ToLower(node.Value) == node.Value {
2216
+	for _, stage := range stages {
2217
+		if isSelfConsistentCasing(stage.OrigCmd) {
2218
+			if strings.ToLower(stage.OrigCmd) == stage.OrigCmd {
2206 2219
 				lowerCount++
2207 2220
 			} else {
2208 2221
 				upperCount++
2209 2222
 			}
2210 2223
 		}
2224
+		for _, cmd := range stage.Commands {
2225
+			cmdName := cmd.Name()
2226
+			if isSelfConsistentCasing(cmdName) {
2227
+				if strings.ToLower(cmdName) == cmdName {
2228
+					lowerCount++
2229
+				} else {
2230
+					upperCount++
2231
+				}
2232
+			}
2233
+		}
2211 2234
 	}
2212 2235
 
2213 2236
 	isMajorityLower := lowerCount > upperCount
2214
-	for _, node := range dockerfile.AST.Children {
2237
+	for _, stage := range stages {
2215 2238
 		// Here, we check both if the command is consistent per command (ie, "CMD" or "cmd", not "Cmd")
2216 2239
 		// as well as ensuring that the casing is consistent throughout the dockerfile by comparing the
2217 2240
 		// command to the casing of the majority of commands.
2218
-		var correctCasing string
2219
-		if isMajorityLower && strings.ToLower(node.Value) != node.Value {
2220
-			correctCasing = "lowercase"
2221
-		} else if !isMajorityLower && strings.ToUpper(node.Value) != node.Value {
2222
-			correctCasing = "uppercase"
2223
-		}
2224
-		if correctCasing != "" {
2225
-			msg := linter.RuleConsistentInstructionCasing.Format(node.Value, correctCasing)
2226
-			lint.Run(&linter.RuleConsistentInstructionCasing, node.Location(), msg)
2241
+		validateCaseMatch(stage.OrigCmd, isMajorityLower, stage.Location, lint)
2242
+		for _, cmd := range stage.Commands {
2243
+			validateCaseMatch(cmd.Name(), isMajorityLower, cmd.Location(), lint)
2227 2244
 		}
2228 2245
 	}
2229 2246
 }
... ...
@@ -22,9 +22,17 @@ func dispatchSecret(d *dispatchState, m *instructions.Mount, loc []parser.Range)
22 22
 		id = path.Base(m.Target)
23 23
 	}
24 24
 
25
-	target := m.Target
26
-	if target == "" {
27
-		target = "/run/secrets/" + path.Base(id)
25
+	var target *string
26
+	if m.Target != "" {
27
+		target = &m.Target
28
+	}
29
+
30
+	if m.Env == nil {
31
+		dest := m.Target
32
+		if dest == "" {
33
+			dest = "/run/secrets/" + path.Base(id)
34
+		}
35
+		target = &dest
28 36
 	}
29 37
 
30 38
 	if _, ok := d.outline.secrets[id]; !ok {
... ...
@@ -39,6 +47,9 @@ func dispatchSecret(d *dispatchState, m *instructions.Mount, loc []parser.Range)
39 39
 	if !m.Required {
40 40
 		opts = append(opts, llb.SecretOptional)
41 41
 	}
42
+	if m.Env != nil {
43
+		opts = append(opts, llb.SecretAsEnvName(*m.Env))
44
+	}
42 45
 
43 46
 	if m.UID != nil || m.GID != nil || m.Mode != nil {
44 47
 		var uid, gid, mode int
... ...
@@ -56,5 +67,5 @@ func dispatchSecret(d *dispatchState, m *instructions.Mount, loc []parser.Range)
56 56
 		opts = append(opts, llb.SecretFileOpt(uid, gid, mode))
57 57
 	}
58 58
 
59
-	return llb.AddSecret(target, opts...), nil
59
+	return llb.AddSecretWithDest(id, target, opts...), nil
60 60
 }
... ...
@@ -255,6 +255,12 @@ func (c *AddCommand) Expand(expander SingleWordExpander) error {
255 255
 	}
256 256
 	c.Chown = expandedChown
257 257
 
258
+	expandedChmod, err := expander(c.Chmod)
259
+	if err != nil {
260
+		return err
261
+	}
262
+	c.Chmod = expandedChmod
263
+
258 264
 	expandedChecksum, err := expander(c.Checksum)
259 265
 	if err != nil {
260 266
 		return err
... ...
@@ -287,6 +293,12 @@ func (c *CopyCommand) Expand(expander SingleWordExpander) error {
287 287
 	}
288 288
 	c.Chown = expandedChown
289 289
 
290
+	expandedChmod, err := expander(c.Chmod)
291
+	if err != nil {
292
+		return err
293
+	}
294
+	c.Chmod = expandedChmod
295
+
290 296
 	return c.SourcesAndDest.Expand(expander)
291 297
 }
292 298
 
... ...
@@ -494,6 +506,7 @@ type ShellCommand struct {
494 494
 type Stage struct {
495 495
 	Name     string    // name of the stage
496 496
 	Commands []Command // commands contained within the stage
497
+	OrigCmd  string    // original FROM command, used for rule checks
497 498
 	BaseName string    // name of the base stage or source
498 499
 	Platform string    // platform of base source to use
499 500
 
... ...
@@ -122,9 +122,12 @@ type Mount struct {
122 122
 	CacheID      string
123 123
 	CacheSharing ShareMode
124 124
 	Required     bool
125
-	Mode         *uint64
126
-	UID          *uint64
127
-	GID          *uint64
125
+	// Env optionally specifies the name of the environment variable for a secret.
126
+	// A pointer to an empty value uses the default
127
+	Env  *string
128
+	Mode *uint64
129
+	UID  *uint64
130
+	GID  *uint64
128 131
 }
129 132
 
130 133
 func parseMount(val string, expander SingleWordExpander) (*Mount, error) {
... ...
@@ -252,9 +255,11 @@ func parseMount(val string, expander SingleWordExpander) (*Mount, error) {
252 252
 				return nil, errors.Errorf("invalid value %s for gid", value)
253 253
 			}
254 254
 			m.GID = &gid
255
+		case "env":
256
+			m.Env = &value
255 257
 		default:
256 258
 			allKeys := []string{
257
-				"type", "from", "source", "target", "readonly", "id", "sharing", "required", "mode", "uid", "gid", "src", "dst", "ro", "rw", "readwrite",
259
+				"type", "from", "source", "target", "readonly", "id", "sharing", "required", "size", "mode", "uid", "gid", "src", "dst", "destination", "ro", "rw", "readwrite", "env",
258 260
 			}
259 261
 			return nil, suggest.WrapError(errors.Errorf("unexpected key '%s' in '%s'", key, field), key, allKeys, true)
260 262
 		}
... ...
@@ -398,6 +398,7 @@ func parseFrom(req parseRequest) (*Stage, error) {
398 398
 	code := strings.TrimSpace(req.original)
399 399
 	return &Stage{
400 400
 		BaseName:   req.args[0],
401
+		OrigCmd:    req.command,
401 402
 		Name:       stageName,
402 403
 		SourceCode: code,
403 404
 		Commands:   []Command{},
... ...
@@ -10,42 +10,61 @@ import (
10 10
 )
11 11
 
12 12
 type Config struct {
13
-	Warn          LintWarnFunc
14
-	SkipRules     []string
15
-	SkipAll       bool
16
-	ReturnAsError bool
13
+	ExperimentalAll   bool
14
+	ExperimentalRules []string
15
+	ReturnAsError     bool
16
+	SkipAll           bool
17
+	SkipRules         []string
18
+	Warn              LintWarnFunc
17 19
 }
18 20
 
19 21
 type Linter struct {
20
-	SkippedRules  map[string]struct{}
21
-	CalledRules   []string
22
-	SkipAll       bool
23
-	ReturnAsError bool
24
-	Warn          LintWarnFunc
22
+	CalledRules       []string
23
+	ExperimentalAll   bool
24
+	ExperimentalRules map[string]struct{}
25
+	ReturnAsError     bool
26
+	SkipAll           bool
27
+	SkippedRules      map[string]struct{}
28
+	Warn              LintWarnFunc
25 29
 }
26 30
 
27 31
 func New(config *Config) *Linter {
28 32
 	toret := &Linter{
29
-		SkippedRules: map[string]struct{}{},
30
-		CalledRules:  []string{},
31
-		Warn:         config.Warn,
33
+		SkippedRules:      map[string]struct{}{},
34
+		ExperimentalRules: map[string]struct{}{},
35
+		CalledRules:       []string{},
36
+		Warn:              config.Warn,
32 37
 	}
33 38
 	toret.SkipAll = config.SkipAll
39
+	toret.ExperimentalAll = config.ExperimentalAll
34 40
 	toret.ReturnAsError = config.ReturnAsError
35 41
 	for _, rule := range config.SkipRules {
36 42
 		toret.SkippedRules[rule] = struct{}{}
37 43
 	}
44
+	for _, rule := range config.ExperimentalRules {
45
+		toret.ExperimentalRules[rule] = struct{}{}
46
+	}
38 47
 	return toret
39 48
 }
40 49
 
41 50
 func (lc *Linter) Run(rule LinterRuleI, location []parser.Range, txt ...string) {
42
-	if lc == nil || lc.Warn == nil || lc.SkipAll || rule.IsDeprecated() {
51
+	if lc == nil || lc.Warn == nil || rule.IsDeprecated() {
43 52
 		return
44 53
 	}
54
+
45 55
 	rulename := rule.RuleName()
46
-	if _, ok := lc.SkippedRules[rulename]; ok {
47
-		return
56
+	if rule.IsExperimental() {
57
+		_, experimentalOk := lc.ExperimentalRules[rulename]
58
+		if !(lc.ExperimentalAll || experimentalOk) {
59
+			return
60
+		}
61
+	} else {
62
+		_, skipOk := lc.SkippedRules[rulename]
63
+		if lc.SkipAll || skipOk {
64
+			return
65
+		}
48 66
 	}
67
+
49 68
 	lc.CalledRules = append(lc.CalledRules, rulename)
50 69
 	rule.Run(lc.Warn, location, txt...)
51 70
 }
... ...
@@ -72,14 +91,16 @@ type LinterRuleI interface {
72 72
 	RuleName() string
73 73
 	Run(warn LintWarnFunc, location []parser.Range, txt ...string)
74 74
 	IsDeprecated() bool
75
+	IsExperimental() bool
75 76
 }
76 77
 
77 78
 type LinterRule[F any] struct {
78
-	Name        string
79
-	Description string
80
-	Deprecated  bool
81
-	URL         string
82
-	Format      F
79
+	Name         string
80
+	Description  string
81
+	Deprecated   bool
82
+	Experimental bool
83
+	URL          string
84
+	Format       F
83 85
 }
84 86
 
85 87
 func (rule *LinterRule[F]) RuleName() string {
... ...
@@ -98,6 +119,10 @@ func (rule *LinterRule[F]) IsDeprecated() bool {
98 98
 	return rule.Deprecated
99 99
 }
100 100
 
101
+func (rule *LinterRule[F]) IsExperimental() bool {
102
+	return rule.Experimental
103
+}
104
+
101 105
 func LintFormatShort(rulename, msg string, line int) string {
102 106
 	msg = fmt.Sprintf("%s: %s", rulename, msg)
103 107
 	if line > 0 {
... ...
@@ -114,9 +139,9 @@ func ParseLintOptions(checkStr string) (*Config, error) {
114 114
 		return &Config{}, nil
115 115
 	}
116 116
 
117
-	parts := strings.SplitN(checkStr, ";", 2)
118
-	var skipSet []string
119
-	var errorOnWarn, skipAll bool
117
+	parts := strings.SplitN(checkStr, ";", 3)
118
+	var skipSet, experimentalSet []string
119
+	var errorOnWarn, skipAll, experimentalAll bool
120 120
 	for _, p := range parts {
121 121
 		k, v, ok := strings.Cut(p, "=")
122 122
 		if !ok {
... ...
@@ -134,6 +159,16 @@ func ParseLintOptions(checkStr string) (*Config, error) {
134 134
 					skipSet[i] = strings.TrimSpace(rule)
135 135
 				}
136 136
 			}
137
+		case "experimental":
138
+			v = strings.TrimSpace(v)
139
+			if v == "all" {
140
+				experimentalAll = true
141
+			} else {
142
+				experimentalSet = strings.Split(v, ",")
143
+				for i, rule := range experimentalSet {
144
+					experimentalSet[i] = strings.TrimSpace(rule)
145
+				}
146
+			}
137 147
 		case "error":
138 148
 			v, err := strconv.ParseBool(strings.TrimSpace(v))
139 149
 			if err != nil {
... ...
@@ -145,8 +180,10 @@ func ParseLintOptions(checkStr string) (*Config, error) {
145 145
 		}
146 146
 	}
147 147
 	return &Config{
148
-		SkipRules:     skipSet,
149
-		SkipAll:       skipAll,
150
-		ReturnAsError: errorOnWarn,
148
+		ExperimentalAll:   experimentalAll,
149
+		ExperimentalRules: experimentalSet,
150
+		SkipRules:         skipSet,
151
+		SkipAll:           skipAll,
152
+		ReturnAsError:     errorOnWarn,
151 153
 	}, nil
152 154
 }
... ...
@@ -163,5 +163,6 @@ var (
163 163
 		Format: func(cmd, file string) string {
164 164
 			return fmt.Sprintf("Attempting to %s file %q that is excluded by .dockerignore", cmd, file)
165 165
 		},
166
+		Experimental: true,
166 167
 	}
167 168
 )
... ...
@@ -378,6 +378,9 @@ func (sw *shellWord) processDollar() (string, error) {
378 378
 		fallthrough
379 379
 	case '+', '-', '?', '#', '%':
380 380
 		rawEscapes := ch == '#' || ch == '%'
381
+		if nullIsUnset && rawEscapes {
382
+			return "", errors.Errorf("unsupported modifier (%s) in substitution", chs)
383
+		}
381 384
 		word, _, err := sw.processStopOn('}', rawEscapes)
382 385
 		if err != nil {
383 386
 			if sw.scanner.Peek() == scanner.EOF {
... ...
@@ -125,6 +125,16 @@ func parseSourceDateEpoch(v string) (*time.Time, error) {
125 125
 	return &tm, nil
126 126
 }
127 127
 
128
+func parseLocalSessionIDs(opt map[string]string) map[string]string {
129
+	m := map[string]string{}
130
+	for k, v := range opt {
131
+		if strings.HasPrefix(k, localSessionIDPrefix) {
132
+			m[strings.TrimPrefix(k, localSessionIDPrefix)] = v
133
+		}
134
+	}
135
+	return m
136
+}
137
+
128 138
 func filter(opt map[string]string, key string) map[string]string {
129 139
 	m := map[string]string{}
130 140
 	for k, v := range opt {
... ...
@@ -26,8 +26,9 @@ import (
26 26
 )
27 27
 
28 28
 const (
29
-	buildArgPrefix = "build-arg:"
30
-	labelPrefix    = "label:"
29
+	buildArgPrefix       = "build-arg:"
30
+	labelPrefix          = "label:"
31
+	localSessionIDPrefix = "local-sessionid:"
31 32
 
32 33
 	keyTarget           = "target"
33 34
 	keyCgroupParent     = "cgroup-parent"
... ...
@@ -45,30 +46,28 @@ const (
45 45
 
46 46
 	// Don't forget to update frontend documentation if you add
47 47
 	// a new build-arg: frontend/dockerfile/docs/reference.md
48
-	keyCacheNSArg              = "build-arg:BUILDKIT_CACHE_MOUNT_NS"
49
-	keyMultiPlatformArg        = "build-arg:BUILDKIT_MULTI_PLATFORM"
50
-	keyHostnameArg             = "build-arg:BUILDKIT_SANDBOX_HOSTNAME"
51
-	keyDockerfileLintArg       = "build-arg:BUILDKIT_DOCKERFILE_CHECK"
52
-	keyContextKeepGitDirArg    = "build-arg:BUILDKIT_CONTEXT_KEEP_GIT_DIR"
53
-	keySourceDateEpoch         = "build-arg:SOURCE_DATE_EPOCH"
54
-	keyCopyIgnoredCheckEnabled = "build-arg:BUILDKIT_DOCKERFILE_CHECK_COPYIGNORED_EXPERIMENT"
48
+	keyCacheNSArg           = "build-arg:BUILDKIT_CACHE_MOUNT_NS"
49
+	keyMultiPlatformArg     = "build-arg:BUILDKIT_MULTI_PLATFORM"
50
+	keyHostnameArg          = "build-arg:BUILDKIT_SANDBOX_HOSTNAME"
51
+	keyDockerfileLintArg    = "build-arg:BUILDKIT_DOCKERFILE_CHECK"
52
+	keyContextKeepGitDirArg = "build-arg:BUILDKIT_CONTEXT_KEEP_GIT_DIR"
53
+	keySourceDateEpoch      = "build-arg:SOURCE_DATE_EPOCH"
55 54
 )
56 55
 
57 56
 type Config struct {
58
-	BuildArgs               map[string]string
59
-	CacheIDNamespace        string
60
-	CgroupParent            string
61
-	Epoch                   *time.Time
62
-	ExtraHosts              []llb.HostIP
63
-	Hostname                string
64
-	ImageResolveMode        llb.ResolveMode
65
-	Labels                  map[string]string
66
-	NetworkMode             pb.NetMode
67
-	ShmSize                 int64
68
-	Target                  string
69
-	Ulimits                 []pb.Ulimit
70
-	LinterConfig            *linter.Config
71
-	CopyIgnoredCheckEnabled bool
57
+	BuildArgs        map[string]string
58
+	CacheIDNamespace string
59
+	CgroupParent     string
60
+	Epoch            *time.Time
61
+	ExtraHosts       []llb.HostIP
62
+	Hostname         string
63
+	ImageResolveMode llb.ResolveMode
64
+	Labels           map[string]string
65
+	NetworkMode      pb.NetMode
66
+	ShmSize          int64
67
+	Target           string
68
+	Ulimits          []pb.Ulimit
69
+	LinterConfig     *linter.Config
72 70
 
73 71
 	CacheImports           []client.CacheOptionsEntry
74 72
 	TargetPlatforms        []ocispecs.Platform // nil means default
... ...
@@ -79,10 +78,11 @@ type Config struct {
79 79
 
80 80
 type Client struct {
81 81
 	Config
82
-	client      client.Client
83
-	ignoreCache []string
84
-	g           flightcontrol.CachedGroup[*buildContext]
85
-	bopts       client.BuildOpts
82
+	client           client.Client
83
+	ignoreCache      []string
84
+	g                flightcontrol.CachedGroup[*buildContext]
85
+	bopts            client.BuildOpts
86
+	localsSessionIDs map[string]string
86 87
 
87 88
 	dockerignore     []byte
88 89
 	dockerignoreName string
... ...
@@ -289,15 +289,8 @@ func (bc *Client) init() error {
289 289
 		}
290 290
 	}
291 291
 
292
-	// CopyIgnoredCheckEnabled is an experimental feature to check if COPY is ignored by .dockerignore,
293
-	// and it is disabled by default. It is expected that this feature will be enabled by default in a future
294
-	// release, and this build-arg will be removed.
295
-	if v, ok := opts[keyCopyIgnoredCheckEnabled]; ok {
296
-		bc.CopyIgnoredCheckEnabled, err = strconv.ParseBool(v)
297
-		if err != nil {
298
-			return errors.Wrapf(err, "failed to parse %s", keyCopyIgnoredCheckEnabled)
299
-		}
300
-	}
292
+	bc.localsSessionIDs = parseLocalSessionIDs(opts)
293
+
301 294
 	return nil
302 295
 }
303 296
 
... ...
@@ -331,9 +324,14 @@ func (bc *Client) ReadEntrypoint(ctx context.Context, lang string, opts ...llb.L
331 331
 			filenames = append(filenames, path.Join(path.Dir(bctx.filename), strings.ToLower(DefaultDockerfileName)))
332 332
 		}
333 333
 
334
+		sessionID := bc.bopts.SessionID
335
+		if v, ok := bc.localsSessionIDs[bctx.dockerfileLocalName]; ok {
336
+			sessionID = v
337
+		}
338
+
334 339
 		opts = append([]llb.LocalOption{
335 340
 			llb.FollowPaths(filenames),
336
-			llb.SessionID(bc.bopts.SessionID),
341
+			llb.SessionID(sessionID),
337 342
 			llb.SharedKeyHint(bctx.dockerfileLocalName),
338 343
 			WithInternalName(name),
339 344
 			llb.Differ(llb.DiffNone, false),
... ...
@@ -427,8 +425,13 @@ func (bc *Client) MainContext(ctx context.Context, opts ...llb.LocalOption) (*ll
427 427
 		return nil, errors.Wrapf(err, "failed to read dockerignore patterns")
428 428
 	}
429 429
 
430
+	sessionID := bc.bopts.SessionID
431
+	if v, ok := bc.localsSessionIDs[bctx.contextLocalName]; ok {
432
+		sessionID = v
433
+	}
434
+
430 435
 	opts = append([]llb.LocalOption{
431
-		llb.SessionID(bc.bopts.SessionID),
436
+		llb.SessionID(sessionID),
432 437
 		llb.ExcludePatterns(excludes),
433 438
 		llb.SharedKeyHint(bctx.contextLocalName),
434 439
 		WithInternalName("load build context"),
... ...
@@ -500,8 +503,12 @@ func WithInternalName(name string) llb.ConstraintsOpt {
500 500
 
501 501
 func (bc *Client) dockerIgnorePatterns(ctx context.Context, bctx *buildContext) ([]string, error) {
502 502
 	if bc.dockerignore == nil {
503
+		sessionID := bc.bopts.SessionID
504
+		if v, ok := bc.localsSessionIDs[bctx.contextLocalName]; ok {
505
+			sessionID = v
506
+		}
503 507
 		st := llb.Local(bctx.contextLocalName,
504
-			llb.SessionID(bc.bopts.SessionID),
508
+			llb.SessionID(sessionID),
505 509
 			llb.FollowPaths([]string{DefaultDockerignoreName}),
506 510
 			llb.SharedKeyHint(bctx.contextLocalName+"-"+DefaultDockerignoreName),
507 511
 			WithInternalName("load "+DefaultDockerignoreName),
... ...
@@ -187,8 +187,12 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
187 187
 		}
188 188
 		return &st, &img, nil
189 189
 	case "local":
190
+		sessionID := bc.bopts.SessionID
191
+		if v, ok := bc.localsSessionIDs[vv[1]]; ok {
192
+			sessionID = v
193
+		}
190 194
 		st := llb.Local(vv[1],
191
-			llb.SessionID(bc.bopts.SessionID),
195
+			llb.SessionID(sessionID),
192 196
 			llb.FollowPaths([]string{DefaultDockerignoreName}),
193 197
 			llb.SharedKeyHint("context:"+nameWithPlatform+"-"+DefaultDockerignoreName),
194 198
 			llb.WithCustomName("[context "+nameWithPlatform+"] load "+DefaultDockerignoreName),
... ...
@@ -226,7 +230,7 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
226 226
 		localOutput := &asyncLocalOutput{
227 227
 			name:             vv[1],
228 228
 			nameWithPlatform: nameWithPlatform,
229
-			sessionID:        bc.bopts.SessionID,
229
+			sessionID:        sessionID,
230 230
 			excludes:         excludes,
231 231
 			extraOpts:        opt.AsyncLocalOpts,
232 232
 		}
... ...
@@ -66,7 +66,7 @@ func (bc *Client) HandleSubrequest(ctx context.Context, h RequestHandler) (*clie
66 66
 			if warnings == nil {
67 67
 				return nil, true, nil
68 68
 			}
69
-			res, err := warnings.ToResult()
69
+			res, err := warnings.ToResult(nil)
70 70
 			return res, true, err
71 71
 		}
72 72
 	}
... ...
@@ -16,6 +16,8 @@ import (
16 16
 	"github.com/pkg/errors"
17 17
 )
18 18
 
19
+type SourceInfoMap func(*pb.SourceInfo) *pb.SourceInfo
20
+
19 21
 const RequestLint = "frontend.lint"
20 22
 
21 23
 var SubrequestLintDefinition = subrequests.Request{
... ...
@@ -39,6 +41,27 @@ type Warning struct {
39 39
 	Location    pb.Location `json:"location,omitempty"`
40 40
 }
41 41
 
42
+func (w *Warning) PrintTo(wr io.Writer, sources []*pb.SourceInfo, scb SourceInfoMap) error {
43
+	fmt.Fprintf(wr, "\nWARNING: %s", w.RuleName)
44
+	if w.URL != "" {
45
+		fmt.Fprintf(wr, " - %s", w.URL)
46
+	}
47
+	fmt.Fprintf(wr, "\n%s\n", w.Detail)
48
+
49
+	if w.Location.SourceIndex < 0 {
50
+		return nil
51
+	}
52
+	sourceInfo := sources[w.Location.SourceIndex]
53
+	if scb != nil {
54
+		sourceInfo = scb(sourceInfo)
55
+	}
56
+	source := errdefs.Source{
57
+		Info:   sourceInfo,
58
+		Ranges: w.Location.Ranges,
59
+	}
60
+	return source.Print(wr)
61
+}
62
+
42 63
 type BuildError struct {
43 64
 	Message  string      `json:"message"`
44 65
 	Location pb.Location `json:"location"`
... ...
@@ -93,7 +116,7 @@ func (results *LintResults) AddWarning(rulename, description, url, fmtmsg string
93 93
 	})
94 94
 }
95 95
 
96
-func (results *LintResults) ToResult() (*client.Result, error) {
96
+func (results *LintResults) ToResult(scb SourceInfoMap) (*client.Result, error) {
97 97
 	res := client.NewResult()
98 98
 	dt, err := json.MarshalIndent(results, "", "  ")
99 99
 	if err != nil {
... ...
@@ -102,7 +125,7 @@ func (results *LintResults) ToResult() (*client.Result, error) {
102 102
 	res.AddMeta("result.json", dt)
103 103
 
104 104
 	b := bytes.NewBuffer(nil)
105
-	if err := PrintLintViolations(dt, b); err != nil {
105
+	if err := PrintLintViolations(dt, b, scb); err != nil {
106 106
 		return nil, err
107 107
 	}
108 108
 	res.AddMeta("result.txt", b.Bytes())
... ...
@@ -117,28 +140,7 @@ func (results *LintResults) ToResult() (*client.Result, error) {
117 117
 	return res, nil
118 118
 }
119 119
 
120
-func (results *LintResults) validateWarnings() error {
121
-	for _, warning := range results.Warnings {
122
-		if int(warning.Location.SourceIndex) >= len(results.Sources) {
123
-			return errors.Errorf("sourceIndex is out of range")
124
-		}
125
-		if warning.Location.SourceIndex > 0 {
126
-			warningSource := results.Sources[warning.Location.SourceIndex]
127
-			if warningSource == nil {
128
-				return errors.Errorf("sourceIndex points to nil source")
129
-			}
130
-		}
131
-	}
132
-	return nil
133
-}
134
-
135
-func PrintLintViolations(dt []byte, w io.Writer) error {
136
-	var results LintResults
137
-
138
-	if err := json.Unmarshal(dt, &results); err != nil {
139
-		return err
140
-	}
141
-
120
+func (results *LintResults) PrintTo(w io.Writer, scb SourceInfoMap) error {
142 121
 	if err := results.validateWarnings(); err != nil {
143 122
 		return err
144 123
 	}
... ...
@@ -169,21 +171,7 @@ func PrintLintViolations(dt []byte, w io.Writer) error {
169 169
 	})
170 170
 
171 171
 	for _, warning := range results.Warnings {
172
-		fmt.Fprintf(w, "\nWARNING: %s", warning.RuleName)
173
-		if warning.URL != "" {
174
-			fmt.Fprintf(w, " - %s", warning.URL)
175
-		}
176
-		fmt.Fprintf(w, "\n%s\n", warning.Detail)
177
-
178
-		if warning.Location.SourceIndex < 0 {
179
-			continue
180
-		}
181
-		sourceInfo := results.Sources[warning.Location.SourceIndex]
182
-		source := errdefs.Source{
183
-			Info:   sourceInfo,
184
-			Ranges: warning.Location.Ranges,
185
-		}
186
-		err := source.Print(w)
172
+		err := warning.PrintTo(w, results.Sources, scb)
187 173
 		if err != nil {
188 174
 			return err
189 175
 		}
... ...
@@ -192,6 +180,47 @@ func PrintLintViolations(dt []byte, w io.Writer) error {
192 192
 	return nil
193 193
 }
194 194
 
195
+func (results *LintResults) PrintErrorTo(w io.Writer) {
196
+	// This prints out the error in LintResults to the writer in a format that
197
+	// is consistent with the warnings for easier downstream consumption.
198
+	if results.Error == nil {
199
+		return
200
+	}
201
+
202
+	fmt.Fprintln(w, results.Error.Message)
203
+	sourceInfo := results.Sources[results.Error.Location.SourceIndex]
204
+	source := errdefs.Source{
205
+		Info:   sourceInfo,
206
+		Ranges: results.Error.Location.Ranges,
207
+	}
208
+	source.Print(w)
209
+}
210
+
211
+func (results *LintResults) validateWarnings() error {
212
+	for _, warning := range results.Warnings {
213
+		if int(warning.Location.SourceIndex) >= len(results.Sources) {
214
+			return errors.Errorf("sourceIndex is out of range")
215
+		}
216
+		if warning.Location.SourceIndex > 0 {
217
+			warningSource := results.Sources[warning.Location.SourceIndex]
218
+			if warningSource == nil {
219
+				return errors.Errorf("sourceIndex points to nil source")
220
+			}
221
+		}
222
+	}
223
+	return nil
224
+}
225
+
226
+func PrintLintViolations(dt []byte, w io.Writer, scb SourceInfoMap) error {
227
+	var results LintResults
228
+
229
+	if err := json.Unmarshal(dt, &results); err != nil {
230
+		return err
231
+	}
232
+
233
+	return results.PrintTo(w, scb)
234
+}
235
+
195 236
 func sourceInfoEqual(a, b *pb.SourceInfo) bool {
196 237
 	if a.Filename != b.Filename || a.Language != b.Language {
197 238
 		return false
... ...
@@ -16,7 +16,6 @@ type Caller interface {
16 16
 	Context() context.Context
17 17
 	Supports(method string) bool
18 18
 	Conn() *grpc.ClientConn
19
-	Name() string
20 19
 	SharedKey() string
21 20
 }
22 21
 
... ...
@@ -106,7 +105,6 @@ func (sm *Manager) handleConn(ctx context.Context, conn net.Conn, opts map[strin
106 106
 
107 107
 	h := http.Header(opts)
108 108
 	id := h.Get(headerSessionID)
109
-	name := h.Get(headerSessionName)
110 109
 	sharedKey := h.Get(headerSessionSharedKey)
111 110
 
112 111
 	ctx, cc, err := grpcClientConn(ctx, conn)
... ...
@@ -118,7 +116,6 @@ func (sm *Manager) handleConn(ctx context.Context, conn net.Conn, opts map[strin
118 118
 	c := &client{
119 119
 		Session: Session{
120 120
 			id:        id,
121
-			name:      name,
122 121
 			sharedKey: sharedKey,
123 122
 			ctx:       ctx,
124 123
 			cancelCtx: cancel,
... ...
@@ -197,10 +194,6 @@ func (c *client) Context() context.Context {
197 197
 	return c.context()
198 198
 }
199 199
 
200
-func (c *client) Name() string {
201
-	return c.name
202
-}
203
-
204 200
 func (c *client) SharedKey() string {
205 201
 	return c.sharedKey
206 202
 }
... ...
@@ -38,7 +38,6 @@ type Attachable interface {
38 38
 type Session struct {
39 39
 	mu          sync.Mutex // synchronizes conn run and close
40 40
 	id          string
41
-	name        string
42 41
 	sharedKey   string
43 42
 	ctx         context.Context
44 43
 	cancelCtx   func(error)
... ...
@@ -49,7 +48,7 @@ type Session struct {
49 49
 }
50 50
 
51 51
 // NewSession returns a new long running session
52
-func NewSession(ctx context.Context, name, sharedKey string) (*Session, error) {
52
+func NewSession(ctx context.Context, sharedKey string) (*Session, error) {
53 53
 	id := identity.NewID()
54 54
 
55 55
 	serverOpts := []grpc.ServerOption{
... ...
@@ -67,7 +66,6 @@ func NewSession(ctx context.Context, name, sharedKey string) (*Session, error) {
67 67
 
68 68
 	s := &Session{
69 69
 		id:         id,
70
-		name:       name,
71 70
 		sharedKey:  sharedKey,
72 71
 		grpcServer: grpc.NewServer(serverOpts...),
73 72
 	}
... ...
@@ -103,7 +101,6 @@ func (s *Session) Run(ctx context.Context, dialer Dialer) error {
103 103
 
104 104
 	meta := make(map[string][]string)
105 105
 	meta[headerSessionID] = []string{s.id}
106
-	meta[headerSessionName] = []string{s.name}
107 106
 	meta[headerSessionSharedKey] = []string{s.sharedKey}
108 107
 
109 108
 	for name, svc := range s.grpcServer.GetServiceInfo() {
110 109
deleted file mode 100644
... ...
@@ -1,17 +0,0 @@
1
-package snapshot
2
-
3
-import (
4
-	"context"
5
-
6
-	"github.com/containerd/containerd/leases"
7
-	"github.com/containerd/containerd/snapshots"
8
-	"github.com/pkg/errors"
9
-)
10
-
11
-func (sn *mergeSnapshotter) diffApply(_ context.Context, _ Mountable, _ ...Diff) (_ snapshots.Usage, rerr error) {
12
-	return snapshots.Usage{}, errors.New("diffApply not yet supported on FreeBSD")
13
-}
14
-
15
-func needsUserXAttr(_ context.Context, _ Snapshotter, _ leases.Manager) (bool, error) {
16
-	return false, errors.New("needs userxattr not supported on FreeBSD")
17
-}
18 1
new file mode 100644
... ...
@@ -0,0 +1,857 @@
0
+package snapshot
1
+
2
+import (
3
+	"context"
4
+	gofs "io/fs"
5
+	"os"
6
+	"path/filepath"
7
+	"strings"
8
+	"syscall"
9
+
10
+	"github.com/containerd/containerd/leases"
11
+	"github.com/containerd/containerd/mount"
12
+	"github.com/containerd/containerd/snapshots"
13
+	"github.com/containerd/containerd/snapshots/overlay/overlayutils"
14
+	"github.com/containerd/continuity/fs"
15
+	"github.com/containerd/continuity/sysx"
16
+	"github.com/hashicorp/go-multierror"
17
+	"github.com/moby/buildkit/identity"
18
+	"github.com/moby/buildkit/util/bklog"
19
+	"github.com/moby/buildkit/util/leaseutil"
20
+	"github.com/moby/buildkit/util/overlay"
21
+	"github.com/pkg/errors"
22
+	"golang.org/x/sys/unix"
23
+)
24
+
25
+// diffApply applies the provided diffs to the dest Mountable and returns the correctly calculated disk usage
26
+// that accounts for any hardlinks made from existing snapshots. ctx is expected to have a temporary lease
27
+// associated with it.
28
+func (sn *mergeSnapshotter) diffApply(ctx context.Context, dest Mountable, diffs ...Diff) (_ snapshots.Usage, rerr error) {
29
+	a, err := applierFor(dest, sn.tryCrossSnapshotLink, sn.userxattr)
30
+	if err != nil {
31
+		return snapshots.Usage{}, errors.Wrapf(err, "failed to create applier")
32
+	}
33
+	defer func() {
34
+		releaseErr := a.Release()
35
+		if releaseErr != nil {
36
+			rerr = multierror.Append(rerr, errors.Wrapf(releaseErr, "failed to release applier")).ErrorOrNil()
37
+		}
38
+	}()
39
+
40
+	// TODO:(sipsma) optimization: parallelize differ and applier in separate goroutines, connected with a buffered channel
41
+
42
+	for _, diff := range diffs {
43
+		var lowerMntable Mountable
44
+		if diff.Lower != "" {
45
+			if info, err := sn.Stat(ctx, diff.Lower); err != nil {
46
+				return snapshots.Usage{}, errors.Wrapf(err, "failed to stat lower snapshot %s", diff.Lower)
47
+			} else if info.Kind == snapshots.KindCommitted {
48
+				lowerMntable, err = sn.View(ctx, identity.NewID(), diff.Lower)
49
+				if err != nil {
50
+					return snapshots.Usage{}, errors.Wrapf(err, "failed to mount lower snapshot view %s", diff.Lower)
51
+				}
52
+			} else {
53
+				lowerMntable, err = sn.Mounts(ctx, diff.Lower)
54
+				if err != nil {
55
+					return snapshots.Usage{}, errors.Wrapf(err, "failed to mount lower snapshot %s", diff.Lower)
56
+				}
57
+			}
58
+		}
59
+		var upperMntable Mountable
60
+		if diff.Upper != "" {
61
+			if info, err := sn.Stat(ctx, diff.Upper); err != nil {
62
+				return snapshots.Usage{}, errors.Wrapf(err, "failed to stat upper snapshot %s", diff.Upper)
63
+			} else if info.Kind == snapshots.KindCommitted {
64
+				upperMntable, err = sn.View(ctx, identity.NewID(), diff.Upper)
65
+				if err != nil {
66
+					return snapshots.Usage{}, errors.Wrapf(err, "failed to mount upper snapshot view %s", diff.Upper)
67
+				}
68
+			} else {
69
+				upperMntable, err = sn.Mounts(ctx, diff.Upper)
70
+				if err != nil {
71
+					return snapshots.Usage{}, errors.Wrapf(err, "failed to mount upper snapshot %s", diff.Upper)
72
+				}
73
+			}
74
+		} else {
75
+			// create an empty view
76
+			upperMntable, err = sn.View(ctx, identity.NewID(), "")
77
+			if err != nil {
78
+				return snapshots.Usage{}, errors.Wrapf(err, "failed to mount empty upper snapshot view %s", diff.Upper)
79
+			}
80
+		}
81
+		d, err := differFor(lowerMntable, upperMntable)
82
+		if err != nil {
83
+			return snapshots.Usage{}, errors.Wrapf(err, "failed to create differ")
84
+		}
85
+		defer func() {
86
+			rerr = multierror.Append(rerr, d.Release()).ErrorOrNil()
87
+		}()
88
+		if err := d.HandleChanges(ctx, a.Apply); err != nil {
89
+			return snapshots.Usage{}, errors.Wrapf(err, "failed to handle changes")
90
+		}
91
+	}
92
+
93
+	if err := a.Flush(); err != nil {
94
+		return snapshots.Usage{}, errors.Wrapf(err, "failed to flush changes")
95
+	}
96
+	return a.Usage()
97
+}
98
+
99
+type change struct {
100
+	kind    fs.ChangeKind
101
+	subPath string
102
+	srcPath string
103
+	srcStat *syscall.Stat_t
104
+	// linkSubPath is set to a subPath of a previous change from the same
105
+	// differ instance that is a hardlink to this one, if any.
106
+	linkSubPath string
107
+}
108
+
109
+type changeApply struct {
110
+	*change
111
+	dstPath   string
112
+	dstStat   *syscall.Stat_t
113
+	setOpaque bool
114
+}
115
+
116
+type inode struct {
117
+	ino uint64
118
+	dev uint64
119
+}
120
+
121
+func statInode(stat *syscall.Stat_t) inode {
122
+	if stat == nil {
123
+		return inode{}
124
+	}
125
+	return inode{
126
+		ino: stat.Ino,
127
+		dev: stat.Dev,
128
+	}
129
+}
130
+
131
+type applier struct {
132
+	root                 string
133
+	release              func() error
134
+	lowerdirs            []string // ordered highest -> lowest, the order we want to check them in
135
+	crossSnapshotLinks   map[inode]struct{}
136
+	createWhiteoutDelete bool
137
+	userxattr            bool
138
+	dirModTimes          map[string]unix.Timespec // map of dstPath -> mtime that should be set on that subPath
139
+}
140
+
141
+func applierFor(dest Mountable, tryCrossSnapshotLink, userxattr bool) (_ *applier, rerr error) {
142
+	a := &applier{
143
+		dirModTimes: make(map[string]unix.Timespec),
144
+		userxattr:   userxattr,
145
+	}
146
+	defer func() {
147
+		if rerr != nil {
148
+			rerr = multierror.Append(rerr, a.Release()).ErrorOrNil()
149
+		}
150
+	}()
151
+	if tryCrossSnapshotLink {
152
+		a.crossSnapshotLinks = make(map[inode]struct{})
153
+	}
154
+
155
+	mnts, release, err := dest.Mount()
156
+	if err != nil {
157
+		return nil, nil
158
+	}
159
+	a.release = release
160
+
161
+	if len(mnts) != 1 {
162
+		return nil, errors.Errorf("expected exactly one mount, got %d", len(mnts))
163
+	}
164
+	mnt := mnts[0]
165
+
166
+	if overlay.IsOverlayMountType(mnt) {
167
+		for _, opt := range mnt.Options {
168
+			if strings.HasPrefix(opt, "upperdir=") {
169
+				a.root = strings.TrimPrefix(opt, "upperdir=")
170
+			} else if strings.HasPrefix(opt, "lowerdir=") {
171
+				a.lowerdirs = strings.Split(strings.TrimPrefix(opt, "lowerdir="), ":")
172
+			}
173
+		}
174
+		if a.root == "" {
175
+			return nil, errors.Errorf("could not find upperdir in mount options %v", mnt.Options)
176
+		}
177
+		if len(a.lowerdirs) == 0 {
178
+			return nil, errors.Errorf("could not find lowerdir in mount options %v", mnt.Options)
179
+		}
180
+		a.createWhiteoutDelete = true
181
+	} else if mnt.Type == "bind" || mnt.Type == "rbind" {
182
+		a.root = mnt.Source
183
+	} else {
184
+		mnter := LocalMounter(dest)
185
+		root, err := mnter.Mount()
186
+		if err != nil {
187
+			return nil, err
188
+		}
189
+		a.root = root
190
+		prevRelease := a.release
191
+		a.release = func() error {
192
+			err := mnter.Unmount()
193
+			return multierror.Append(err, prevRelease()).ErrorOrNil()
194
+		}
195
+	}
196
+
197
+	a.root, err = filepath.EvalSymlinks(a.root)
198
+	if err != nil {
199
+		return nil, errors.Wrapf(err, "failed to resolve symlinks in %s", a.root)
200
+	}
201
+	return a, nil
202
+}
203
+
204
+func (a *applier) Apply(ctx context.Context, c *change) error {
205
+	if c == nil {
206
+		return errors.New("nil change")
207
+	}
208
+
209
+	if c.kind == fs.ChangeKindUnmodified {
210
+		return nil
211
+	}
212
+
213
+	dstPath, err := safeJoin(a.root, c.subPath)
214
+	if err != nil {
215
+		return errors.Wrapf(err, "failed to join paths %q and %q", a.root, c.subPath)
216
+	}
217
+	var dstStat *syscall.Stat_t
218
+	if dstfi, err := os.Lstat(dstPath); err == nil {
219
+		stat, ok := dstfi.Sys().(*syscall.Stat_t)
220
+		if !ok {
221
+			return errors.Errorf("failed to get stat_t for %T", dstStat)
222
+		}
223
+		dstStat = stat
224
+	} else if !os.IsNotExist(err) {
225
+		return errors.Wrap(err, "failed to stat during copy apply")
226
+	}
227
+
228
+	ca := &changeApply{
229
+		change:  c,
230
+		dstPath: dstPath,
231
+		dstStat: dstStat,
232
+	}
233
+
234
+	if done, err := a.applyDelete(ca); err != nil {
235
+		return errors.Wrap(err, "failed to delete during apply")
236
+	} else if done {
237
+		return nil
238
+	}
239
+
240
+	if done, err := a.applyHardlink(ctx, ca); err != nil {
241
+		return errors.Wrapf(err, "failed to hardlink during apply")
242
+	} else if done {
243
+		return nil
244
+	}
245
+
246
+	if err := a.applyCopy(ctx, ca); err != nil {
247
+		return errors.Wrapf(err, "failed to copy during apply")
248
+	}
249
+	return nil
250
+}
251
+
252
+func (a *applier) applyDelete(ca *changeApply) (bool, error) {
253
+	// Even when not deleting, we may be overwriting a file, in which case we should
254
+	// delete the existing file at the path, if any. Don't delete when both are dirs
255
+	// in this case though because they should get merged, not overwritten.
256
+	deleteOnly := ca.kind == fs.ChangeKindDelete
257
+	overwrite := !deleteOnly && ca.dstStat != nil && ca.srcStat.Mode&ca.dstStat.Mode&unix.S_IFMT != unix.S_IFDIR
258
+
259
+	if !deleteOnly && !overwrite {
260
+		// nothing to delete, continue on
261
+		return false, nil
262
+	}
263
+
264
+	if err := os.RemoveAll(ca.dstPath); err != nil {
265
+		return false, errors.Wrap(err, "failed to remove during apply")
266
+	}
267
+	ca.dstStat = nil
268
+
269
+	if overwrite && a.createWhiteoutDelete && ca.srcStat.Mode&unix.S_IFMT == unix.S_IFDIR {
270
+		// If we are using an overlay snapshotter and overwriting an existing non-directory
271
+		// with a directory, we need this new dir to be opaque so that any files from lowerdirs
272
+		// under it are not visible.
273
+		ca.setOpaque = true
274
+	}
275
+
276
+	if deleteOnly && a.createWhiteoutDelete {
277
+		// only create a whiteout device if there is something to delete
278
+		var foundLower bool
279
+		for _, lowerdir := range a.lowerdirs {
280
+			lowerPath, err := safeJoin(lowerdir, ca.subPath)
281
+			if err != nil {
282
+				return false, errors.Wrapf(err, "failed to join lowerdir %q and subPath %q", lowerdir, ca.subPath)
283
+			}
284
+			if _, err := os.Lstat(lowerPath); err == nil {
285
+				foundLower = true
286
+				break
287
+			} else if !errors.Is(err, unix.ENOENT) && !errors.Is(err, unix.ENOTDIR) {
288
+				return false, errors.Wrapf(err, "failed to stat lowerPath %q", lowerPath)
289
+			}
290
+		}
291
+		if foundLower {
292
+			ca.kind = fs.ChangeKindAdd
293
+			if ca.srcStat == nil {
294
+				ca.srcStat = &syscall.Stat_t{
295
+					Mode: syscall.S_IFCHR,
296
+					Rdev: unix.Mkdev(0, 0),
297
+				}
298
+				ca.srcPath = ""
299
+			}
300
+			return false, nil
301
+		}
302
+	}
303
+
304
+	return deleteOnly, nil
305
+}
306
+
307
+func (a *applier) applyHardlink(ctx context.Context, ca *changeApply) (bool, error) {
308
+	switch ca.srcStat.Mode & unix.S_IFMT {
309
+	case unix.S_IFDIR, unix.S_IFIFO, unix.S_IFSOCK:
310
+		// Directories can't be hard-linked, so they just have to be recreated.
311
+		// Named pipes and sockets can be hard-linked but is best to avoid as it could enable IPC in weird cases.
312
+		return false, nil
313
+
314
+	default:
315
+		var linkSrcPath string
316
+		if ca.linkSubPath != "" {
317
+			// there's an already applied path that we should link from
318
+			path, err := safeJoin(a.root, ca.linkSubPath)
319
+			if err != nil {
320
+				return false, errors.Errorf("failed to get hardlink source path: %v", err)
321
+			}
322
+			linkSrcPath = path
323
+		} else if a.crossSnapshotLinks != nil {
324
+			// we can try to link across snapshots from the source file
325
+			linkSrcPath = ca.srcPath
326
+			a.crossSnapshotLinks[statInode(ca.srcStat)] = struct{}{}
327
+		}
328
+		if linkSrcPath == "" {
329
+			// nothing to hardlink from, will have to copy the file
330
+			return false, nil
331
+		}
332
+
333
+		if err := os.Link(linkSrcPath, ca.dstPath); errors.Is(err, unix.EXDEV) || errors.Is(err, unix.EMLINK) {
334
+			// These errors are expected when the hardlink would cross devices or would exceed the maximum number of links for the inode.
335
+			// Just fallback to a copy.
336
+			bklog.G(ctx).WithError(err).WithField("srcPath", linkSrcPath).WithField("dstPath", ca.dstPath).Debug("hardlink failed")
337
+			if a.crossSnapshotLinks != nil {
338
+				delete(a.crossSnapshotLinks, statInode(ca.srcStat))
339
+			}
340
+			return false, nil
341
+		} else if err != nil {
342
+			return false, errors.Wrap(err, "failed to hardlink during apply")
343
+		}
344
+
345
+		return true, nil
346
+	}
347
+}
348
+
349
+func (a *applier) applyCopy(ctx context.Context, ca *changeApply) error {
350
+	switch ca.srcStat.Mode & unix.S_IFMT {
351
+	case unix.S_IFREG:
352
+		if err := fs.CopyFile(ca.dstPath, ca.srcPath); err != nil {
353
+			return errors.Wrapf(err, "failed to copy from %s to %s during apply", ca.srcPath, ca.dstPath)
354
+		}
355
+	case unix.S_IFDIR:
356
+		if ca.dstStat == nil {
357
+			// dstPath doesn't exist, make it a dir
358
+			if err := unix.Mkdir(ca.dstPath, ca.srcStat.Mode); err != nil {
359
+				return errors.Wrapf(err, "failed to create applied dir at %q from %q", ca.dstPath, ca.srcPath)
360
+			}
361
+		}
362
+	case unix.S_IFLNK:
363
+		if target, err := os.Readlink(ca.srcPath); err != nil {
364
+			return errors.Wrap(err, "failed to read symlink during apply")
365
+		} else if err := os.Symlink(target, ca.dstPath); err != nil {
366
+			return errors.Wrap(err, "failed to create symlink during apply")
367
+		}
368
+	case unix.S_IFBLK, unix.S_IFCHR, unix.S_IFIFO, unix.S_IFSOCK:
369
+		if err := unix.Mknod(ca.dstPath, ca.srcStat.Mode, int(ca.srcStat.Rdev)); err != nil {
370
+			return errors.Wrap(err, "failed to mknod during apply")
371
+		}
372
+	default:
373
+		// should never be here, all types should be handled
374
+		return errors.Errorf("unhandled file type %d during merge at path %q", ca.srcStat.Mode&unix.S_IFMT, ca.srcPath)
375
+	}
376
+
377
+	// NOTE: it's important that chown happens before setting xattrs due to the fact that chown will
378
+	// reset the security.capabilities xattr which results in file capabilities being lost.
379
+	if err := os.Lchown(ca.dstPath, int(ca.srcStat.Uid), int(ca.srcStat.Gid)); err != nil {
380
+		return errors.Wrap(err, "failed to chown during apply")
381
+	}
382
+
383
+	if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFLNK {
384
+		if err := unix.Chmod(ca.dstPath, ca.srcStat.Mode); err != nil {
385
+			return errors.Wrapf(err, "failed to chmod path %q during apply", ca.dstPath)
386
+		}
387
+	}
388
+
389
+	if ca.srcPath != "" {
390
+		xattrs, err := sysx.LListxattr(ca.srcPath)
391
+		if err != nil {
392
+			return errors.Wrapf(err, "failed to list xattrs of src path %s", ca.srcPath)
393
+		}
394
+		for _, xattr := range xattrs {
395
+			if isOpaqueXattr(xattr) {
396
+				// Don't recreate opaque xattrs during merge based on the source file. The differs take care of converting
397
+				// source path from the "opaque whiteout" format to the "explicit whiteout" format. The only time we set
398
+				// opaque xattrs is handled after this loop below.
399
+				continue
400
+			}
401
+			xattrVal, err := sysx.LGetxattr(ca.srcPath, xattr)
402
+			if err != nil {
403
+				return errors.Wrapf(err, "failed to get xattr %s of src path %s", xattr, ca.srcPath)
404
+			}
405
+			if err := sysx.LSetxattr(ca.dstPath, xattr, xattrVal, 0); err != nil {
406
+				// This can often fail, so just log it: https://github.com/moby/buildkit/issues/1189
407
+				bklog.G(ctx).Debugf("failed to set xattr %s of path %s during apply", xattr, ca.dstPath)
408
+			}
409
+		}
410
+	}
411
+
412
+	if ca.setOpaque {
413
+		// This is set in the case where we are creating a directory that is replacing a whiteout device
414
+		xattr := opaqueXattr(a.userxattr)
415
+		if err := sysx.LSetxattr(ca.dstPath, xattr, []byte{'y'}, 0); err != nil {
416
+			return errors.Wrapf(err, "failed to set opaque xattr %q of path %s", xattr, ca.dstPath)
417
+		}
418
+	}
419
+
420
+	atimeSpec := unix.Timespec{Sec: ca.srcStat.Atim.Sec, Nsec: ca.srcStat.Atim.Nsec}
421
+	mtimeSpec := unix.Timespec{Sec: ca.srcStat.Mtim.Sec, Nsec: ca.srcStat.Mtim.Nsec}
422
+	if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFDIR {
423
+		// apply times immediately for non-dirs
424
+		if err := unix.UtimesNanoAt(unix.AT_FDCWD, ca.dstPath, []unix.Timespec{atimeSpec, mtimeSpec}, unix.AT_SYMLINK_NOFOLLOW); err != nil {
425
+			return err
426
+		}
427
+	} else {
428
+		// save the times we should set on this dir, to be applied after subfiles have been set
429
+		a.dirModTimes[ca.dstPath] = mtimeSpec
430
+	}
431
+
432
+	return nil
433
+}
434
+
435
+func (a *applier) Flush() error {
436
+	// Set dir times now that everything has been modified. Walk the filesystem tree to ensure
437
+	// that we never try to apply to a path that has been deleted or modified since times for it
438
+	// were stored. This is needed for corner cases such as where a parent dir is removed and
439
+	// replaced with a symlink.
440
+	return filepath.WalkDir(a.root, func(path string, d gofs.DirEntry, prevErr error) error {
441
+		if prevErr != nil {
442
+			return prevErr
443
+		}
444
+		if !d.IsDir() {
445
+			return nil
446
+		}
447
+		if mtime, ok := a.dirModTimes[path]; ok {
448
+			if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, []unix.Timespec{{Nsec: unix.UTIME_OMIT}, mtime}, unix.AT_SYMLINK_NOFOLLOW); err != nil {
449
+				return err
450
+			}
451
+		}
452
+		return nil
453
+	})
454
+}
455
+
456
+func (a *applier) Release() error {
457
+	if a.release != nil {
458
+		err := a.release()
459
+		if err != nil {
460
+			return err
461
+		}
462
+	}
463
+	a.release = nil
464
+	return nil
465
+}
466
+
467
+func (a *applier) Usage() (snapshots.Usage, error) {
468
+	// Calculate the disk space used under the apply root, similar to the normal containerd snapshotter disk usage
469
+	// calculations but with the extra ability to take into account hardlinks that were created between snapshots, ensuring that
470
+	// they don't get double counted.
471
+	inodes := make(map[inode]struct{})
472
+	var usage snapshots.Usage
473
+	if err := filepath.WalkDir(a.root, func(path string, dirent gofs.DirEntry, err error) error {
474
+		if err != nil {
475
+			return err
476
+		}
477
+		info, err := dirent.Info()
478
+		if err != nil {
479
+			return err
480
+		}
481
+		stat := info.Sys().(*syscall.Stat_t)
482
+		inode := statInode(stat)
483
+		if _, ok := inodes[inode]; ok {
484
+			return nil
485
+		}
486
+		inodes[inode] = struct{}{}
487
+		if a.crossSnapshotLinks != nil {
488
+			if _, ok := a.crossSnapshotLinks[statInode(stat)]; ok {
489
+				// don't count cross-snapshot hardlinks
490
+				return nil
491
+			}
492
+		}
493
+		usage.Inodes++
494
+		usage.Size += stat.Blocks * 512 // 512 is always block size, see "man 2 stat"
495
+		return nil
496
+	}); err != nil {
497
+		return snapshots.Usage{}, err
498
+	}
499
+	return usage, nil
500
+}
501
+
502
+type differ struct {
503
+	lowerRoot    string
504
+	releaseLower func() error
505
+
506
+	upperRoot    string
507
+	releaseUpper func() error
508
+
509
+	upperBindSource  string
510
+	upperOverlayDirs []string // ordered lowest -> highest
511
+
512
+	upperdir string
513
+
514
+	visited map[string]struct{} // set of parent subPaths that have been visited
515
+	inodes  map[inode]string    // map of inode -> subPath
516
+}
517
+
518
+func differFor(lowerMntable, upperMntable Mountable) (_ *differ, rerr error) {
519
+	d := &differ{
520
+		visited: make(map[string]struct{}),
521
+		inodes:  make(map[inode]string),
522
+	}
523
+	defer func() {
524
+		if rerr != nil {
525
+			rerr = multierror.Append(rerr, d.Release()).ErrorOrNil()
526
+		}
527
+	}()
528
+
529
+	var lowerMnts []mount.Mount
530
+	if lowerMntable != nil {
531
+		mnts, release, err := lowerMntable.Mount()
532
+		if err != nil {
533
+			return nil, err
534
+		}
535
+		mounter := LocalMounterWithMounts(mnts)
536
+		root, err := mounter.Mount()
537
+		if err != nil {
538
+			return nil, err
539
+		}
540
+		d.lowerRoot = root
541
+		lowerMnts = mnts
542
+		d.releaseLower = func() error {
543
+			err := mounter.Unmount()
544
+			return multierror.Append(err, release()).ErrorOrNil()
545
+		}
546
+	}
547
+
548
+	var upperMnts []mount.Mount
549
+	if upperMntable != nil {
550
+		mnts, release, err := upperMntable.Mount()
551
+		if err != nil {
552
+			return nil, err
553
+		}
554
+		mounter := LocalMounterWithMounts(mnts)
555
+		root, err := mounter.Mount()
556
+		if err != nil {
557
+			return nil, err
558
+		}
559
+		d.upperRoot = root
560
+		upperMnts = mnts
561
+		d.releaseUpper = func() error {
562
+			err := mounter.Unmount()
563
+			return multierror.Append(err, release()).ErrorOrNil()
564
+		}
565
+	}
566
+
567
+	if len(upperMnts) == 1 {
568
+		if upperMnts[0].Type == "bind" || upperMnts[0].Type == "rbind" {
569
+			d.upperBindSource = upperMnts[0].Source
570
+		} else if overlay.IsOverlayMountType(upperMnts[0]) {
571
+			overlayDirs, err := overlay.GetOverlayLayers(upperMnts[0])
572
+			if err != nil {
573
+				return nil, errors.Wrapf(err, "failed to get overlay layers from mount %+v", upperMnts[0])
574
+			}
575
+			d.upperOverlayDirs = overlayDirs
576
+		}
577
+	}
578
+	if len(lowerMnts) > 0 {
579
+		if upperdir, err := overlay.GetUpperdir(lowerMnts, upperMnts); err == nil {
580
+			d.upperdir = upperdir
581
+		}
582
+	}
583
+
584
+	return d, nil
585
+}
586
+
587
+func (d *differ) HandleChanges(ctx context.Context, handle func(context.Context, *change) error) error {
588
+	if d.upperdir != "" {
589
+		return d.overlayChanges(ctx, handle)
590
+	}
591
+	return d.doubleWalkingChanges(ctx, handle)
592
+}
593
+
594
+func (d *differ) doubleWalkingChanges(ctx context.Context, handle func(context.Context, *change) error) error {
595
+	return fs.Changes(ctx, d.lowerRoot, d.upperRoot, func(kind fs.ChangeKind, subPath string, srcfi os.FileInfo, prevErr error) error {
596
+		if prevErr != nil {
597
+			return prevErr
598
+		}
599
+		select {
600
+		case <-ctx.Done():
601
+			return context.Cause(ctx)
602
+		default:
603
+		}
604
+
605
+		if kind == fs.ChangeKindUnmodified {
606
+			return nil
607
+		}
608
+
609
+		// NOTE: it's tempting to skip creating parent dirs when change kind is Delete, but
610
+		// that would make us incompatible with the image exporter code:
611
+		// https://github.com/containerd/containerd/pull/2095
612
+		if err := d.checkParent(ctx, subPath, handle); err != nil {
613
+			return errors.Wrapf(err, "failed to check parent for %s", subPath)
614
+		}
615
+
616
+		c := &change{
617
+			kind:    kind,
618
+			subPath: subPath,
619
+		}
620
+
621
+		if srcfi != nil {
622
+			// Try to ensure that srcPath and srcStat are set to a file from the underlying filesystem
623
+			// rather than the actual mount when possible. This allows hardlinking without getting EXDEV.
624
+			switch {
625
+			case !srcfi.IsDir() && d.upperBindSource != "":
626
+				srcPath, err := safeJoin(d.upperBindSource, c.subPath)
627
+				if err != nil {
628
+					return errors.Wrapf(err, "failed to join %s and %s", d.upperBindSource, c.subPath)
629
+				}
630
+				c.srcPath = srcPath
631
+				if fi, err := os.Lstat(c.srcPath); err == nil {
632
+					srcfi = fi
633
+				} else {
634
+					return errors.Wrap(err, "failed to stat underlying file from bind mount")
635
+				}
636
+			case !srcfi.IsDir() && len(d.upperOverlayDirs) > 0:
637
+				for i := range d.upperOverlayDirs {
638
+					dir := d.upperOverlayDirs[len(d.upperOverlayDirs)-1-i]
639
+					path, err := safeJoin(dir, c.subPath)
640
+					if err != nil {
641
+						return errors.Wrapf(err, "failed to join %s and %s", dir, c.subPath)
642
+					}
643
+					if stat, err := os.Lstat(path); err == nil {
644
+						c.srcPath = path
645
+						srcfi = stat
646
+						break
647
+					} else if errors.Is(err, unix.ENOENT) {
648
+						continue
649
+					} else {
650
+						return errors.Wrap(err, "failed to lstat when finding direct path of overlay file")
651
+					}
652
+				}
653
+			default:
654
+				srcPath, err := safeJoin(d.upperRoot, subPath)
655
+				if err != nil {
656
+					return errors.Wrapf(err, "failed to join %s and %s", d.upperRoot, subPath)
657
+				}
658
+				c.srcPath = srcPath
659
+				if fi, err := os.Lstat(c.srcPath); err == nil {
660
+					srcfi = fi
661
+				} else {
662
+					return errors.Wrap(err, "failed to stat srcPath from differ")
663
+				}
664
+			}
665
+
666
+			var ok bool
667
+			c.srcStat, ok = srcfi.Sys().(*syscall.Stat_t)
668
+			if !ok {
669
+				return errors.Errorf("unhandled stat type for %+v", srcfi)
670
+			}
671
+
672
+			if !srcfi.IsDir() && c.srcStat.Nlink > 1 {
673
+				if linkSubPath, ok := d.inodes[statInode(c.srcStat)]; ok {
674
+					c.linkSubPath = linkSubPath
675
+				} else {
676
+					d.inodes[statInode(c.srcStat)] = c.subPath
677
+				}
678
+			}
679
+		}
680
+
681
+		return handle(ctx, c)
682
+	})
683
+}
684
+
685
+func (d *differ) overlayChanges(ctx context.Context, handle func(context.Context, *change) error) error {
686
+	return overlay.Changes(ctx, func(kind fs.ChangeKind, subPath string, srcfi os.FileInfo, prevErr error) error {
687
+		if prevErr != nil {
688
+			return prevErr
689
+		}
690
+
691
+		select {
692
+		case <-ctx.Done():
693
+			return context.Cause(ctx)
694
+		default:
695
+		}
696
+
697
+		if kind == fs.ChangeKindUnmodified {
698
+			return nil
699
+		}
700
+
701
+		if err := d.checkParent(ctx, subPath, handle); err != nil {
702
+			return errors.Wrapf(err, "failed to check parent for %s", subPath)
703
+		}
704
+
705
+		srcPath, err := safeJoin(d.upperdir, subPath)
706
+		if err != nil {
707
+			return errors.Wrapf(err, "failed to join %s and %s", d.upperdir, subPath)
708
+		}
709
+
710
+		c := &change{
711
+			kind:    kind,
712
+			subPath: subPath,
713
+			srcPath: srcPath,
714
+		}
715
+
716
+		if srcfi != nil {
717
+			var ok bool
718
+			c.srcStat, ok = srcfi.Sys().(*syscall.Stat_t)
719
+			if !ok {
720
+				return errors.Errorf("unhandled stat type for %+v", srcfi)
721
+			}
722
+
723
+			// Changes with Delete kind may share the same inode even if they are unrelated.
724
+			// Skip them to avoid creating hardlinks between whiteouts as whiteouts are not
725
+			// always created and may leave the hardlink dangling.
726
+			if !srcfi.IsDir() && c.srcStat.Nlink > 1 && c.kind != fs.ChangeKindDelete {
727
+				if linkSubPath, ok := d.inodes[statInode(c.srcStat)]; ok {
728
+					c.linkSubPath = linkSubPath
729
+				} else {
730
+					d.inodes[statInode(c.srcStat)] = c.subPath
731
+				}
732
+			}
733
+		}
734
+
735
+		return handle(ctx, c)
736
+	}, d.upperdir, d.upperRoot, d.lowerRoot)
737
+}
738
+
739
+func (d *differ) checkParent(ctx context.Context, subPath string, handle func(context.Context, *change) error) error {
740
+	parentSubPath := filepath.Dir(subPath)
741
+	if parentSubPath == "/" {
742
+		return nil
743
+	}
744
+	if _, ok := d.visited[parentSubPath]; ok {
745
+		return nil
746
+	}
747
+	d.visited[parentSubPath] = struct{}{}
748
+
749
+	if err := d.checkParent(ctx, parentSubPath, handle); err != nil {
750
+		return err
751
+	}
752
+	parentSrcPath, err := safeJoin(d.upperRoot, parentSubPath)
753
+	if err != nil {
754
+		return err
755
+	}
756
+	srcfi, err := os.Lstat(parentSrcPath)
757
+	if err != nil {
758
+		return err
759
+	}
760
+	parentSrcStat, ok := srcfi.Sys().(*syscall.Stat_t)
761
+	if !ok {
762
+		return errors.Errorf("unexpected type %T", srcfi)
763
+	}
764
+	return handle(ctx, &change{
765
+		kind:    fs.ChangeKindModify,
766
+		subPath: parentSubPath,
767
+		srcPath: parentSrcPath,
768
+		srcStat: parentSrcStat,
769
+	})
770
+}
771
+
772
+func (d *differ) Release() error {
773
+	var err error
774
+	if d.releaseLower != nil {
775
+		err = d.releaseLower()
776
+		if err == nil {
777
+			d.releaseLower = nil
778
+		}
779
+	}
780
+	if d.releaseUpper != nil {
781
+		err = multierror.Append(err, d.releaseUpper()).ErrorOrNil()
782
+		if err == nil {
783
+			d.releaseUpper = nil
784
+		}
785
+	}
786
+	return err
787
+}
788
+
789
+func safeJoin(root, path string) (string, error) {
790
+	dir, base := filepath.Split(path)
791
+	parent, err := fs.RootPath(root, dir)
792
+	if err != nil {
793
+		return "", err
794
+	}
795
+	return filepath.Join(parent, base), nil
796
+}
797
+
798
+const (
799
+	trustedOpaqueXattr = "trusted.overlay.opaque"
800
+	userOpaqueXattr    = "user.overlay.opaque"
801
+)
802
+
803
+func isOpaqueXattr(s string) bool {
804
+	for _, k := range []string{trustedOpaqueXattr, userOpaqueXattr} {
805
+		if s == k {
806
+			return true
807
+		}
808
+	}
809
+	return false
810
+}
811
+
812
+func opaqueXattr(userxattr bool) string {
813
+	if userxattr {
814
+		return userOpaqueXattr
815
+	}
816
+	return trustedOpaqueXattr
817
+}
818
+
819
+// needsUserXAttr checks whether overlay mounts should be provided the userxattr option. We can't use
820
+// NeedsUserXAttr from the overlayutils package directly because we don't always have direct knowledge
821
+// of the root of the snapshotter state (such as when using a remote snapshotter). Instead, we create
822
+// a temporary new snapshot and test using its root, which works because single layer snapshots will
823
+// use bind-mounts even when created by an overlay based snapshotter.
824
+func needsUserXAttr(ctx context.Context, sn Snapshotter, lm leases.Manager) (bool, error) {
825
+	key := identity.NewID()
826
+
827
+	ctx, done, err := leaseutil.WithLease(ctx, lm, leaseutil.MakeTemporary)
828
+	if err != nil {
829
+		return false, errors.Wrap(err, "failed to create lease for checking user xattr")
830
+	}
831
+	defer done(context.TODO())
832
+
833
+	err = sn.Prepare(ctx, key, "")
834
+	if err != nil {
835
+		return false, err
836
+	}
837
+	mntable, err := sn.Mounts(ctx, key)
838
+	if err != nil {
839
+		return false, err
840
+	}
841
+	mnts, unmount, err := mntable.Mount()
842
+	if err != nil {
843
+		return false, err
844
+	}
845
+	defer unmount()
846
+
847
+	var userxattr bool
848
+	if err := mount.WithTempMount(ctx, mnts, func(root string) error {
849
+		var err error
850
+		userxattr, err = overlayutils.NeedsUserXAttr(root)
851
+		return err
852
+	}); err != nil {
853
+		return false, err
854
+	}
855
+	return userxattr, nil
856
+}
0 857
deleted file mode 100644
... ...
@@ -1,860 +0,0 @@
1
-//go:build !windows && !freebsd
2
-// +build !windows,!freebsd
3
-
4
-package snapshot
5
-
6
-import (
7
-	"context"
8
-	gofs "io/fs"
9
-	"os"
10
-	"path/filepath"
11
-	"strings"
12
-	"syscall"
13
-
14
-	"github.com/containerd/containerd/leases"
15
-	"github.com/containerd/containerd/mount"
16
-	"github.com/containerd/containerd/snapshots"
17
-	"github.com/containerd/containerd/snapshots/overlay/overlayutils"
18
-	"github.com/containerd/continuity/fs"
19
-	"github.com/containerd/continuity/sysx"
20
-	"github.com/hashicorp/go-multierror"
21
-	"github.com/moby/buildkit/identity"
22
-	"github.com/moby/buildkit/util/bklog"
23
-	"github.com/moby/buildkit/util/leaseutil"
24
-	"github.com/moby/buildkit/util/overlay"
25
-	"github.com/pkg/errors"
26
-	"golang.org/x/sys/unix"
27
-)
28
-
29
-// diffApply applies the provided diffs to the dest Mountable and returns the correctly calculated disk usage
30
-// that accounts for any hardlinks made from existing snapshots. ctx is expected to have a temporary lease
31
-// associated with it.
32
-func (sn *mergeSnapshotter) diffApply(ctx context.Context, dest Mountable, diffs ...Diff) (_ snapshots.Usage, rerr error) {
33
-	a, err := applierFor(dest, sn.tryCrossSnapshotLink, sn.userxattr)
34
-	if err != nil {
35
-		return snapshots.Usage{}, errors.Wrapf(err, "failed to create applier")
36
-	}
37
-	defer func() {
38
-		releaseErr := a.Release()
39
-		if releaseErr != nil {
40
-			rerr = multierror.Append(rerr, errors.Wrapf(releaseErr, "failed to release applier")).ErrorOrNil()
41
-		}
42
-	}()
43
-
44
-	// TODO:(sipsma) optimization: parallelize differ and applier in separate goroutines, connected with a buffered channel
45
-
46
-	for _, diff := range diffs {
47
-		var lowerMntable Mountable
48
-		if diff.Lower != "" {
49
-			if info, err := sn.Stat(ctx, diff.Lower); err != nil {
50
-				return snapshots.Usage{}, errors.Wrapf(err, "failed to stat lower snapshot %s", diff.Lower)
51
-			} else if info.Kind == snapshots.KindCommitted {
52
-				lowerMntable, err = sn.View(ctx, identity.NewID(), diff.Lower)
53
-				if err != nil {
54
-					return snapshots.Usage{}, errors.Wrapf(err, "failed to mount lower snapshot view %s", diff.Lower)
55
-				}
56
-			} else {
57
-				lowerMntable, err = sn.Mounts(ctx, diff.Lower)
58
-				if err != nil {
59
-					return snapshots.Usage{}, errors.Wrapf(err, "failed to mount lower snapshot %s", diff.Lower)
60
-				}
61
-			}
62
-		}
63
-		var upperMntable Mountable
64
-		if diff.Upper != "" {
65
-			if info, err := sn.Stat(ctx, diff.Upper); err != nil {
66
-				return snapshots.Usage{}, errors.Wrapf(err, "failed to stat upper snapshot %s", diff.Upper)
67
-			} else if info.Kind == snapshots.KindCommitted {
68
-				upperMntable, err = sn.View(ctx, identity.NewID(), diff.Upper)
69
-				if err != nil {
70
-					return snapshots.Usage{}, errors.Wrapf(err, "failed to mount upper snapshot view %s", diff.Upper)
71
-				}
72
-			} else {
73
-				upperMntable, err = sn.Mounts(ctx, diff.Upper)
74
-				if err != nil {
75
-					return snapshots.Usage{}, errors.Wrapf(err, "failed to mount upper snapshot %s", diff.Upper)
76
-				}
77
-			}
78
-		} else {
79
-			// create an empty view
80
-			upperMntable, err = sn.View(ctx, identity.NewID(), "")
81
-			if err != nil {
82
-				return snapshots.Usage{}, errors.Wrapf(err, "failed to mount empty upper snapshot view %s", diff.Upper)
83
-			}
84
-		}
85
-		d, err := differFor(lowerMntable, upperMntable)
86
-		if err != nil {
87
-			return snapshots.Usage{}, errors.Wrapf(err, "failed to create differ")
88
-		}
89
-		defer func() {
90
-			rerr = multierror.Append(rerr, d.Release()).ErrorOrNil()
91
-		}()
92
-		if err := d.HandleChanges(ctx, a.Apply); err != nil {
93
-			return snapshots.Usage{}, errors.Wrapf(err, "failed to handle changes")
94
-		}
95
-	}
96
-
97
-	if err := a.Flush(); err != nil {
98
-		return snapshots.Usage{}, errors.Wrapf(err, "failed to flush changes")
99
-	}
100
-	return a.Usage()
101
-}
102
-
103
-type change struct {
104
-	kind    fs.ChangeKind
105
-	subPath string
106
-	srcPath string
107
-	srcStat *syscall.Stat_t
108
-	// linkSubPath is set to a subPath of a previous change from the same
109
-	// differ instance that is a hardlink to this one, if any.
110
-	linkSubPath string
111
-}
112
-
113
-type changeApply struct {
114
-	*change
115
-	dstPath   string
116
-	dstStat   *syscall.Stat_t
117
-	setOpaque bool
118
-}
119
-
120
-type inode struct {
121
-	ino uint64
122
-	dev uint64
123
-}
124
-
125
-func statInode(stat *syscall.Stat_t) inode {
126
-	if stat == nil {
127
-		return inode{}
128
-	}
129
-	return inode{
130
-		ino: stat.Ino,
131
-		dev: stat.Dev,
132
-	}
133
-}
134
-
135
-type applier struct {
136
-	root                 string
137
-	release              func() error
138
-	lowerdirs            []string // ordered highest -> lowest, the order we want to check them in
139
-	crossSnapshotLinks   map[inode]struct{}
140
-	createWhiteoutDelete bool
141
-	userxattr            bool
142
-	dirModTimes          map[string]unix.Timespec // map of dstPath -> mtime that should be set on that subPath
143
-}
144
-
145
-func applierFor(dest Mountable, tryCrossSnapshotLink, userxattr bool) (_ *applier, rerr error) {
146
-	a := &applier{
147
-		dirModTimes: make(map[string]unix.Timespec),
148
-		userxattr:   userxattr,
149
-	}
150
-	defer func() {
151
-		if rerr != nil {
152
-			rerr = multierror.Append(rerr, a.Release()).ErrorOrNil()
153
-		}
154
-	}()
155
-	if tryCrossSnapshotLink {
156
-		a.crossSnapshotLinks = make(map[inode]struct{})
157
-	}
158
-
159
-	mnts, release, err := dest.Mount()
160
-	if err != nil {
161
-		return nil, nil
162
-	}
163
-	a.release = release
164
-
165
-	if len(mnts) != 1 {
166
-		return nil, errors.Errorf("expected exactly one mount, got %d", len(mnts))
167
-	}
168
-	mnt := mnts[0]
169
-
170
-	if overlay.IsOverlayMountType(mnt) {
171
-		for _, opt := range mnt.Options {
172
-			if strings.HasPrefix(opt, "upperdir=") {
173
-				a.root = strings.TrimPrefix(opt, "upperdir=")
174
-			} else if strings.HasPrefix(opt, "lowerdir=") {
175
-				a.lowerdirs = strings.Split(strings.TrimPrefix(opt, "lowerdir="), ":")
176
-			}
177
-		}
178
-		if a.root == "" {
179
-			return nil, errors.Errorf("could not find upperdir in mount options %v", mnt.Options)
180
-		}
181
-		if len(a.lowerdirs) == 0 {
182
-			return nil, errors.Errorf("could not find lowerdir in mount options %v", mnt.Options)
183
-		}
184
-		a.createWhiteoutDelete = true
185
-	} else if mnt.Type == "bind" || mnt.Type == "rbind" {
186
-		a.root = mnt.Source
187
-	} else {
188
-		mnter := LocalMounter(dest)
189
-		root, err := mnter.Mount()
190
-		if err != nil {
191
-			return nil, err
192
-		}
193
-		a.root = root
194
-		prevRelease := a.release
195
-		a.release = func() error {
196
-			err := mnter.Unmount()
197
-			return multierror.Append(err, prevRelease()).ErrorOrNil()
198
-		}
199
-	}
200
-
201
-	a.root, err = filepath.EvalSymlinks(a.root)
202
-	if err != nil {
203
-		return nil, errors.Wrapf(err, "failed to resolve symlinks in %s", a.root)
204
-	}
205
-	return a, nil
206
-}
207
-
208
-func (a *applier) Apply(ctx context.Context, c *change) error {
209
-	if c == nil {
210
-		return errors.New("nil change")
211
-	}
212
-
213
-	if c.kind == fs.ChangeKindUnmodified {
214
-		return nil
215
-	}
216
-
217
-	dstPath, err := safeJoin(a.root, c.subPath)
218
-	if err != nil {
219
-		return errors.Wrapf(err, "failed to join paths %q and %q", a.root, c.subPath)
220
-	}
221
-	var dstStat *syscall.Stat_t
222
-	if dstfi, err := os.Lstat(dstPath); err == nil {
223
-		stat, ok := dstfi.Sys().(*syscall.Stat_t)
224
-		if !ok {
225
-			return errors.Errorf("failed to get stat_t for %T", dstStat)
226
-		}
227
-		dstStat = stat
228
-	} else if !os.IsNotExist(err) {
229
-		return errors.Wrap(err, "failed to stat during copy apply")
230
-	}
231
-
232
-	ca := &changeApply{
233
-		change:  c,
234
-		dstPath: dstPath,
235
-		dstStat: dstStat,
236
-	}
237
-
238
-	if done, err := a.applyDelete(ca); err != nil {
239
-		return errors.Wrap(err, "failed to delete during apply")
240
-	} else if done {
241
-		return nil
242
-	}
243
-
244
-	if done, err := a.applyHardlink(ctx, ca); err != nil {
245
-		return errors.Wrapf(err, "failed to hardlink during apply")
246
-	} else if done {
247
-		return nil
248
-	}
249
-
250
-	if err := a.applyCopy(ctx, ca); err != nil {
251
-		return errors.Wrapf(err, "failed to copy during apply")
252
-	}
253
-	return nil
254
-}
255
-
256
-func (a *applier) applyDelete(ca *changeApply) (bool, error) {
257
-	// Even when not deleting, we may be overwriting a file, in which case we should
258
-	// delete the existing file at the path, if any. Don't delete when both are dirs
259
-	// in this case though because they should get merged, not overwritten.
260
-	deleteOnly := ca.kind == fs.ChangeKindDelete
261
-	overwrite := !deleteOnly && ca.dstStat != nil && ca.srcStat.Mode&ca.dstStat.Mode&unix.S_IFMT != unix.S_IFDIR
262
-
263
-	if !deleteOnly && !overwrite {
264
-		// nothing to delete, continue on
265
-		return false, nil
266
-	}
267
-
268
-	if err := os.RemoveAll(ca.dstPath); err != nil {
269
-		return false, errors.Wrap(err, "failed to remove during apply")
270
-	}
271
-	ca.dstStat = nil
272
-
273
-	if overwrite && a.createWhiteoutDelete && ca.srcStat.Mode&unix.S_IFMT == unix.S_IFDIR {
274
-		// If we are using an overlay snapshotter and overwriting an existing non-directory
275
-		// with a directory, we need this new dir to be opaque so that any files from lowerdirs
276
-		// under it are not visible.
277
-		ca.setOpaque = true
278
-	}
279
-
280
-	if deleteOnly && a.createWhiteoutDelete {
281
-		// only create a whiteout device if there is something to delete
282
-		var foundLower bool
283
-		for _, lowerdir := range a.lowerdirs {
284
-			lowerPath, err := safeJoin(lowerdir, ca.subPath)
285
-			if err != nil {
286
-				return false, errors.Wrapf(err, "failed to join lowerdir %q and subPath %q", lowerdir, ca.subPath)
287
-			}
288
-			if _, err := os.Lstat(lowerPath); err == nil {
289
-				foundLower = true
290
-				break
291
-			} else if !errors.Is(err, unix.ENOENT) && !errors.Is(err, unix.ENOTDIR) {
292
-				return false, errors.Wrapf(err, "failed to stat lowerPath %q", lowerPath)
293
-			}
294
-		}
295
-		if foundLower {
296
-			ca.kind = fs.ChangeKindAdd
297
-			if ca.srcStat == nil {
298
-				ca.srcStat = &syscall.Stat_t{
299
-					Mode: syscall.S_IFCHR,
300
-					Rdev: unix.Mkdev(0, 0),
301
-				}
302
-				ca.srcPath = ""
303
-			}
304
-			return false, nil
305
-		}
306
-	}
307
-
308
-	return deleteOnly, nil
309
-}
310
-
311
-func (a *applier) applyHardlink(ctx context.Context, ca *changeApply) (bool, error) {
312
-	switch ca.srcStat.Mode & unix.S_IFMT {
313
-	case unix.S_IFDIR, unix.S_IFIFO, unix.S_IFSOCK:
314
-		// Directories can't be hard-linked, so they just have to be recreated.
315
-		// Named pipes and sockets can be hard-linked but is best to avoid as it could enable IPC in weird cases.
316
-		return false, nil
317
-
318
-	default:
319
-		var linkSrcPath string
320
-		if ca.linkSubPath != "" {
321
-			// there's an already applied path that we should link from
322
-			path, err := safeJoin(a.root, ca.linkSubPath)
323
-			if err != nil {
324
-				return false, errors.Errorf("failed to get hardlink source path: %v", err)
325
-			}
326
-			linkSrcPath = path
327
-		} else if a.crossSnapshotLinks != nil {
328
-			// we can try to link across snapshots from the source file
329
-			linkSrcPath = ca.srcPath
330
-			a.crossSnapshotLinks[statInode(ca.srcStat)] = struct{}{}
331
-		}
332
-		if linkSrcPath == "" {
333
-			// nothing to hardlink from, will have to copy the file
334
-			return false, nil
335
-		}
336
-
337
-		if err := os.Link(linkSrcPath, ca.dstPath); errors.Is(err, unix.EXDEV) || errors.Is(err, unix.EMLINK) {
338
-			// These errors are expected when the hardlink would cross devices or would exceed the maximum number of links for the inode.
339
-			// Just fallback to a copy.
340
-			bklog.G(ctx).WithError(err).WithField("srcPath", linkSrcPath).WithField("dstPath", ca.dstPath).Debug("hardlink failed")
341
-			if a.crossSnapshotLinks != nil {
342
-				delete(a.crossSnapshotLinks, statInode(ca.srcStat))
343
-			}
344
-			return false, nil
345
-		} else if err != nil {
346
-			return false, errors.Wrap(err, "failed to hardlink during apply")
347
-		}
348
-
349
-		return true, nil
350
-	}
351
-}
352
-
353
-func (a *applier) applyCopy(ctx context.Context, ca *changeApply) error {
354
-	switch ca.srcStat.Mode & unix.S_IFMT {
355
-	case unix.S_IFREG:
356
-		if err := fs.CopyFile(ca.dstPath, ca.srcPath); err != nil {
357
-			return errors.Wrapf(err, "failed to copy from %s to %s during apply", ca.srcPath, ca.dstPath)
358
-		}
359
-	case unix.S_IFDIR:
360
-		if ca.dstStat == nil {
361
-			// dstPath doesn't exist, make it a dir
362
-			if err := unix.Mkdir(ca.dstPath, ca.srcStat.Mode); err != nil {
363
-				return errors.Wrapf(err, "failed to create applied dir at %q from %q", ca.dstPath, ca.srcPath)
364
-			}
365
-		}
366
-	case unix.S_IFLNK:
367
-		if target, err := os.Readlink(ca.srcPath); err != nil {
368
-			return errors.Wrap(err, "failed to read symlink during apply")
369
-		} else if err := os.Symlink(target, ca.dstPath); err != nil {
370
-			return errors.Wrap(err, "failed to create symlink during apply")
371
-		}
372
-	case unix.S_IFBLK, unix.S_IFCHR, unix.S_IFIFO, unix.S_IFSOCK:
373
-		if err := unix.Mknod(ca.dstPath, ca.srcStat.Mode, int(ca.srcStat.Rdev)); err != nil {
374
-			return errors.Wrap(err, "failed to mknod during apply")
375
-		}
376
-	default:
377
-		// should never be here, all types should be handled
378
-		return errors.Errorf("unhandled file type %d during merge at path %q", ca.srcStat.Mode&unix.S_IFMT, ca.srcPath)
379
-	}
380
-
381
-	// NOTE: it's important that chown happens before setting xattrs due to the fact that chown will
382
-	// reset the security.capabilities xattr which results in file capabilities being lost.
383
-	if err := os.Lchown(ca.dstPath, int(ca.srcStat.Uid), int(ca.srcStat.Gid)); err != nil {
384
-		return errors.Wrap(err, "failed to chown during apply")
385
-	}
386
-
387
-	if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFLNK {
388
-		if err := unix.Chmod(ca.dstPath, ca.srcStat.Mode); err != nil {
389
-			return errors.Wrapf(err, "failed to chmod path %q during apply", ca.dstPath)
390
-		}
391
-	}
392
-
393
-	if ca.srcPath != "" {
394
-		xattrs, err := sysx.LListxattr(ca.srcPath)
395
-		if err != nil {
396
-			return errors.Wrapf(err, "failed to list xattrs of src path %s", ca.srcPath)
397
-		}
398
-		for _, xattr := range xattrs {
399
-			if isOpaqueXattr(xattr) {
400
-				// Don't recreate opaque xattrs during merge based on the source file. The differs take care of converting
401
-				// source path from the "opaque whiteout" format to the "explicit whiteout" format. The only time we set
402
-				// opaque xattrs is handled after this loop below.
403
-				continue
404
-			}
405
-			xattrVal, err := sysx.LGetxattr(ca.srcPath, xattr)
406
-			if err != nil {
407
-				return errors.Wrapf(err, "failed to get xattr %s of src path %s", xattr, ca.srcPath)
408
-			}
409
-			if err := sysx.LSetxattr(ca.dstPath, xattr, xattrVal, 0); err != nil {
410
-				// This can often fail, so just log it: https://github.com/moby/buildkit/issues/1189
411
-				bklog.G(ctx).Debugf("failed to set xattr %s of path %s during apply", xattr, ca.dstPath)
412
-			}
413
-		}
414
-	}
415
-
416
-	if ca.setOpaque {
417
-		// This is set in the case where we are creating a directory that is replacing a whiteout device
418
-		xattr := opaqueXattr(a.userxattr)
419
-		if err := sysx.LSetxattr(ca.dstPath, xattr, []byte{'y'}, 0); err != nil {
420
-			return errors.Wrapf(err, "failed to set opaque xattr %q of path %s", xattr, ca.dstPath)
421
-		}
422
-	}
423
-
424
-	atimeSpec := unix.Timespec{Sec: ca.srcStat.Atim.Sec, Nsec: ca.srcStat.Atim.Nsec}
425
-	mtimeSpec := unix.Timespec{Sec: ca.srcStat.Mtim.Sec, Nsec: ca.srcStat.Mtim.Nsec}
426
-	if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFDIR {
427
-		// apply times immediately for non-dirs
428
-		if err := unix.UtimesNanoAt(unix.AT_FDCWD, ca.dstPath, []unix.Timespec{atimeSpec, mtimeSpec}, unix.AT_SYMLINK_NOFOLLOW); err != nil {
429
-			return err
430
-		}
431
-	} else {
432
-		// save the times we should set on this dir, to be applied after subfiles have been set
433
-		a.dirModTimes[ca.dstPath] = mtimeSpec
434
-	}
435
-
436
-	return nil
437
-}
438
-
439
-func (a *applier) Flush() error {
440
-	// Set dir times now that everything has been modified. Walk the filesystem tree to ensure
441
-	// that we never try to apply to a path that has been deleted or modified since times for it
442
-	// were stored. This is needed for corner cases such as where a parent dir is removed and
443
-	// replaced with a symlink.
444
-	return filepath.WalkDir(a.root, func(path string, d gofs.DirEntry, prevErr error) error {
445
-		if prevErr != nil {
446
-			return prevErr
447
-		}
448
-		if !d.IsDir() {
449
-			return nil
450
-		}
451
-		if mtime, ok := a.dirModTimes[path]; ok {
452
-			if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, []unix.Timespec{{Nsec: unix.UTIME_OMIT}, mtime}, unix.AT_SYMLINK_NOFOLLOW); err != nil {
453
-				return err
454
-			}
455
-		}
456
-		return nil
457
-	})
458
-}
459
-
460
-func (a *applier) Release() error {
461
-	if a.release != nil {
462
-		err := a.release()
463
-		if err != nil {
464
-			return err
465
-		}
466
-	}
467
-	a.release = nil
468
-	return nil
469
-}
470
-
471
-func (a *applier) Usage() (snapshots.Usage, error) {
472
-	// Calculate the disk space used under the apply root, similar to the normal containerd snapshotter disk usage
473
-	// calculations but with the extra ability to take into account hardlinks that were created between snapshots, ensuring that
474
-	// they don't get double counted.
475
-	inodes := make(map[inode]struct{})
476
-	var usage snapshots.Usage
477
-	if err := filepath.WalkDir(a.root, func(path string, dirent gofs.DirEntry, err error) error {
478
-		if err != nil {
479
-			return err
480
-		}
481
-		info, err := dirent.Info()
482
-		if err != nil {
483
-			return err
484
-		}
485
-		stat := info.Sys().(*syscall.Stat_t)
486
-		inode := statInode(stat)
487
-		if _, ok := inodes[inode]; ok {
488
-			return nil
489
-		}
490
-		inodes[inode] = struct{}{}
491
-		if a.crossSnapshotLinks != nil {
492
-			if _, ok := a.crossSnapshotLinks[statInode(stat)]; ok {
493
-				// don't count cross-snapshot hardlinks
494
-				return nil
495
-			}
496
-		}
497
-		usage.Inodes++
498
-		usage.Size += stat.Blocks * 512 // 512 is always block size, see "man 2 stat"
499
-		return nil
500
-	}); err != nil {
501
-		return snapshots.Usage{}, err
502
-	}
503
-	return usage, nil
504
-}
505
-
506
-type differ struct {
507
-	lowerRoot    string
508
-	releaseLower func() error
509
-
510
-	upperRoot    string
511
-	releaseUpper func() error
512
-
513
-	upperBindSource  string
514
-	upperOverlayDirs []string // ordered lowest -> highest
515
-
516
-	upperdir string
517
-
518
-	visited map[string]struct{} // set of parent subPaths that have been visited
519
-	inodes  map[inode]string    // map of inode -> subPath
520
-}
521
-
522
-func differFor(lowerMntable, upperMntable Mountable) (_ *differ, rerr error) {
523
-	d := &differ{
524
-		visited: make(map[string]struct{}),
525
-		inodes:  make(map[inode]string),
526
-	}
527
-	defer func() {
528
-		if rerr != nil {
529
-			rerr = multierror.Append(rerr, d.Release()).ErrorOrNil()
530
-		}
531
-	}()
532
-
533
-	var lowerMnts []mount.Mount
534
-	if lowerMntable != nil {
535
-		mnts, release, err := lowerMntable.Mount()
536
-		if err != nil {
537
-			return nil, err
538
-		}
539
-		mounter := LocalMounterWithMounts(mnts)
540
-		root, err := mounter.Mount()
541
-		if err != nil {
542
-			return nil, err
543
-		}
544
-		d.lowerRoot = root
545
-		lowerMnts = mnts
546
-		d.releaseLower = func() error {
547
-			err := mounter.Unmount()
548
-			return multierror.Append(err, release()).ErrorOrNil()
549
-		}
550
-	}
551
-
552
-	var upperMnts []mount.Mount
553
-	if upperMntable != nil {
554
-		mnts, release, err := upperMntable.Mount()
555
-		if err != nil {
556
-			return nil, err
557
-		}
558
-		mounter := LocalMounterWithMounts(mnts)
559
-		root, err := mounter.Mount()
560
-		if err != nil {
561
-			return nil, err
562
-		}
563
-		d.upperRoot = root
564
-		upperMnts = mnts
565
-		d.releaseUpper = func() error {
566
-			err := mounter.Unmount()
567
-			return multierror.Append(err, release()).ErrorOrNil()
568
-		}
569
-	}
570
-
571
-	if len(upperMnts) == 1 {
572
-		if upperMnts[0].Type == "bind" || upperMnts[0].Type == "rbind" {
573
-			d.upperBindSource = upperMnts[0].Source
574
-		} else if overlay.IsOverlayMountType(upperMnts[0]) {
575
-			overlayDirs, err := overlay.GetOverlayLayers(upperMnts[0])
576
-			if err != nil {
577
-				return nil, errors.Wrapf(err, "failed to get overlay layers from mount %+v", upperMnts[0])
578
-			}
579
-			d.upperOverlayDirs = overlayDirs
580
-		}
581
-	}
582
-	if len(lowerMnts) > 0 {
583
-		if upperdir, err := overlay.GetUpperdir(lowerMnts, upperMnts); err == nil {
584
-			d.upperdir = upperdir
585
-		}
586
-	}
587
-
588
-	return d, nil
589
-}
590
-
591
-func (d *differ) HandleChanges(ctx context.Context, handle func(context.Context, *change) error) error {
592
-	if d.upperdir != "" {
593
-		return d.overlayChanges(ctx, handle)
594
-	}
595
-	return d.doubleWalkingChanges(ctx, handle)
596
-}
597
-
598
-func (d *differ) doubleWalkingChanges(ctx context.Context, handle func(context.Context, *change) error) error {
599
-	return fs.Changes(ctx, d.lowerRoot, d.upperRoot, func(kind fs.ChangeKind, subPath string, srcfi os.FileInfo, prevErr error) error {
600
-		if prevErr != nil {
601
-			return prevErr
602
-		}
603
-		select {
604
-		case <-ctx.Done():
605
-			return context.Cause(ctx)
606
-		default:
607
-		}
608
-
609
-		if kind == fs.ChangeKindUnmodified {
610
-			return nil
611
-		}
612
-
613
-		// NOTE: it's tempting to skip creating parent dirs when change kind is Delete, but
614
-		// that would make us incompatible with the image exporter code:
615
-		// https://github.com/containerd/containerd/pull/2095
616
-		if err := d.checkParent(ctx, subPath, handle); err != nil {
617
-			return errors.Wrapf(err, "failed to check parent for %s", subPath)
618
-		}
619
-
620
-		c := &change{
621
-			kind:    kind,
622
-			subPath: subPath,
623
-		}
624
-
625
-		if srcfi != nil {
626
-			// Try to ensure that srcPath and srcStat are set to a file from the underlying filesystem
627
-			// rather than the actual mount when possible. This allows hardlinking without getting EXDEV.
628
-			switch {
629
-			case !srcfi.IsDir() && d.upperBindSource != "":
630
-				srcPath, err := safeJoin(d.upperBindSource, c.subPath)
631
-				if err != nil {
632
-					return errors.Wrapf(err, "failed to join %s and %s", d.upperBindSource, c.subPath)
633
-				}
634
-				c.srcPath = srcPath
635
-				if fi, err := os.Lstat(c.srcPath); err == nil {
636
-					srcfi = fi
637
-				} else {
638
-					return errors.Wrap(err, "failed to stat underlying file from bind mount")
639
-				}
640
-			case !srcfi.IsDir() && len(d.upperOverlayDirs) > 0:
641
-				for i := range d.upperOverlayDirs {
642
-					dir := d.upperOverlayDirs[len(d.upperOverlayDirs)-1-i]
643
-					path, err := safeJoin(dir, c.subPath)
644
-					if err != nil {
645
-						return errors.Wrapf(err, "failed to join %s and %s", dir, c.subPath)
646
-					}
647
-					if stat, err := os.Lstat(path); err == nil {
648
-						c.srcPath = path
649
-						srcfi = stat
650
-						break
651
-					} else if errors.Is(err, unix.ENOENT) {
652
-						continue
653
-					} else {
654
-						return errors.Wrap(err, "failed to lstat when finding direct path of overlay file")
655
-					}
656
-				}
657
-			default:
658
-				srcPath, err := safeJoin(d.upperRoot, subPath)
659
-				if err != nil {
660
-					return errors.Wrapf(err, "failed to join %s and %s", d.upperRoot, subPath)
661
-				}
662
-				c.srcPath = srcPath
663
-				if fi, err := os.Lstat(c.srcPath); err == nil {
664
-					srcfi = fi
665
-				} else {
666
-					return errors.Wrap(err, "failed to stat srcPath from differ")
667
-				}
668
-			}
669
-
670
-			var ok bool
671
-			c.srcStat, ok = srcfi.Sys().(*syscall.Stat_t)
672
-			if !ok {
673
-				return errors.Errorf("unhandled stat type for %+v", srcfi)
674
-			}
675
-
676
-			if !srcfi.IsDir() && c.srcStat.Nlink > 1 {
677
-				if linkSubPath, ok := d.inodes[statInode(c.srcStat)]; ok {
678
-					c.linkSubPath = linkSubPath
679
-				} else {
680
-					d.inodes[statInode(c.srcStat)] = c.subPath
681
-				}
682
-			}
683
-		}
684
-
685
-		return handle(ctx, c)
686
-	})
687
-}
688
-
689
-func (d *differ) overlayChanges(ctx context.Context, handle func(context.Context, *change) error) error {
690
-	return overlay.Changes(ctx, func(kind fs.ChangeKind, subPath string, srcfi os.FileInfo, prevErr error) error {
691
-		if prevErr != nil {
692
-			return prevErr
693
-		}
694
-
695
-		select {
696
-		case <-ctx.Done():
697
-			return context.Cause(ctx)
698
-		default:
699
-		}
700
-
701
-		if kind == fs.ChangeKindUnmodified {
702
-			return nil
703
-		}
704
-
705
-		if err := d.checkParent(ctx, subPath, handle); err != nil {
706
-			return errors.Wrapf(err, "failed to check parent for %s", subPath)
707
-		}
708
-
709
-		srcPath, err := safeJoin(d.upperdir, subPath)
710
-		if err != nil {
711
-			return errors.Wrapf(err, "failed to join %s and %s", d.upperdir, subPath)
712
-		}
713
-
714
-		c := &change{
715
-			kind:    kind,
716
-			subPath: subPath,
717
-			srcPath: srcPath,
718
-		}
719
-
720
-		if srcfi != nil {
721
-			var ok bool
722
-			c.srcStat, ok = srcfi.Sys().(*syscall.Stat_t)
723
-			if !ok {
724
-				return errors.Errorf("unhandled stat type for %+v", srcfi)
725
-			}
726
-
727
-			// Changes with Delete kind may share the same inode even if they are unrelated.
728
-			// Skip them to avoid creating hardlinks between whiteouts as whiteouts are not
729
-			// always created and may leave the hardlink dangling.
730
-			if !srcfi.IsDir() && c.srcStat.Nlink > 1 && c.kind != fs.ChangeKindDelete {
731
-				if linkSubPath, ok := d.inodes[statInode(c.srcStat)]; ok {
732
-					c.linkSubPath = linkSubPath
733
-				} else {
734
-					d.inodes[statInode(c.srcStat)] = c.subPath
735
-				}
736
-			}
737
-		}
738
-
739
-		return handle(ctx, c)
740
-	}, d.upperdir, d.upperRoot, d.lowerRoot)
741
-}
742
-
743
-func (d *differ) checkParent(ctx context.Context, subPath string, handle func(context.Context, *change) error) error {
744
-	parentSubPath := filepath.Dir(subPath)
745
-	if parentSubPath == "/" {
746
-		return nil
747
-	}
748
-	if _, ok := d.visited[parentSubPath]; ok {
749
-		return nil
750
-	}
751
-	d.visited[parentSubPath] = struct{}{}
752
-
753
-	if err := d.checkParent(ctx, parentSubPath, handle); err != nil {
754
-		return err
755
-	}
756
-	parentSrcPath, err := safeJoin(d.upperRoot, parentSubPath)
757
-	if err != nil {
758
-		return err
759
-	}
760
-	srcfi, err := os.Lstat(parentSrcPath)
761
-	if err != nil {
762
-		return err
763
-	}
764
-	parentSrcStat, ok := srcfi.Sys().(*syscall.Stat_t)
765
-	if !ok {
766
-		return errors.Errorf("unexpected type %T", srcfi)
767
-	}
768
-	return handle(ctx, &change{
769
-		kind:    fs.ChangeKindModify,
770
-		subPath: parentSubPath,
771
-		srcPath: parentSrcPath,
772
-		srcStat: parentSrcStat,
773
-	})
774
-}
775
-
776
-func (d *differ) Release() error {
777
-	var err error
778
-	if d.releaseLower != nil {
779
-		err = d.releaseLower()
780
-		if err == nil {
781
-			d.releaseLower = nil
782
-		}
783
-	}
784
-	if d.releaseUpper != nil {
785
-		err = multierror.Append(err, d.releaseUpper()).ErrorOrNil()
786
-		if err == nil {
787
-			d.releaseUpper = nil
788
-		}
789
-	}
790
-	return err
791
-}
792
-
793
-func safeJoin(root, path string) (string, error) {
794
-	dir, base := filepath.Split(path)
795
-	parent, err := fs.RootPath(root, dir)
796
-	if err != nil {
797
-		return "", err
798
-	}
799
-	return filepath.Join(parent, base), nil
800
-}
801
-
802
-const (
803
-	trustedOpaqueXattr = "trusted.overlay.opaque"
804
-	userOpaqueXattr    = "user.overlay.opaque"
805
-)
806
-
807
-func isOpaqueXattr(s string) bool {
808
-	for _, k := range []string{trustedOpaqueXattr, userOpaqueXattr} {
809
-		if s == k {
810
-			return true
811
-		}
812
-	}
813
-	return false
814
-}
815
-
816
-func opaqueXattr(userxattr bool) string {
817
-	if userxattr {
818
-		return userOpaqueXattr
819
-	}
820
-	return trustedOpaqueXattr
821
-}
822
-
823
-// needsUserXAttr checks whether overlay mounts should be provided the userxattr option. We can't use
824
-// NeedsUserXAttr from the overlayutils package directly because we don't always have direct knowledge
825
-// of the root of the snapshotter state (such as when using a remote snapshotter). Instead, we create
826
-// a temporary new snapshot and test using its root, which works because single layer snapshots will
827
-// use bind-mounts even when created by an overlay based snapshotter.
828
-func needsUserXAttr(ctx context.Context, sn Snapshotter, lm leases.Manager) (bool, error) {
829
-	key := identity.NewID()
830
-
831
-	ctx, done, err := leaseutil.WithLease(ctx, lm, leaseutil.MakeTemporary)
832
-	if err != nil {
833
-		return false, errors.Wrap(err, "failed to create lease for checking user xattr")
834
-	}
835
-	defer done(context.TODO())
836
-
837
-	err = sn.Prepare(ctx, key, "")
838
-	if err != nil {
839
-		return false, err
840
-	}
841
-	mntable, err := sn.Mounts(ctx, key)
842
-	if err != nil {
843
-		return false, err
844
-	}
845
-	mnts, unmount, err := mntable.Mount()
846
-	if err != nil {
847
-		return false, err
848
-	}
849
-	defer unmount()
850
-
851
-	var userxattr bool
852
-	if err := mount.WithTempMount(ctx, mnts, func(root string) error {
853
-		var err error
854
-		userxattr, err = overlayutils.NeedsUserXAttr(root)
855
-		return err
856
-	}); err != nil {
857
-		return false, err
858
-	}
859
-	return userxattr, nil
860
-}
861 1
new file mode 100644
... ...
@@ -0,0 +1,21 @@
0
+//go:build !linux
1
+// +build !linux
2
+
3
+package snapshot
4
+
5
+import (
6
+	"context"
7
+	"runtime"
8
+
9
+	"github.com/containerd/containerd/leases"
10
+	"github.com/containerd/containerd/snapshots"
11
+	"github.com/pkg/errors"
12
+)
13
+
14
+func (sn *mergeSnapshotter) diffApply(_ context.Context, _ Mountable, _ ...Diff) (_ snapshots.Usage, rerr error) {
15
+	return snapshots.Usage{}, errors.New("diffApply not yet supported on " + runtime.GOOS)
16
+}
17
+
18
+func needsUserXAttr(_ context.Context, _ Snapshotter, _ leases.Manager) (bool, error) {
19
+	return false, errors.New("needs userxattr not supported on " + runtime.GOOS)
20
+}
0 21
deleted file mode 100644
... ...
@@ -1,20 +0,0 @@
1
-//go:build windows
2
-// +build windows
3
-
4
-package snapshot
5
-
6
-import (
7
-	"context"
8
-
9
-	"github.com/containerd/containerd/leases"
10
-	"github.com/containerd/containerd/snapshots"
11
-	"github.com/pkg/errors"
12
-)
13
-
14
-func (sn *mergeSnapshotter) diffApply(_ context.Context, _ Mountable, _ ...Diff) (_ snapshots.Usage, rerr error) {
15
-	return snapshots.Usage{}, errors.New("diffApply not yet supported on windows")
16
-}
17
-
18
-func needsUserXAttr(_ context.Context, _ Snapshotter, _ leases.Manager) (bool, error) {
19
-	return false, errors.New("needs userxattr not supported on windows")
20
-}
... ...
@@ -6,8 +6,8 @@ import (
6 6
 	"syscall"
7 7
 
8 8
 	"github.com/containerd/containerd/mount"
9
-	"github.com/containerd/containerd/pkg/userns"
10 9
 	rootlessmountopts "github.com/moby/buildkit/util/rootless/mountopts"
10
+	"github.com/moby/sys/userns"
11 11
 	"github.com/pkg/errors"
12 12
 )
13 13
 
... ...
@@ -5,11 +5,11 @@ import (
5 5
 	"strconv"
6 6
 
7 7
 	"github.com/containerd/containerd/leases"
8
-	"github.com/containerd/containerd/pkg/userns"
9 8
 	"github.com/containerd/containerd/snapshots"
10 9
 	"github.com/moby/buildkit/identity"
11 10
 	"github.com/moby/buildkit/util/bklog"
12 11
 	"github.com/moby/buildkit/util/leaseutil"
12
+	"github.com/moby/sys/userns"
13 13
 	"github.com/pkg/errors"
14 14
 )
15 15
 
... ...
@@ -7,10 +7,10 @@ import (
7 7
 	"sync"
8 8
 
9 9
 	"github.com/containerd/containerd/mount"
10
-	"github.com/containerd/containerd/pkg/userns"
11 10
 	"github.com/containerd/containerd/snapshots"
12 11
 	"github.com/docker/docker/pkg/idtools"
13 12
 	"github.com/moby/buildkit/executor"
13
+	"github.com/moby/sys/userns"
14 14
 	"github.com/pkg/errors"
15 15
 )
16 16
 
... ...
@@ -9,6 +9,8 @@ import (
9 9
 	"github.com/moby/buildkit/identity"
10 10
 	"github.com/moby/buildkit/solver"
11 11
 	"github.com/moby/buildkit/util/bklog"
12
+	"github.com/moby/buildkit/util/db"
13
+	"github.com/moby/buildkit/util/db/boltutil"
12 14
 	digest "github.com/opencontainers/go-digest"
13 15
 	"github.com/pkg/errors"
14 16
 	bolt "go.etcd.io/bbolt"
... ...
@@ -22,11 +24,13 @@ const (
22 22
 )
23 23
 
24 24
 type Store struct {
25
-	db *bolt.DB
25
+	db db.DB
26 26
 }
27 27
 
28 28
 func NewStore(dbPath string) (*Store, error) {
29
-	db, err := safeOpenDB(dbPath)
29
+	db, err := safeOpenDB(dbPath, &bolt.Options{
30
+		NoSync: true,
31
+	})
30 32
 	if err != nil {
31 33
 		return nil, err
32 34
 	}
... ...
@@ -42,7 +46,6 @@ func NewStore(dbPath string) (*Store, error) {
42 42
 	}); err != nil {
43 43
 		return nil, err
44 44
 	}
45
-	db.NoSync = true
46 45
 	return &Store{db: db}, nil
47 46
 }
48 47
 
... ...
@@ -465,7 +468,7 @@ func isEmptyBucket(b *bolt.Bucket) bool {
465 465
 
466 466
 // safeOpenDB opens a bolt database and recovers from panic that
467 467
 // can be caused by a corrupted database file.
468
-func safeOpenDB(dbPath string) (db *bolt.DB, err error) {
468
+func safeOpenDB(dbPath string, opts *bolt.Options) (db db.DB, err error) {
469 469
 	defer func() {
470 470
 		if r := recover(); r != nil {
471 471
 			err = errors.Errorf("%v", r)
... ...
@@ -476,16 +479,16 @@ func safeOpenDB(dbPath string) (db *bolt.DB, err error) {
476 476
 		// then fallback to resetting the database since the database
477 477
 		// may be corrupt.
478 478
 		if err != nil && fileHasContent(dbPath) {
479
-			db, err = fallbackOpenDB(dbPath, err)
479
+			db, err = fallbackOpenDB(dbPath, opts, err)
480 480
 		}
481 481
 	}()
482
-	return openDB(dbPath)
482
+	return openDB(dbPath, opts)
483 483
 }
484 484
 
485 485
 // fallbackOpenDB performs database recovery and opens the new database
486 486
 // file when the database fails to open. Called after the first database
487 487
 // open fails.
488
-func fallbackOpenDB(dbPath string, openErr error) (*bolt.DB, error) {
488
+func fallbackOpenDB(dbPath string, opts *bolt.Options, openErr error) (db.DB, error) {
489 489
 	backupPath := dbPath + "." + identity.NewID() + ".bak"
490 490
 	bklog.L.Errorf("failed to open database file %s, resetting to empty. Old database is backed up to %s. "+
491 491
 		"This error signifies that buildkitd likely crashed or was sigkilled abrubtly, leaving the database corrupted. "+
... ...
@@ -496,12 +499,12 @@ func fallbackOpenDB(dbPath string, openErr error) (*bolt.DB, error) {
496 496
 
497 497
 	// Attempt to open the database again. This should be a new database.
498 498
 	// If this fails, it is a permanent error.
499
-	return openDB(dbPath)
499
+	return openDB(dbPath, opts)
500 500
 }
501 501
 
502 502
 // openDB opens a bolt database in user-only read/write mode.
503
-func openDB(dbPath string) (*bolt.DB, error) {
504
-	return bolt.Open(dbPath, 0600, nil)
503
+func openDB(dbPath string, opts *bolt.Options) (db.DB, error) {
504
+	return boltutil.Open(dbPath, 0600, opts)
505 505
 }
506 506
 
507 507
 // fileHasContent checks if we have access to the file with appropriate
... ...
@@ -27,10 +27,17 @@ func timestampToTime(ts int64) *time.Time {
27 27
 	return &tm
28 28
 }
29 29
 
30
-func mkdir(d string, action pb.FileActionMkDir, user *copy.User, idmap *idtools.IdentityMapping) error {
30
+func mkdir(d string, action pb.FileActionMkDir, user *copy.User, idmap *idtools.IdentityMapping) (err error) {
31
+	defer func() {
32
+		var osErr *os.PathError
33
+		if errors.As(err, &osErr) {
34
+			osErr.Path = strings.TrimPrefix(osErr.Path, d)
35
+		}
36
+	}()
37
+
31 38
 	p, err := fs.RootPath(d, action.Path)
32 39
 	if err != nil {
33
-		return err
40
+		return errors.WithStack(err)
34 41
 	}
35 42
 
36 43
 	ch, err := mapUserToChowner(user, idmap)
... ...
@@ -47,23 +54,31 @@ func mkdir(d string, action pb.FileActionMkDir, user *copy.User, idmap *idtools.
47 47
 			if errors.Is(err, os.ErrExist) {
48 48
 				return nil
49 49
 			}
50
-			return err
50
+			return errors.WithStack(err)
51 51
 		}
52 52
 		if err := copy.Chown(p, nil, ch); err != nil {
53
-			return err
53
+			return errors.WithStack(err)
54 54
 		}
55 55
 		if err := copy.Utimes(p, timestampToTime(action.Timestamp)); err != nil {
56
-			return err
56
+			return errors.WithStack(err)
57 57
 		}
58 58
 	}
59 59
 
60 60
 	return nil
61 61
 }
62 62
 
63
-func mkfile(d string, action pb.FileActionMkFile, user *copy.User, idmap *idtools.IdentityMapping) error {
63
+func mkfile(d string, action pb.FileActionMkFile, user *copy.User, idmap *idtools.IdentityMapping) (err error) {
64
+	defer func() {
65
+		var osErr *os.PathError
66
+		if errors.As(err, &osErr) {
67
+			// remove system root from error path if present
68
+			osErr.Path = strings.TrimPrefix(osErr.Path, d)
69
+		}
70
+	}()
71
+
64 72
 	p, err := fs.RootPath(d, filepath.Join("/", action.Path))
65 73
 	if err != nil {
66
-		return err
74
+		return errors.WithStack(err)
67 75
 	}
68 76
 
69 77
 	ch, err := mapUserToChowner(user, idmap)
... ...
@@ -72,21 +87,29 @@ func mkfile(d string, action pb.FileActionMkFile, user *copy.User, idmap *idtool
72 72
 	}
73 73
 
74 74
 	if err := os.WriteFile(p, action.Data, os.FileMode(action.Mode)&0777); err != nil {
75
-		return err
75
+		return errors.WithStack(err)
76 76
 	}
77 77
 
78 78
 	if err := copy.Chown(p, nil, ch); err != nil {
79
-		return err
79
+		return errors.WithStack(err)
80 80
 	}
81 81
 
82 82
 	if err := copy.Utimes(p, timestampToTime(action.Timestamp)); err != nil {
83
-		return err
83
+		return errors.WithStack(err)
84 84
 	}
85 85
 
86 86
 	return nil
87 87
 }
88 88
 
89
-func rm(d string, action pb.FileActionRm) error {
89
+func rm(d string, action pb.FileActionRm) (err error) {
90
+	defer func() {
91
+		var osErr *os.PathError
92
+		if errors.As(err, &osErr) {
93
+			// remove system root from error path if present
94
+			osErr.Path = strings.TrimPrefix(osErr.Path, d)
95
+		}
96
+	}()
97
+
90 98
 	if action.AllowWildcard {
91 99
 		src, err := cleanPath(action.Path)
92 100
 		if err != nil {
... ...
@@ -94,7 +117,7 @@ func rm(d string, action pb.FileActionRm) error {
94 94
 		}
95 95
 		m, err := copy.ResolveWildcards(d, src, false)
96 96
 		if err != nil {
97
-			return err
97
+			return errors.WithStack(err)
98 98
 		}
99 99
 
100 100
 		for _, s := range m {
... ...
@@ -117,7 +140,7 @@ func rmPath(root, src string, allowNotFound bool) error {
117 117
 	}
118 118
 	dir, err := fs.RootPath(root, filepath.Join("/", dir))
119 119
 	if err != nil {
120
-		return err
120
+		return errors.WithStack(err)
121 121
 	}
122 122
 	p := filepath.Join(dir, base)
123 123
 
... ...
@@ -125,14 +148,14 @@ func rmPath(root, src string, allowNotFound bool) error {
125 125
 		_, err := os.Stat(p)
126 126
 
127 127
 		if errors.Is(err, os.ErrNotExist) {
128
-			return err
128
+			return errors.WithStack(err)
129 129
 		}
130 130
 	}
131 131
 
132
-	return os.RemoveAll(p)
132
+	return errors.WithStack(os.RemoveAll(p))
133 133
 }
134 134
 
135
-func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *copy.User, idmap *idtools.IdentityMapping) error {
135
+func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *copy.User, idmap *idtools.IdentityMapping) (err error) {
136 136
 	srcPath, err := cleanPath(action.Src)
137 137
 	if err != nil {
138 138
 		return errors.Wrap(err, "cleaning source path")
... ...
@@ -144,7 +167,7 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *
144 144
 	if !action.CreateDestPath {
145 145
 		p, err := fs.RootPath(dest, filepath.Join("/", action.Dest))
146 146
 		if err != nil {
147
-			return err
147
+			return errors.WithStack(err)
148 148
 		}
149 149
 		if _, err := os.Lstat(filepath.Dir(p)); err != nil {
150 150
 			return errors.Wrapf(err, "failed to stat %s", action.Dest)
... ...
@@ -177,6 +200,15 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *
177 177
 		copy.WithXAttrErrorHandler(xattrErrorHandler),
178 178
 	}
179 179
 
180
+	defer func() {
181
+		var osErr *os.PathError
182
+		if errors.As(err, &osErr) {
183
+			// remove system root from error path if present
184
+			osErr.Path = strings.TrimPrefix(osErr.Path, src)
185
+			osErr.Path = strings.TrimPrefix(osErr.Path, dest)
186
+		}
187
+	}()
188
+
180 189
 	var m []string
181 190
 	if !action.AllowWildcard {
182 191
 		m = []string{srcPath}
... ...
@@ -184,7 +216,7 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *
184 184
 		var err error
185 185
 		m, err = copy.ResolveWildcards(src, srcPath, action.FollowSymlink)
186 186
 		if err != nil {
187
-			return err
187
+			return errors.WithStack(err)
188 188
 		}
189 189
 
190 190
 		if len(m) == 0 {
... ...
@@ -198,13 +230,13 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *
198 198
 	for _, s := range m {
199 199
 		if action.AttemptUnpackDockerCompatibility {
200 200
 			if ok, err := unpack(src, s, dest, destPath, ch, timestampToTime(action.Timestamp), idmap); err != nil {
201
-				return err
201
+				return errors.WithStack(err)
202 202
 			} else if ok {
203 203
 				continue
204 204
 			}
205 205
 		}
206 206
 		if err := copy.Copy(ctx, src, s, dest, destPath, opt...); err != nil {
207
-			return err
207
+			return errors.WithStack(err)
208 208
 		}
209 209
 	}
210 210
 
... ...
@@ -5,6 +5,7 @@ package file
5 5
 
6 6
 import (
7 7
 	"github.com/docker/docker/pkg/idtools"
8
+	"github.com/pkg/errors"
8 9
 	copy "github.com/tonistiigi/fsutil/copy"
9 10
 )
10 11
 
... ...
@@ -23,7 +24,7 @@ func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Cho
23 23
 						GID: old.GID,
24 24
 					})
25 25
 					if err != nil {
26
-						return nil, err
26
+						return nil, errors.WithStack(err)
27 27
 					}
28 28
 					return &copy.User{UID: identity.UID, GID: identity.GID}, nil
29 29
 				}
... ...
@@ -38,7 +39,7 @@ func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Cho
38 38
 			GID: user.GID,
39 39
 		})
40 40
 		if err != nil {
41
-			return nil, err
41
+			return nil, errors.WithStack(err)
42 42
 		}
43 43
 		u.UID = identity.UID
44 44
 		u.GID = identity.GID
... ...
@@ -22,6 +22,7 @@ import (
22 22
 	"github.com/moby/buildkit/cmd/buildkitd/config"
23 23
 	"github.com/moby/buildkit/identity"
24 24
 	containerdsnapshot "github.com/moby/buildkit/snapshot/containerd"
25
+	"github.com/moby/buildkit/util/db"
25 26
 	"github.com/moby/buildkit/util/grpcerrors"
26 27
 	"github.com/moby/buildkit/util/iohelper"
27 28
 	"github.com/moby/buildkit/util/leaseutil"
... ...
@@ -39,7 +40,7 @@ const (
39 39
 )
40 40
 
41 41
 type HistoryQueueOpt struct {
42
-	DB           *bolt.DB
42
+	DB           db.Transactor
43 43
 	LeaseManager *leaseutil.Manager
44 44
 	ContentStore *containerdsnapshot.Store
45 45
 	CleanConfig  *config.HistoryConfig
... ...
@@ -71,6 +72,7 @@ type StatusImportResult struct {
71 71
 	NumCachedSteps    int
72 72
 	NumCompletedSteps int
73 73
 	NumTotalSteps     int
74
+	NumWarnings       int
74 75
 }
75 76
 
76 77
 func NewHistoryQueue(opt HistoryQueueOpt) (*HistoryQueue, error) {
... ...
@@ -779,9 +781,11 @@ func (h *HistoryQueue) ImportStatus(ctx context.Context, ch chan *client.SolveSt
779 779
 		completed bool
780 780
 	}
781 781
 	vtxMap := make(map[digest.Digest]*vtxInfo)
782
+	var numWarnings int
782 783
 
783 784
 	buf := make([]byte, 32*1024)
784 785
 	for st := range ch {
786
+		numWarnings += len(st.Warnings)
785 787
 		for _, vtx := range st.Vertexes {
786 788
 			if _, ok := vtxMap[vtx.Digest]; !ok {
787 789
 				vtxMap[vtx.Digest] = &vtxInfo{}
... ...
@@ -837,6 +841,7 @@ func (h *HistoryQueue) ImportStatus(ctx context.Context, ch chan *client.SolveSt
837 837
 		NumCachedSteps:    numCached,
838 838
 		NumCompletedSteps: numCompleted,
839 839
 		NumTotalSteps:     len(vtxMap),
840
+		NumWarnings:       numWarnings,
840 841
 	}, release, nil
841 842
 }
842 843
 
... ...
@@ -11,7 +11,6 @@ import (
11 11
 	"github.com/moby/buildkit/util/bklog"
12 12
 
13 13
 	"github.com/containerd/containerd/mount"
14
-	"github.com/containerd/containerd/pkg/userns"
15 14
 	"github.com/docker/docker/pkg/idtools"
16 15
 	"github.com/moby/buildkit/cache"
17 16
 	"github.com/moby/buildkit/client"
... ...
@@ -23,6 +22,7 @@ import (
23 23
 	"github.com/moby/buildkit/solver/pb"
24 24
 	"github.com/moby/buildkit/util/grpcerrors"
25 25
 	"github.com/moby/locker"
26
+	"github.com/moby/sys/userns"
26 27
 	"github.com/pkg/errors"
27 28
 	"google.golang.org/grpc/codes"
28 29
 )
... ...
@@ -169,7 +169,7 @@ func (f *fileOp) Exec(ctx context.Context, g session.Group, inputs []solver.Resu
169 169
 
170 170
 	backend, err := file.NewFileOpBackend(getReadUserFn(f.w))
171 171
 	if err != nil {
172
-		return nil, err
172
+		return nil, errors.WithStack(err)
173 173
 	}
174 174
 
175 175
 	fs := NewFileOpSolver(f.w, backend, f.refManager)
... ...
@@ -474,7 +474,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp
474 474
 				if inp.ref != nil {
475 475
 					m, err := s.r.Prepare(ctx, inp.ref, false, g)
476 476
 					if err != nil {
477
-						return err
477
+						return errors.WithStack(err)
478 478
 					}
479 479
 					inpMount = m
480 480
 					return nil
... ...
@@ -493,7 +493,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp
493 493
 				if inp.ref != nil {
494 494
 					m, err := s.r.Prepare(ctx, inp.ref, true, g)
495 495
 					if err != nil {
496
-						return err
496
+						return errors.WithStack(err)
497 497
 					}
498 498
 					inpMountSecondary = m
499 499
 					toRelease = append(toRelease, m)
... ...
@@ -521,7 +521,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp
521 521
 				if inp.ref != nil {
522 522
 					mm, err := s.r.Prepare(ctx, inp.ref, true, g)
523 523
 					if err != nil {
524
-						return nil, err
524
+						return nil, errors.WithStack(err)
525 525
 					}
526 526
 					toRelease = append(toRelease, mm)
527 527
 					m = mm
... ...
@@ -572,7 +572,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp
572 572
 		if inpMount == nil {
573 573
 			m, err := s.r.Prepare(ctx, nil, false, g)
574 574
 			if err != nil {
575
-				return input{}, err
575
+				return input{}, errors.WithStack(err)
576 576
 			}
577 577
 			inpMount = m
578 578
 		}
... ...
@@ -18,6 +18,7 @@ import (
18 18
 	"github.com/moby/buildkit/cache/remotecache"
19 19
 	"github.com/moby/buildkit/client"
20 20
 	controlgateway "github.com/moby/buildkit/control/gateway"
21
+	"github.com/moby/buildkit/errdefs"
21 22
 	"github.com/moby/buildkit/executor/resources"
22 23
 	resourcestypes "github.com/moby/buildkit/executor/resources/types"
23 24
 	"github.com/moby/buildkit/exporter"
... ...
@@ -158,7 +159,7 @@ func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge {
158 158
 func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend.SolveRequest, exp ExporterRequest, j *solver.Job, usage *resources.SysSampler) (func(context.Context, *Result, []exporter.DescriptorReference, error) error, error) {
159 159
 	stopTrace, err := detect.Recorder.Record(ctx)
160 160
 	if err != nil {
161
-		return nil, err
161
+		return nil, errdefs.Internal(err)
162 162
 	}
163 163
 
164 164
 	st := time.Now()
... ...
@@ -183,7 +184,7 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend
183 183
 		if stopTrace != nil {
184 184
 			stopTrace()
185 185
 		}
186
-		return nil, err
186
+		return nil, errdefs.Internal(err)
187 187
 	}
188 188
 
189 189
 	return func(ctx context.Context, res *Result, descrefs []exporter.DescriptorReference, err error) error {
... ...
@@ -329,6 +330,7 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend
329 329
 			rec.NumCachedSteps = int32(st.NumCachedSteps)
330 330
 			rec.NumCompletedSteps = int32(st.NumCompletedSteps)
331 331
 			rec.NumTotalSteps = int32(st.NumTotalSteps)
332
+			rec.NumWarnings = int32(st.NumWarnings)
332 333
 			mu.Unlock()
333 334
 			return nil
334 335
 		})
... ...
@@ -370,7 +372,8 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend
370 370
 			})
371 371
 		}
372 372
 		if err1 := eg.Wait(); err == nil {
373
-			err = err1
373
+			// any error from exporting history record is internal
374
+			err = errdefs.Internal(err1)
374 375
 		}
375 376
 
376 377
 		defer func() {
... ...
@@ -398,7 +401,7 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend
398 398
 			Record: rec,
399 399
 		}); err1 != nil {
400 400
 			if err == nil {
401
-				err = err1
401
+				err = errdefs.Internal(err1)
402 402
 			}
403 403
 		}
404 404
 
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"os"
6 6
 	"sync"
7 7
 
8
+	"github.com/moby/buildkit/errdefs"
8 9
 	"github.com/moby/buildkit/solver/internal/pipe"
9 10
 	"github.com/moby/buildkit/util/bklog"
10 11
 	"github.com/moby/buildkit/util/cond"
... ...
@@ -403,7 +404,7 @@ func (pf *pipeFactory) NewInputRequest(ee Edge, req *edgeRequest) pipe.Receiver
403 403
 			WithField("edge_index", ee.Index).
404 404
 			Error("failed to get edge: inconsistent graph state")
405 405
 		return pf.NewFuncRequest(func(_ context.Context) (interface{}, error) {
406
-			return nil, errors.Errorf("failed to get edge: inconsistent graph state in edge %s %s %d", ee.Vertex.Name(), ee.Vertex.Digest(), ee.Index)
406
+			return nil, errdefs.Internal(errors.Errorf("failed to get edge: inconsistent graph state in edge %s %s %d", ee.Vertex.Name(), ee.Vertex.Digest(), ee.Index))
407 407
 		})
408 408
 	}
409 409
 	p := pf.s.newPipe(target, pf.e, pipe.Request{Payload: req})
... ...
@@ -25,6 +25,7 @@ import (
25 25
 	"github.com/moby/buildkit/util/imageutil"
26 26
 	"github.com/moby/buildkit/util/pull"
27 27
 	"github.com/moby/buildkit/util/resolver"
28
+	"github.com/moby/buildkit/util/tracing"
28 29
 	digest "github.com/opencontainers/go-digest"
29 30
 	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
30 31
 	"github.com/pkg/errors"
... ...
@@ -148,7 +149,12 @@ func (is *Source) Resolve(ctx context.Context, id source.Identifier, sm *session
148 148
 	return p, nil
149 149
 }
150 150
 
151
-func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (digest.Digest, []byte, error) {
151
+func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (digest digest.Digest, config []byte, retErr error) {
152
+	span, ctx := tracing.StartSpan(ctx, "resolving "+ref)
153
+	defer func() {
154
+		tracing.FinishWithError(span, retErr)
155
+	}()
156
+
152 157
 	key := ref
153 158
 	var (
154 159
 		rm    resolver.ResolveMode
155 160
new file mode 100644
... ...
@@ -0,0 +1,63 @@
0
+package git
1
+
2
+import (
3
+	"context"
4
+	"os/exec"
5
+	"runtime"
6
+	"syscall"
7
+	"time"
8
+
9
+	"golang.org/x/sys/unix"
10
+)
11
+
12
+func runWithStandardUmask(ctx context.Context, cmd *exec.Cmd) error {
13
+	errCh := make(chan error)
14
+
15
+	go func() {
16
+		defer close(errCh)
17
+		runtime.LockOSThread()
18
+
19
+		if err := unshareAndRun(ctx, cmd); err != nil {
20
+			errCh <- err
21
+		}
22
+	}()
23
+
24
+	return <-errCh
25
+}
26
+
27
+// unshareAndRun needs to be called in a locked thread.
28
+func unshareAndRun(ctx context.Context, cmd *exec.Cmd) error {
29
+	if err := syscall.Unshare(syscall.CLONE_FS); err != nil {
30
+		return err
31
+	}
32
+	syscall.Umask(0022)
33
+	return runProcessGroup(ctx, cmd)
34
+}
35
+
36
+func runProcessGroup(ctx context.Context, cmd *exec.Cmd) error {
37
+	cmd.SysProcAttr = &unix.SysProcAttr{
38
+		Setpgid:   true,
39
+		Pdeathsig: unix.SIGTERM,
40
+	}
41
+	if err := cmd.Start(); err != nil {
42
+		return err
43
+	}
44
+	waitDone := make(chan struct{})
45
+	go func() {
46
+		select {
47
+		case <-ctx.Done():
48
+			_ = unix.Kill(-cmd.Process.Pid, unix.SIGTERM)
49
+			go func() {
50
+				select {
51
+				case <-waitDone:
52
+				case <-time.After(10 * time.Second):
53
+					_ = unix.Kill(-cmd.Process.Pid, unix.SIGKILL)
54
+				}
55
+			}()
56
+		case <-waitDone:
57
+		}
58
+	}()
59
+	err := cmd.Wait()
60
+	close(waitDone)
61
+	return err
62
+}
0 63
deleted file mode 100644
... ...
@@ -1,66 +0,0 @@
1
-//go:build !windows && !freebsd
2
-// +build !windows,!freebsd
3
-
4
-package git
5
-
6
-import (
7
-	"context"
8
-	"os/exec"
9
-	"runtime"
10
-	"syscall"
11
-	"time"
12
-
13
-	"golang.org/x/sys/unix"
14
-)
15
-
16
-func runWithStandardUmask(ctx context.Context, cmd *exec.Cmd) error {
17
-	errCh := make(chan error)
18
-
19
-	go func() {
20
-		defer close(errCh)
21
-		runtime.LockOSThread()
22
-
23
-		if err := unshareAndRun(ctx, cmd); err != nil {
24
-			errCh <- err
25
-		}
26
-	}()
27
-
28
-	return <-errCh
29
-}
30
-
31
-// unshareAndRun needs to be called in a locked thread.
32
-func unshareAndRun(ctx context.Context, cmd *exec.Cmd) error {
33
-	if err := syscall.Unshare(syscall.CLONE_FS); err != nil {
34
-		return err
35
-	}
36
-	syscall.Umask(0022)
37
-	return runProcessGroup(ctx, cmd)
38
-}
39
-
40
-func runProcessGroup(ctx context.Context, cmd *exec.Cmd) error {
41
-	cmd.SysProcAttr = &unix.SysProcAttr{
42
-		Setpgid:   true,
43
-		Pdeathsig: unix.SIGTERM,
44
-	}
45
-	if err := cmd.Start(); err != nil {
46
-		return err
47
-	}
48
-	waitDone := make(chan struct{})
49
-	go func() {
50
-		select {
51
-		case <-ctx.Done():
52
-			_ = unix.Kill(-cmd.Process.Pid, unix.SIGTERM)
53
-			go func() {
54
-				select {
55
-				case <-waitDone:
56
-				case <-time.After(10 * time.Second):
57
-					_ = unix.Kill(-cmd.Process.Pid, unix.SIGKILL)
58
-				}
59
-			}()
60
-		case <-waitDone:
61
-		}
62
-	}()
63
-	err := cmd.Wait()
64
-	close(waitDone)
65
-	return err
66
-}
67 1
new file mode 100644
... ...
@@ -0,0 +1,6 @@
0
+package appdefaults
1
+
2
+const (
3
+	Address         = "unix:///run/buildkit/buildkitd.sock"
4
+	traceSocketPath = "/run/buildkit/otel-grpc.sock"
5
+)
... ...
@@ -10,7 +10,6 @@ import (
10 10
 )
11 11
 
12 12
 const (
13
-	Address              = "unix:///run/buildkit/buildkitd.sock"
14 13
 	Root                 = "/var/lib/buildkit"
15 14
 	ConfigDir            = "/etc/buildkit"
16 15
 	DefaultCNIBinDir     = "/opt/cni/bin"
... ...
@@ -82,5 +81,5 @@ func TraceSocketPath(inUserNS bool) string {
82 82
 			return filepath.Join(dirs[0], "buildkit", "otel-grpc.sock")
83 83
 		}
84 84
 	}
85
-	return "/run/buildkit/otel-grpc.sock"
85
+	return traceSocketPath
86 86
 }
87 87
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+//go:build unix && !linux
1
+
2
+package appdefaults
3
+
4
+const (
5
+	Address         = "unix:///var/run/buildkit/buildkitd.sock"
6
+	traceSocketPath = "/var/run/buildkit/otel-grpc.sock"
7
+)
0 8
new file mode 100644
... ...
@@ -0,0 +1,16 @@
0
+package boltutil
1
+
2
+import (
3
+	"io/fs"
4
+
5
+	"github.com/moby/buildkit/util/db"
6
+	bolt "go.etcd.io/bbolt"
7
+)
8
+
9
+func Open(p string, mode fs.FileMode, options *bolt.Options) (db.DB, error) {
10
+	bdb, err := bolt.Open(p, mode, options)
11
+	if err != nil {
12
+		return nil, err
13
+	}
14
+	return bdb, nil
15
+}
0 16
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+package db
1
+
2
+import "io"
3
+
4
+type DB interface {
5
+	io.Closer
6
+	Transactor
7
+}
0 8
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+package db
1
+
2
+import (
3
+	bolt "go.etcd.io/bbolt"
4
+)
5
+
6
+// Transactor is the database interface for running transactions
7
+type Transactor interface {
8
+	View(fn func(*bolt.Tx) error) error
9
+	Update(fn func(*bolt.Tx) error) error
10
+}
... ...
@@ -9,8 +9,8 @@ import (
9 9
 	"github.com/containerd/containerd/containers"
10 10
 	"github.com/containerd/containerd/oci"
11 11
 	"github.com/containerd/containerd/pkg/cap"
12
-	"github.com/containerd/containerd/pkg/userns"
13 12
 	"github.com/moby/buildkit/util/bklog"
13
+	"github.com/moby/sys/userns"
14 14
 	specs "github.com/opencontainers/runtime-spec/specs-go"
15 15
 	"github.com/pkg/errors"
16 16
 	"golang.org/x/sys/unix"
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	gogotypes "github.com/gogo/protobuf/types"
11 11
 	"github.com/golang/protobuf/proto" //nolint:staticcheck
12 12
 	"github.com/golang/protobuf/ptypes/any"
13
+	"github.com/moby/buildkit/errdefs"
13 14
 	"github.com/moby/buildkit/util/bklog"
14 15
 	"github.com/moby/buildkit/util/stack"
15 16
 	spb "google.golang.org/genproto/googleapis/rpc/status"
... ...
@@ -94,6 +95,13 @@ func withDetails(ctx context.Context, s *status.Status, details ...proto.Message
94 94
 }
95 95
 
96 96
 func Code(err error) codes.Code {
97
+	if errdefs.IsInternal(err) {
98
+		if errdefs.IsResourceExhausted(err) {
99
+			return codes.ResourceExhausted
100
+		}
101
+		return codes.Internal
102
+	}
103
+
97 104
 	if se, ok := err.(interface {
98 105
 		Code() codes.Code
99 106
 	}); ok {
... ...
@@ -64,11 +64,7 @@ func retryError(err error) bool {
64 64
 		return true
65 65
 	}
66 66
 	// catches TLS timeout or other network-related temporary errors
67
-	if ne, ok := errors.Cause(err).(net.Error); ok && ne.Temporary() { //nolint:staticcheck // ignoring "SA1019: Temporary is deprecated", continue to propagate net.Error through the "temporary" status
68
-		return true
69
-	}
70
-	// https://github.com/containerd/containerd/pull/4724
71
-	if errors.Cause(err).Error() == "no response" {
67
+	if ne := net.Error(nil); errors.As(err, &ne) && ne.Temporary() { // ignoring "SA1019: Temporary is deprecated", continue to propagate net.Error through the "temporary" status
72 68
 		return true
73 69
 	}
74 70
 
75 71
new file mode 100644
... ...
@@ -0,0 +1,67 @@
0
+package stack
1
+
2
+import (
3
+	"slices"
4
+)
5
+
6
+func compressStacks(st []*Stack) []*Stack {
7
+	if len(st) == 0 {
8
+		return nil
9
+	}
10
+
11
+	slices.SortFunc(st, func(a, b *Stack) int {
12
+		return len(b.Frames) - len(a.Frames)
13
+	})
14
+
15
+	out := []*Stack{st[0]}
16
+
17
+loop0:
18
+	for _, st := range st[1:] {
19
+		maxIdx := -1
20
+		for _, prev := range out {
21
+			idx := subFrames(st.Frames, prev.Frames)
22
+			if idx == -1 {
23
+				continue
24
+			}
25
+			// full match, potentially skip all
26
+			if idx == len(st.Frames)-1 {
27
+				if st.Pid == prev.Pid && st.Version == prev.Version && slices.Compare(st.Cmdline, st.Cmdline) == 0 {
28
+					continue loop0
29
+				}
30
+			}
31
+			if idx > maxIdx {
32
+				maxIdx = idx
33
+			}
34
+		}
35
+
36
+		if maxIdx > 0 {
37
+			st.Frames = st.Frames[:len(st.Frames)-maxIdx]
38
+		}
39
+		out = append(out, st)
40
+	}
41
+
42
+	return out
43
+}
44
+
45
+func subFrames(a, b []*Frame) int {
46
+	idx := -1
47
+	i := len(a) - 1
48
+	j := len(b) - 1
49
+	for i >= 0 {
50
+		if j < 0 {
51
+			break
52
+		}
53
+		if a[i].Equal(b[j]) {
54
+			idx++
55
+			i--
56
+			j--
57
+		} else {
58
+			break
59
+		}
60
+	}
61
+	return idx
62
+}
63
+
64
+func (a *Frame) Equal(b *Frame) bool {
65
+	return a.File == b.File && a.Line == b.Line && a.Name == b.Name
66
+}
... ...
@@ -44,6 +44,10 @@ func Helper() {
44 44
 }
45 45
 
46 46
 func Traces(err error) []*Stack {
47
+	return compressStacks(traces(err))
48
+}
49
+
50
+func traces(err error) []*Stack {
47 51
 	var st []*Stack
48 52
 
49 53
 	switch e := err.(type) {
50 54
deleted file mode 100644
... ...
@@ -1,201 +0,0 @@
1
-                                 Apache License
2
-                           Version 2.0, January 2004
3
-                        http://www.apache.org/licenses/
4
-
5
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
-
7
-   1. Definitions.
8
-
9
-      "License" shall mean the terms and conditions for use, reproduction,
10
-      and distribution as defined by Sections 1 through 9 of this document.
11
-
12
-      "Licensor" shall mean the copyright owner or entity authorized by
13
-      the copyright owner that is granting the License.
14
-
15
-      "Legal Entity" shall mean the union of the acting entity and all
16
-      other entities that control, are controlled by, or are under common
17
-      control with that entity. For the purposes of this definition,
18
-      "control" means (i) the power, direct or indirect, to cause the
19
-      direction or management of such entity, whether by contract or
20
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
-      outstanding shares, or (iii) beneficial ownership of such entity.
22
-
23
-      "You" (or "Your") shall mean an individual or Legal Entity
24
-      exercising permissions granted by this License.
25
-
26
-      "Source" form shall mean the preferred form for making modifications,
27
-      including but not limited to software source code, documentation
28
-      source, and configuration files.
29
-
30
-      "Object" form shall mean any form resulting from mechanical
31
-      transformation or translation of a Source form, including but
32
-      not limited to compiled object code, generated documentation,
33
-      and conversions to other media types.
34
-
35
-      "Work" shall mean the work of authorship, whether in Source or
36
-      Object form, made available under the License, as indicated by a
37
-      copyright notice that is included in or attached to the work
38
-      (an example is provided in the Appendix below).
39
-
40
-      "Derivative Works" shall mean any work, whether in Source or Object
41
-      form, that is based on (or derived from) the Work and for which the
42
-      editorial revisions, annotations, elaborations, or other modifications
43
-      represent, as a whole, an original work of authorship. For the purposes
44
-      of this License, Derivative Works shall not include works that remain
45
-      separable from, or merely link (or bind by name) to the interfaces of,
46
-      the Work and Derivative Works thereof.
47
-
48
-      "Contribution" shall mean any work of authorship, including
49
-      the original version of the Work and any modifications or additions
50
-      to that Work or Derivative Works thereof, that is intentionally
51
-      submitted to Licensor for inclusion in the Work by the copyright owner
52
-      or by an individual or Legal Entity authorized to submit on behalf of
53
-      the copyright owner. For the purposes of this definition, "submitted"
54
-      means any form of electronic, verbal, or written communication sent
55
-      to the Licensor or its representatives, including but not limited to
56
-      communication on electronic mailing lists, source code control systems,
57
-      and issue tracking systems that are managed by, or on behalf of, the
58
-      Licensor for the purpose of discussing and improving the Work, but
59
-      excluding communication that is conspicuously marked or otherwise
60
-      designated in writing by the copyright owner as "Not a Contribution."
61
-
62
-      "Contributor" shall mean Licensor and any individual or Legal Entity
63
-      on behalf of whom a Contribution has been received by Licensor and
64
-      subsequently incorporated within the Work.
65
-
66
-   2. Grant of Copyright License. Subject to the terms and conditions of
67
-      this License, each Contributor hereby grants to You a perpetual,
68
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
-      copyright license to reproduce, prepare Derivative Works of,
70
-      publicly display, publicly perform, sublicense, and distribute the
71
-      Work and such Derivative Works in Source or Object form.
72
-
73
-   3. Grant of Patent License. Subject to the terms and conditions of
74
-      this License, each Contributor hereby grants to You a perpetual,
75
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
-      (except as stated in this section) patent license to make, have made,
77
-      use, offer to sell, sell, import, and otherwise transfer the Work,
78
-      where such license applies only to those patent claims licensable
79
-      by such Contributor that are necessarily infringed by their
80
-      Contribution(s) alone or by combination of their Contribution(s)
81
-      with the Work to which such Contribution(s) was submitted. If You
82
-      institute patent litigation against any entity (including a
83
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
84
-      or a Contribution incorporated within the Work constitutes direct
85
-      or contributory patent infringement, then any patent licenses
86
-      granted to You under this License for that Work shall terminate
87
-      as of the date such litigation is filed.
88
-
89
-   4. Redistribution. You may reproduce and distribute copies of the
90
-      Work or Derivative Works thereof in any medium, with or without
91
-      modifications, and in Source or Object form, provided that You
92
-      meet the following conditions:
93
-
94
-      (a) You must give any other recipients of the Work or
95
-          Derivative Works a copy of this License; and
96
-
97
-      (b) You must cause any modified files to carry prominent notices
98
-          stating that You changed the files; and
99
-
100
-      (c) You must retain, in the Source form of any Derivative Works
101
-          that You distribute, all copyright, patent, trademark, and
102
-          attribution notices from the Source form of the Work,
103
-          excluding those notices that do not pertain to any part of
104
-          the Derivative Works; and
105
-
106
-      (d) If the Work includes a "NOTICE" text file as part of its
107
-          distribution, then any Derivative Works that You distribute must
108
-          include a readable copy of the attribution notices contained
109
-          within such NOTICE file, excluding those notices that do not
110
-          pertain to any part of the Derivative Works, in at least one
111
-          of the following places: within a NOTICE text file distributed
112
-          as part of the Derivative Works; within the Source form or
113
-          documentation, if provided along with the Derivative Works; or,
114
-          within a display generated by the Derivative Works, if and
115
-          wherever such third-party notices normally appear. The contents
116
-          of the NOTICE file are for informational purposes only and
117
-          do not modify the License. You may add Your own attribution
118
-          notices within Derivative Works that You distribute, alongside
119
-          or as an addendum to the NOTICE text from the Work, provided
120
-          that such additional attribution notices cannot be construed
121
-          as modifying the License.
122
-
123
-      You may add Your own copyright statement to Your modifications and
124
-      may provide additional or different license terms and conditions
125
-      for use, reproduction, or distribution of Your modifications, or
126
-      for any such Derivative Works as a whole, provided Your use,
127
-      reproduction, and distribution of the Work otherwise complies with
128
-      the conditions stated in this License.
129
-
130
-   5. Submission of Contributions. Unless You explicitly state otherwise,
131
-      any Contribution intentionally submitted for inclusion in the Work
132
-      by You to the Licensor shall be under the terms and conditions of
133
-      this License, without any additional terms or conditions.
134
-      Notwithstanding the above, nothing herein shall supersede or modify
135
-      the terms of any separate license agreement you may have executed
136
-      with Licensor regarding such Contributions.
137
-
138
-   6. Trademarks. This License does not grant permission to use the trade
139
-      names, trademarks, service marks, or product names of the Licensor,
140
-      except as required for reasonable and customary use in describing the
141
-      origin of the Work and reproducing the content of the NOTICE file.
142
-
143
-   7. Disclaimer of Warranty. Unless required by applicable law or
144
-      agreed to in writing, Licensor provides the Work (and each
145
-      Contributor provides its Contributions) on an "AS IS" BASIS,
146
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
-      implied, including, without limitation, any warranties or conditions
148
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
-      PARTICULAR PURPOSE. You are solely responsible for determining the
150
-      appropriateness of using or redistributing the Work and assume any
151
-      risks associated with Your exercise of permissions under this License.
152
-
153
-   8. Limitation of Liability. In no event and under no legal theory,
154
-      whether in tort (including negligence), contract, or otherwise,
155
-      unless required by applicable law (such as deliberate and grossly
156
-      negligent acts) or agreed to in writing, shall any Contributor be
157
-      liable to You for damages, including any direct, indirect, special,
158
-      incidental, or consequential damages of any character arising as a
159
-      result of this License or out of the use or inability to use the
160
-      Work (including but not limited to damages for loss of goodwill,
161
-      work stoppage, computer failure or malfunction, or any and all
162
-      other commercial damages or losses), even if such Contributor
163
-      has been advised of the possibility of such damages.
164
-
165
-   9. Accepting Warranty or Additional Liability. While redistributing
166
-      the Work or Derivative Works thereof, You may choose to offer,
167
-      and charge a fee for, acceptance of support, warranty, indemnity,
168
-      or other liability obligations and/or rights consistent with this
169
-      License. However, in accepting such obligations, You may act only
170
-      on Your own behalf and on Your sole responsibility, not on behalf
171
-      of any other Contributor, and only if You agree to indemnify,
172
-      defend, and hold each Contributor harmless for any liability
173
-      incurred by, or claims asserted against, such Contributor by reason
174
-      of your accepting any such warranty or additional liability.
175
-
176
-   END OF TERMS AND CONDITIONS
177
-
178
-   APPENDIX: How to apply the Apache License to your work.
179
-
180
-      To apply the Apache License to your work, attach the following
181
-      boilerplate notice, with the fields enclosed by brackets "[]"
182
-      replaced with your own identifying information. (Don't include
183
-      the brackets!)  The text should be enclosed in the appropriate
184
-      comment syntax for the file format. We also recommend that a
185
-      file or class name and description of purpose be included on the
186
-      same "printed page" as the copyright notice for easier
187
-      identification within third-party archives.
188
-
189
-   Copyright [yyyy] [name of copyright owner]
190
-
191
-   Licensed under the Apache License, Version 2.0 (the "License");
192
-   you may not use this file except in compliance with the License.
193
-   You may obtain a copy of the License at
194
-
195
-       http://www.apache.org/licenses/LICENSE-2.0
196
-
197
-   Unless required by applicable law or agreed to in writing, software
198
-   distributed under the License is distributed on an "AS IS" BASIS,
199
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
-   See the License for the specific language governing permissions and
201
-   limitations under the License.
202 1
deleted file mode 100644
... ...
@@ -1,20 +0,0 @@
1
-// Copyright The OpenTelemetry Authors
2
-//
3
-// Licensed under the Apache License, Version 2.0 (the "License");
4
-// you may not use this file except in compliance with the License.
5
-// You may obtain a copy of the License at
6
-//
7
-//     http://www.apache.org/licenses/LICENSE-2.0
8
-//
9
-// Unless required by applicable law or agreed to in writing, software
10
-// distributed under the License is distributed on an "AS IS" BASIS,
11
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
-// See the License for the specific language governing permissions and
13
-// limitations under the License.
14
-
15
-// Package otlpmetric provides an OpenTelemetry metric Exporter that can be
16
-// used with PeriodicReader. It transforms metricdata into OTLP and transmits
17
-// the transformed data to OTLP receivers. The Exporter is configurable to use
18
-// different Clients, each using a distinct transport protocol to communicate
19
-// to an OTLP receiving endpoint.
20
-package otlpmetric // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric"
... ...
@@ -61,7 +61,11 @@ func newClient(ctx context.Context, cfg oconf.Config) (*client, error) {
61 61
 	if c.conn == nil {
62 62
 		// If the caller did not provide a ClientConn when the client was
63 63
 		// created, create one using the configuration they did provide.
64
-		conn, err := grpc.DialContext(ctx, cfg.Metrics.Endpoint, cfg.DialOptions...)
64
+		userAgent := "OTel Go OTLP over gRPC metrics exporter/" + Version()
65
+		dialOpts := []grpc.DialOption{grpc.WithUserAgent(userAgent)}
66
+		dialOpts = append(dialOpts, cfg.DialOptions...)
67
+
68
+		conn, err := grpc.DialContext(ctx, cfg.Metrics.Endpoint, dialOpts...)
65 69
 		if err != nil {
66 70
 			return nil, err
67 71
 		}
... ...
@@ -172,28 +176,36 @@ func (c *client) exportContext(parent context.Context) (context.Context, context
172 172
 // duration to wait for if an explicit throttle time is included in err.
173 173
 func retryable(err error) (bool, time.Duration) {
174 174
 	s := status.Convert(err)
175
+	return retryableGRPCStatus(s)
176
+}
177
+
178
+func retryableGRPCStatus(s *status.Status) (bool, time.Duration) {
175 179
 	switch s.Code() {
176 180
 	case codes.Canceled,
177 181
 		codes.DeadlineExceeded,
178
-		codes.ResourceExhausted,
179 182
 		codes.Aborted,
180 183
 		codes.OutOfRange,
181 184
 		codes.Unavailable,
182 185
 		codes.DataLoss:
183
-		return true, throttleDelay(s)
186
+		// Additionally, handle RetryInfo.
187
+		_, d := throttleDelay(s)
188
+		return true, d
189
+	case codes.ResourceExhausted:
190
+		// Retry only if the server signals that the recovery from resource exhaustion is possible.
191
+		return throttleDelay(s)
184 192
 	}
185 193
 
186 194
 	// Not a retry-able error.
187 195
 	return false, 0
188 196
 }
189 197
 
190
-// throttleDelay returns a duration to wait for if an explicit throttle time
191
-// is included in the response status.
192
-func throttleDelay(s *status.Status) time.Duration {
198
+// throttleDelay returns if the status is RetryInfo
199
+// and the duration to wait for if an explicit throttle time is included.
200
+func throttleDelay(s *status.Status) (bool, time.Duration) {
193 201
 	for _, detail := range s.Details() {
194 202
 		if t, ok := detail.(*errdetails.RetryInfo); ok {
195
-			return t.RetryDelay.AsDuration()
203
+			return true, t.RetryDelay.AsDuration()
196 204
 		}
197 205
 	}
198
-	return 0
206
+	return false, 0
199 207
 }
... ...
@@ -109,13 +109,7 @@ func compressorToCompression(compressor string) oconf.Compression {
109 109
 }
110 110
 
111 111
 // WithCompressor sets the compressor the gRPC client uses.
112
-//
113
-// It is the responsibility of the caller to ensure that the compressor set
114
-// has been registered with google.golang.org/grpc/encoding (see
115
-// encoding.RegisterCompressor for more information). For example, to register
116
-// the gzip compressor import the package:
117
-//
118
-//	import _ "google.golang.org/grpc/encoding/gzip"
112
+// Supported compressor values: "gzip".
119 113
 //
120 114
 // If the OTEL_EXPORTER_OTLP_COMPRESSION or
121 115
 // OTEL_EXPORTER_OTLP_METRICS_COMPRESSION environment variable is set, and
... ...
@@ -12,6 +12,85 @@
12 12
 // See the License for the specific language governing permissions and
13 13
 // limitations under the License.
14 14
 
15
-// Package otlpmetricgrpc provides an otlpmetric.Exporter that communicates
16
-// with an OTLP receiving endpoint using gRPC.
15
+/*
16
+Package otlpmetricgrpc provides an OTLP metrics exporter using gRPC.
17
+By default the telemetry is sent to https://localhost:4317.
18
+
19
+Exporter should be created using [New] and used with a [metric.PeriodicReader].
20
+
21
+The environment variables described below can be used for configuration.
22
+
23
+OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT (default: "https://localhost:4317") -
24
+target to which the exporter sends telemetry.
25
+The target syntax is defined in https://github.com/grpc/grpc/blob/master/doc/naming.md.
26
+The value must contain a host.
27
+The value may additionally a port, a scheme, and a path.
28
+The value accepts "http" and "https" scheme.
29
+The value should not contain a query string or fragment.
30
+OTEL_EXPORTER_OTLP_METRICS_ENDPOINT takes precedence over OTEL_EXPORTER_OTLP_ENDPOINT.
31
+The configuration can be overridden by [WithEndpoint], [WithInsecure], [WithGRPCConn] options.
32
+
33
+OTEL_EXPORTER_OTLP_INSECURE, OTEL_EXPORTER_OTLP_METRICS_INSECURE (default: "false") -
34
+setting "true" disables client transport security for the exporter's gRPC connection.
35
+You can use this only when an endpoint is provided without the http or https scheme.
36
+OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT setting overrides
37
+the scheme defined via OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT.
38
+OTEL_EXPORTER_OTLP_METRICS_INSECURE takes precedence over OTEL_EXPORTER_OTLP_INSECURE.
39
+The configuration can be overridden by [WithInsecure], [WithGRPCConn] options.
40
+
41
+OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_METRICS_HEADERS (default: none) -
42
+key-value pairs used as gRPC metadata associated with gRPC requests.
43
+The value is expected to be represented in a format matching to the [W3C Baggage HTTP Header Content Format],
44
+except that additional semi-colon delimited metadata is not supported.
45
+Example value: "key1=value1,key2=value2".
46
+OTEL_EXPORTER_OTLP_METRICS_HEADERS takes precedence over OTEL_EXPORTER_OTLP_HEADERS.
47
+The configuration can be overridden by [WithHeaders] option.
48
+
49
+OTEL_EXPORTER_OTLP_TIMEOUT, OTEL_EXPORTER_OTLP_METRICS_TIMEOUT (default: "10000") -
50
+maximum time in milliseconds the OTLP exporter waits for each batch export.
51
+OTEL_EXPORTER_OTLP_METRICS_TIMEOUT takes precedence over OTEL_EXPORTER_OTLP_TIMEOUT.
52
+The configuration can be overridden by [WithTimeout] option.
53
+
54
+OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_METRICS_COMPRESSION (default: none) -
55
+the gRPC compressor the exporter uses.
56
+Supported value: "gzip".
57
+OTEL_EXPORTER_OTLP_METRICS_COMPRESSION takes precedence over OTEL_EXPORTER_OTLP_COMPRESSION.
58
+The configuration can be overridden by [WithCompressor], [WithGRPCConn] options.
59
+
60
+OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE (default: none) -
61
+the filepath to the trusted certificate to use when verifying a server's TLS credentials.
62
+OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CERTIFICATE.
63
+The configuration can be overridden by [WithTLSCredentials], [WithGRPCConn] options.
64
+
65
+OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE, OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE (default: none) -
66
+the filepath to the client certificate/chain trust for clients private key to use in mTLS communication in PEM format.
67
+OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE.
68
+The configuration can be overridden by [WithTLSCredentials], [WithGRPCConn] options.
69
+
70
+OTEL_EXPORTER_OTLP_CLIENT_KEY, OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY (default: none) -
71
+the filepath  to the clients private key to use in mTLS communication in PEM format.
72
+OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY takes precedence over OTEL_EXPORTER_OTLP_CLIENT_KEY.
73
+The configuration can be overridden by [WithTLSCredentials], [WithGRPCConn] option.
74
+
75
+OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE (default: "cumulative") -
76
+aggregation temporality to use on the basis of instrument kind. Supported values:
77
+  - "cumulative" - Cumulative aggregation temporality for all instrument kinds,
78
+  - "delta" - Delta aggregation temporality for Counter, Asynchronous Counter and Histogram instrument kinds;
79
+    Cumulative aggregation for UpDownCounter and Asynchronous UpDownCounter instrument kinds,
80
+  - "lowmemory" - Delta aggregation temporality for Synchronous Counter and Histogram instrument kinds;
81
+    Cumulative aggregation temporality for Synchronous UpDownCounter, Asynchronous Counter, and Asynchronous UpDownCounter instrument kinds.
82
+
83
+The configuration can be overridden by [WithTemporalitySelector] option.
84
+
85
+OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION (default: "explicit_bucket_histogram") -
86
+default aggregation to use for histogram instruments. Supported values:
87
+  - "explicit_bucket_histogram" - [Explicit Bucket Histogram Aggregation],
88
+  - "base2_exponential_bucket_histogram" - [Base2 Exponential Bucket Histogram Aggregation].
89
+
90
+The configuration can be overridden by [WithAggregationSelector] option.
91
+
92
+[W3C Baggage HTTP Header Content Format]: https://www.w3.org/TR/baggage/#header-content
93
+[Explicit Bucket Histogram Aggregation]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/sdk.md#explicit-bucket-histogram-aggregation
94
+[Base2 Exponential Bucket Histogram Aggregation]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/sdk.md#base2-exponential-bucket-histogram-aggregation
95
+*/
17 96
 package otlpmetricgrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
... ...
@@ -174,13 +174,13 @@ func stringToHeader(value string) map[string]string {
174 174
 			global.Error(errors.New("missing '="), "parse headers", "input", header)
175 175
 			continue
176 176
 		}
177
-		name, err := url.QueryUnescape(n)
177
+		name, err := url.PathUnescape(n)
178 178
 		if err != nil {
179 179
 			global.Error(err, "escape header key", "key", n)
180 180
 			continue
181 181
 		}
182 182
 		trimmedName := strings.TrimSpace(name)
183
-		value, err := url.QueryUnescape(v)
183
+		value, err := url.PathUnescape(v)
184 184
 		if err != nil {
185 185
 			global.Error(err, "escape header value", "value", v)
186 186
 			continue
... ...
@@ -30,7 +30,6 @@ import (
30 30
 	"google.golang.org/grpc/credentials/insecure"
31 31
 	"google.golang.org/grpc/encoding/gzip"
32 32
 
33
-	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric"
34 33
 	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry"
35 34
 	"go.opentelemetry.io/otel/sdk/metric"
36 35
 )
... ...
@@ -122,7 +121,6 @@ func cleanPath(urlPath string, defaultPath string) string {
122 122
 // NewGRPCConfig returns a new Config with all settings applied from opts and
123 123
 // any unset setting using the default gRPC config values.
124 124
 func NewGRPCConfig(opts ...GRPCOption) Config {
125
-	userAgent := "OTel OTLP Exporter Go/" + otlpmetric.Version()
126 125
 	cfg := Config{
127 126
 		Metrics: SignalConfig{
128 127
 			Endpoint:    fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorGRPCPort),
... ...
@@ -134,7 +132,6 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
134 134
 			AggregationSelector: metric.DefaultAggregationSelector,
135 135
 		},
136 136
 		RetryConfig: retry.DefaultConfig,
137
-		DialOptions: []grpc.DialOption{grpc.WithUserAgent(userAgent)},
138 137
 	}
139 138
 	cfg = ApplyGRPCEnvConfigs(cfg)
140 139
 	for _, opt := range opts {
... ...
@@ -158,9 +155,6 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
158 158
 	if cfg.Metrics.Compression == GzipCompression {
159 159
 		cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name)))
160 160
 	}
161
-	if len(cfg.DialOptions) != 0 {
162
-		cfg.DialOptions = append(cfg.DialOptions, cfg.DialOptions...)
163
-	}
164 161
 	if cfg.ReconnectionPeriod != 0 {
165 162
 		p := grpc.ConnectParams{
166 163
 			Backoff:           backoff.DefaultConfig,
167 164
new file mode 100644
... ...
@@ -0,0 +1,20 @@
0
+// Copyright The OpenTelemetry Authors
1
+//
2
+// Licensed under the Apache License, Version 2.0 (the "License");
3
+// you may not use this file except in compliance with the License.
4
+// You may obtain a copy of the License at
5
+//
6
+//     http://www.apache.org/licenses/LICENSE-2.0
7
+//
8
+// Unless required by applicable law or agreed to in writing, software
9
+// distributed under the License is distributed on an "AS IS" BASIS,
10
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+// See the License for the specific language governing permissions and
12
+// limitations under the License.
13
+
14
+package otlpmetricgrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
15
+
16
+// Version is the current release version of the OpenTelemetry OTLP over gRPC metrics exporter in use.
17
+func Version() string {
18
+	return "0.44.0"
19
+}
... ...
@@ -18,6 +18,7 @@ import (
18 18
 	"bytes"
19 19
 	"compress/gzip"
20 20
 	"context"
21
+	"errors"
21 22
 	"fmt"
22 23
 	"io"
23 24
 	"net"
... ...
@@ -30,7 +31,6 @@ import (
30 30
 	"google.golang.org/protobuf/proto"
31 31
 
32 32
 	"go.opentelemetry.io/otel"
33
-	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric"
34 33
 	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal"
35 34
 	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf"
36 35
 	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry"
... ...
@@ -89,7 +89,7 @@ func newClient(cfg oconf.Config) (*client, error) {
89 89
 		return nil, err
90 90
 	}
91 91
 
92
-	userAgent := "OTel OTLP Exporter Go/" + otlpmetric.Version()
92
+	userAgent := "OTel Go OTLP over HTTP/protobuf metrics exporter/" + Version()
93 93
 	req.Header.Set("User-Agent", userAgent)
94 94
 
95 95
 	if n := len(cfg.Metrics.Headers); n > 0 {
... ...
@@ -148,6 +148,10 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou
148 148
 
149 149
 		request.reset(iCtx)
150 150
 		resp, err := c.httpClient.Do(request.Request)
151
+		var urlErr *url.Error
152
+		if errors.As(err, &urlErr) && urlErr.Temporary() {
153
+			return newResponseError(http.Header{})
154
+		}
151 155
 		if err != nil {
152 156
 			return err
153 157
 		}
... ...
@@ -162,8 +166,11 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou
162 162
 			if _, err := io.Copy(&respData, resp.Body); err != nil {
163 163
 				return err
164 164
 			}
165
+			if respData.Len() == 0 {
166
+				return nil
167
+			}
165 168
 
166
-			if respData.Len() != 0 {
169
+			if resp.Header.Get("Content-Type") == "application/x-protobuf" {
167 170
 				var respProto colmetricpb.ExportMetricsServiceResponse
168 171
 				if err := proto.Unmarshal(respData.Bytes(), &respProto); err != nil {
169 172
 					return err
... ...
@@ -179,7 +186,10 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou
179 179
 				}
180 180
 			}
181 181
 			return nil
182
-		case sc == http.StatusTooManyRequests, sc == http.StatusServiceUnavailable:
182
+		case sc == http.StatusTooManyRequests,
183
+			sc == http.StatusBadGateway,
184
+			sc == http.StatusServiceUnavailable,
185
+			sc == http.StatusGatewayTimeout:
183 186
 			// Retry-able failure.
184 187
 			rErr = newResponseError(resp.Header)
185 188
 
... ...
@@ -12,7 +12,82 @@
12 12
 // See the License for the specific language governing permissions and
13 13
 // limitations under the License.
14 14
 
15
-// Package otlpmetrichttp provides an otlpmetric.Exporter that communicates
16
-// with an OTLP receiving endpoint using protobuf encoded metric data over
17
-// HTTP.
15
+/*
16
+Package otlpmetrichttp provides an OTLP metrics exporter using HTTP with protobuf payloads.
17
+By default the telemetry is sent to https://localhost:4318/v1/metrics.
18
+
19
+Exporter should be created using [New] and used with a [metric.PeriodicReader].
20
+
21
+The environment variables described below can be used for configuration.
22
+
23
+OTEL_EXPORTER_OTLP_ENDPOINT (default: "https://localhost:4318") -
24
+target base URL ("/v1/metrics" is appended) to which the exporter sends telemetry.
25
+The value must contain a scheme ("http" or "https") and host.
26
+The value may additionally contain a port and a path.
27
+The value should not contain a query string or fragment.
28
+The configuration can be overridden by OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
29
+environment variable and by [WithEndpoint], [WithInsecure] options.
30
+
31
+OTEL_EXPORTER_OTLP_METRICS_ENDPOINT (default: "https://localhost:4318/v1/metrics") -
32
+target URL to which the exporter sends telemetry.
33
+The value must contain a scheme ("http" or "https") and host.
34
+The value may additionally contain a port and a path.
35
+The value should not contain a query string or fragment.
36
+The configuration can be overridden by [WithEndpoint], [WitnInsecure], [WithURLPath] options.
37
+
38
+OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_METRICS_HEADERS (default: none) -
39
+key-value pairs used as headers associated with HTTP requests.
40
+The value is expected to be represented in a format matching to the [W3C Baggage HTTP Header Content Format],
41
+except that additional semi-colon delimited metadata is not supported.
42
+Example value: "key1=value1,key2=value2".
43
+OTEL_EXPORTER_OTLP_METRICS_HEADERS takes precedence over OTEL_EXPORTER_OTLP_HEADERS.
44
+The configuration can be overridden by [WithHeaders] option.
45
+
46
+OTEL_EXPORTER_OTLP_TIMEOUT, OTEL_EXPORTER_OTLP_METRICS_TIMEOUT (default: "10000") -
47
+maximum time in milliseconds the OTLP exporter waits for each batch export.
48
+OTEL_EXPORTER_OTLP_METRICS_TIMEOUT takes precedence over OTEL_EXPORTER_OTLP_TIMEOUT.
49
+The configuration can be overridden by [WithTimeout] option.
50
+
51
+OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_METRICS_COMPRESSION (default: none) -
52
+compression strategy the exporter uses to compress the HTTP body.
53
+Supported values: "gzip".
54
+OTEL_EXPORTER_OTLP_METRICS_COMPRESSION takes precedence over OTEL_EXPORTER_OTLP_COMPRESSION.
55
+The configuration can be overridden by [WithCompression] option.
56
+
57
+OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE (default: none) -
58
+filepath to the trusted certificate to use when verifying a server's TLS credentials.
59
+OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CERTIFICATE.
60
+The configuration can be overridden by [WithTLSClientConfig] option.
61
+
62
+OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE, OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE (default: none) -
63
+filepath to the client certificate/chain trust for clients private key to use in mTLS communication in PEM format.
64
+OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE.
65
+The configuration can be overridden by [WithTLSClientConfig] option.
66
+
67
+OTEL_EXPORTER_OTLP_CLIENT_KEY, OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY (default: none) -
68
+filepath to the clients private key to use in mTLS communication in PEM format.
69
+OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY takes precedence over OTEL_EXPORTER_OTLP_CLIENT_KEY.
70
+The configuration can be overridden by [WithTLSClientConfig] option.
71
+
72
+OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE (default: "cumulative") -
73
+aggregation temporality to use on the basis of instrument kind. Supported values:
74
+  - "cumulative" - Cumulative aggregation temporality for all instrument kinds,
75
+  - "delta" - Delta aggregation temporality for Counter, Asynchronous Counter and Histogram instrument kinds;
76
+    Cumulative aggregation for UpDownCounter and Asynchronous UpDownCounter instrument kinds,
77
+  - "lowmemory" - Delta aggregation temporality for Synchronous Counter and Histogram instrument kinds;
78
+    Cumulative aggregation temporality for Synchronous UpDownCounter, Asynchronous Counter, and Asynchronous UpDownCounter instrument kinds.
79
+
80
+The configuration can be overridden by [WithTemporalitySelector] option.
81
+
82
+OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION (default: "explicit_bucket_histogram") -
83
+default aggregation to use for histogram instruments. Supported values:
84
+  - "explicit_bucket_histogram" - [Explicit Bucket Histogram Aggregation],
85
+  - "base2_exponential_bucket_histogram" - [Base2 Exponential Bucket Histogram Aggregation].
86
+
87
+The configuration can be overridden by [WithAggregationSelector] option.
88
+
89
+[W3C Baggage HTTP Header Content Format]: https://www.w3.org/TR/baggage/#header-content
90
+[Explicit Bucket Histogram Aggregation]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/sdk.md#explicit-bucket-histogram-aggregation
91
+[Base2 Exponential Bucket Histogram Aggregation]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/sdk.md#base2-exponential-bucket-histogram-aggregation
92
+*/
18 93
 package otlpmetrichttp // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
... ...
@@ -174,13 +174,13 @@ func stringToHeader(value string) map[string]string {
174 174
 			global.Error(errors.New("missing '="), "parse headers", "input", header)
175 175
 			continue
176 176
 		}
177
-		name, err := url.QueryUnescape(n)
177
+		name, err := url.PathUnescape(n)
178 178
 		if err != nil {
179 179
 			global.Error(err, "escape header key", "key", n)
180 180
 			continue
181 181
 		}
182 182
 		trimmedName := strings.TrimSpace(name)
183
-		value, err := url.QueryUnescape(v)
183
+		value, err := url.PathUnescape(v)
184 184
 		if err != nil {
185 185
 			global.Error(err, "escape header value", "value", v)
186 186
 			continue
... ...
@@ -30,7 +30,6 @@ import (
30 30
 	"google.golang.org/grpc/credentials/insecure"
31 31
 	"google.golang.org/grpc/encoding/gzip"
32 32
 
33
-	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric"
34 33
 	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry"
35 34
 	"go.opentelemetry.io/otel/sdk/metric"
36 35
 )
... ...
@@ -122,7 +121,6 @@ func cleanPath(urlPath string, defaultPath string) string {
122 122
 // NewGRPCConfig returns a new Config with all settings applied from opts and
123 123
 // any unset setting using the default gRPC config values.
124 124
 func NewGRPCConfig(opts ...GRPCOption) Config {
125
-	userAgent := "OTel OTLP Exporter Go/" + otlpmetric.Version()
126 125
 	cfg := Config{
127 126
 		Metrics: SignalConfig{
128 127
 			Endpoint:    fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorGRPCPort),
... ...
@@ -134,7 +132,6 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
134 134
 			AggregationSelector: metric.DefaultAggregationSelector,
135 135
 		},
136 136
 		RetryConfig: retry.DefaultConfig,
137
-		DialOptions: []grpc.DialOption{grpc.WithUserAgent(userAgent)},
138 137
 	}
139 138
 	cfg = ApplyGRPCEnvConfigs(cfg)
140 139
 	for _, opt := range opts {
... ...
@@ -158,9 +155,6 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
158 158
 	if cfg.Metrics.Compression == GzipCompression {
159 159
 		cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name)))
160 160
 	}
161
-	if len(cfg.DialOptions) != 0 {
162
-		cfg.DialOptions = append(cfg.DialOptions, cfg.DialOptions...)
163
-	}
164 161
 	if cfg.ReconnectionPeriod != 0 {
165 162
 		p := grpc.ConnectParams{
166 163
 			Backoff:           backoff.DefaultConfig,
167 164
new file mode 100644
... ...
@@ -0,0 +1,20 @@
0
+// Copyright The OpenTelemetry Authors
1
+//
2
+// Licensed under the Apache License, Version 2.0 (the "License");
3
+// you may not use this file except in compliance with the License.
4
+// You may obtain a copy of the License at
5
+//
6
+//     http://www.apache.org/licenses/LICENSE-2.0
7
+//
8
+// Unless required by applicable law or agreed to in writing, software
9
+// distributed under the License is distributed on an "AS IS" BASIS,
10
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+// See the License for the specific language governing permissions and
12
+// limitations under the License.
13
+
14
+package otlpmetrichttp // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
15
+
16
+// Version is the current release version of the OpenTelemetry OTLP over HTTP/protobuf metrics exporter in use.
17
+func Version() string {
18
+	return "0.44.0"
19
+}
0 20
deleted file mode 100644
... ...
@@ -1,20 +0,0 @@
1
-// Copyright The OpenTelemetry Authors
2
-//
3
-// Licensed under the Apache License, Version 2.0 (the "License");
4
-// you may not use this file except in compliance with the License.
5
-// You may obtain a copy of the License at
6
-//
7
-//     http://www.apache.org/licenses/LICENSE-2.0
8
-//
9
-// Unless required by applicable law or agreed to in writing, software
10
-// distributed under the License is distributed on an "AS IS" BASIS,
11
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
-// See the License for the specific language governing permissions and
13
-// limitations under the License.
14
-
15
-package otlpmetric // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric"
16
-
17
-// Version is the current release version of the OpenTelemetry OTLP metrics exporter in use.
18
-func Version() string {
19
-	return "0.42.0"
20
-}
... ...
@@ -304,7 +304,6 @@ github.com/containerd/containerd/pkg/transfer
304 304
 github.com/containerd/containerd/pkg/transfer/proxy
305 305
 github.com/containerd/containerd/pkg/transfer/streaming
306 306
 github.com/containerd/containerd/pkg/unpack
307
-github.com/containerd/containerd/pkg/userns
308 307
 github.com/containerd/containerd/plugin
309 308
 github.com/containerd/containerd/protobuf
310 309
 github.com/containerd/containerd/protobuf/proto
... ...
@@ -388,8 +387,8 @@ github.com/containerd/stargz-snapshotter/estargz/errorutil
388 388
 # github.com/containerd/ttrpc v1.2.5
389 389
 ## explicit; go 1.19
390 390
 github.com/containerd/ttrpc
391
-# github.com/containerd/typeurl/v2 v2.1.1
392
-## explicit; go 1.13
391
+# github.com/containerd/typeurl/v2 v2.2.0
392
+## explicit; go 1.21
393 393
 github.com/containerd/typeurl/v2
394 394
 # github.com/containernetworking/cni v1.2.2
395 395
 ## explicit; go 1.21
... ...
@@ -703,7 +702,7 @@ github.com/mitchellh/hashstructure/v2
703 703
 # github.com/mitchellh/reflectwalk v1.0.2
704 704
 ## explicit
705 705
 github.com/mitchellh/reflectwalk
706
-# github.com/moby/buildkit v0.15.2
706
+# github.com/moby/buildkit v0.16.0-rc1
707 707
 ## explicit; go 1.21.0
708 708
 github.com/moby/buildkit/api/services/control
709 709
 github.com/moby/buildkit/api/types
... ...
@@ -728,6 +727,7 @@ github.com/moby/buildkit/client/ociindex
728 728
 github.com/moby/buildkit/cmd/buildkitd/config
729 729
 github.com/moby/buildkit/control
730 730
 github.com/moby/buildkit/control/gateway
731
+github.com/moby/buildkit/errdefs
731 732
 github.com/moby/buildkit/executor
732 733
 github.com/moby/buildkit/executor/containerdexecutor
733 734
 github.com/moby/buildkit/executor/oci
... ...
@@ -812,6 +812,8 @@ github.com/moby/buildkit/util/cond
812 812
 github.com/moby/buildkit/util/contentutil
813 813
 github.com/moby/buildkit/util/converter
814 814
 github.com/moby/buildkit/util/converter/tarconverter
815
+github.com/moby/buildkit/util/db
816
+github.com/moby/buildkit/util/db/boltutil
815 817
 github.com/moby/buildkit/util/entitlements
816 818
 github.com/moby/buildkit/util/entitlements/security
817 819
 github.com/moby/buildkit/util/estargz
... ...
@@ -1212,10 +1214,7 @@ go.opentelemetry.io/otel/internal/global
1212 1212
 go.opentelemetry.io/otel/propagation
1213 1213
 go.opentelemetry.io/otel/semconv/v1.17.0
1214 1214
 go.opentelemetry.io/otel/semconv/v1.21.0
1215
-# go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0
1216
-## explicit; go 1.20
1217
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric
1218
-# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0
1215
+# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0
1219 1216
 ## explicit; go 1.20
1220 1217
 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc
1221 1218
 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal
... ...
@@ -1223,7 +1222,7 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envco
1223 1223
 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf
1224 1224
 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry
1225 1225
 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform
1226
-# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0
1226
+# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0
1227 1227
 ## explicit; go 1.20
1228 1228
 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp
1229 1229
 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal