diff --git a/go.mod b/go.mod index 41e194ca0f4ca..5c54cfb64c381 100644 --- a/go.mod +++ b/go.mod @@ -48,7 +48,6 @@ require ( github.com/mdlayher/vsock v1.3.0 github.com/moby/locker v1.0.1 github.com/moby/sys/mountinfo v0.7.2 - github.com/moby/sys/sequential v0.7.0 github.com/moby/sys/signal v0.7.1 github.com/moby/sys/symlink v0.3.0 github.com/moby/sys/user v0.4.0 diff --git a/go.sum b/go.sum index dd5f2b1db5930..c8fcff0d0b700 100644 --- a/go.sum +++ b/go.sum @@ -238,8 +238,6 @@ github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCnd github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= -github.com/moby/sys/sequential v0.7.0 h1:ASQNGNROJSuOO6LL6bPHbKvuZu6NU8P4ldPWk31zj/8= -github.com/moby/sys/sequential v0.7.0/go.mod h1:NfSTAp6V3fw4tmkD62PEcOKeZKquXT8VKCkf7aVR79o= github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0= github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8= github.com/moby/sys/symlink v0.3.0 h1:GZX89mEZ9u53f97npBy4Rc3vJKj7JBDj/PN2I22GrNU= diff --git a/internal/cri/server/images/image_pull.go b/internal/cri/server/images/image_pull.go index 0d927437ddb89..23dd60f050c2d 100644 --- a/internal/cri/server/images/image_pull.go +++ b/internal/cri/server/images/image_pull.go @@ -180,11 +180,14 @@ func (c *CRIImageService) PullImage(ctx context.Context, name string, credential // // Transfer service does not currently support all the CRI image config options. // TODO: Add support for DisableSnapshotAnnotations, DiscardUnpackedLayers, ImagePullWithSyncFs and unpackDuplicationSuppressor - var image containerd.Image + var ( + image containerd.Image + bytesPulled uint64 + ) if c.config.UseLocalImagePull { - image, err = c.pullImageWithLocalPull(ctx, ref, credentials, snapshotter, labels, imagePullProgressTimeout) + image, bytesPulled, err = c.pullImageWithLocalPull(ctx, ref, credentials, snapshotter, labels, imagePullProgressTimeout) } else { - image, err = c.pullImageWithTransferService(ctx, ref, credentials, snapshotter, labels, imagePullProgressTimeout) + image, bytesPulled, err = c.pullImageWithTransferService(ctx, ref, credentials, snapshotter, labels, imagePullProgressTimeout) } if err != nil { @@ -216,13 +219,13 @@ func (c *CRIImageService) PullImage(ctx context.Context, name string, credential } } - const mbToByte = 1024 * 1024 - size, _ := image.Size(ctx) - imagePullingSpeed := float64(size) / mbToByte / time.Since(startTime).Seconds() - imagePullThroughput.Observe(imagePullingSpeed) + elapsed := time.Since(startTime) + recordImagePullThroughput(imagePullThroughput, bytesPulled, elapsed) + recordImagePullThroughput(imagePullThroughputMiBps, bytesPulled, elapsed) + size, _ := image.Size(ctx) log.G(ctx).Infof("Pulled image %q with image id %q, repo tag %q, repo digest %q, size %q in %s", name, imageID, - repoTag, repoDigest, strconv.FormatInt(size, 10), time.Since(startTime)) + repoTag, repoDigest, strconv.FormatInt(size, 10), elapsed) // NOTE(random-liu): the actual state in containerd is the source of truth, even we maintain // in-memory image store, it's only for in-memory indexing. The image could be removed // by someone else anytime, before/during/after we create the metadata. We should always @@ -232,6 +235,10 @@ func (c *CRIImageService) PullImage(ctx context.Context, name string, credential } // pullImageWithLocalPull handles image pulling using the local client. +// +// The returned bytesPulled is the number of bytes actually fetched from the +// registry — cached layers are not counted because they never trigger an +// HTTP request. func (c *CRIImageService) pullImageWithLocalPull( ctx context.Context, ref string, @@ -239,7 +246,7 @@ func (c *CRIImageService) pullImageWithLocalPull( snapshotter string, labels map[string]string, imagePullProgressTimeout time.Duration, -) (containerd.Image, error) { +) (containerd.Image, uint64, error) { pctx, pcancel := context.WithCancel(ctx) defer pcancel() pullReporter := newPullProgressReporter(ref, pcancel, imagePullProgressTimeout) @@ -279,12 +286,17 @@ func (c *CRIImageService) pullImageWithLocalPull( image, err := c.client.Pull(pctx, ref, pullOpts...) pcancel() if err != nil { - return nil, fmt.Errorf("failed to pull and unpack image %q: %w", ref, err) + return nil, 0, fmt.Errorf("failed to pull and unpack image %q: %w", ref, err) } - return image, nil + _, bytesPulled := pullReporter.reqReporter.status() + return image, bytesPulled, nil } // pullImageWithTransferService handles image pulling using the transfer service. +// +// The returned bytesPulled is the number of bytes actually fetched from the +// registry, accumulated from transfer progress events; cached layers emit an +// "already exists" event that does not increment the counter. func (c *CRIImageService) pullImageWithTransferService( ctx context.Context, ref string, @@ -292,7 +304,7 @@ func (c *CRIImageService) pullImageWithTransferService( snapshotter string, labels map[string]string, imagePullProgressTimeout time.Duration, -) (containerd.Image, error) { +) (containerd.Image, uint64, error) { log.G(ctx).Debugf("PullImage %q with snapshotter %s using transfer service", ref, snapshotter) rctx, rcancel := context.WithCancel(ctx) defer rcancel() @@ -318,7 +330,7 @@ func (c *CRIImageService) pullImageWithTransferService( reg, err := registry.NewOCIRegistry(ctx, ref, opts...) if err != nil { - return nil, fmt.Errorf("failed to create OCI registry: %w", err) + return nil, 0, fmt.Errorf("failed to create OCI registry: %w", err) } transferProgressReporter.start(rctx) @@ -326,15 +338,16 @@ func (c *CRIImageService) pullImageWithTransferService( err = c.transferrer.Transfer(rctx, reg, is, transfer.WithProgress(transferProgressReporter.createProgressFunc(rctx))) rcancel() if err != nil { - return nil, fmt.Errorf("failed to pull and unpack image %q: %w", ref, err) + return nil, 0, fmt.Errorf("failed to pull and unpack image %q: %w", ref, err) } // Image should be pulled, unpacked and present in containerd image store at this moment image, err := c.client.GetImage(ctx, ref) if err != nil { - return nil, fmt.Errorf("failed to get image %q from containerd image store: %w", ref, err) + return nil, 0, fmt.Errorf("failed to get image %q from containerd image store: %w", ref, err) } - return image, nil + _, bytesPulled := transferProgressReporter.reqReporter.status() + return image, bytesPulled, nil } // ParseAuth parses AuthConfig and returns username and password/secret required by containerd. diff --git a/internal/cri/server/images/image_pull_test.go b/internal/cri/server/images/image_pull_test.go index e2f1388ae6651..5db59bc1b4ba2 100644 --- a/internal/cri/server/images/image_pull_test.go +++ b/internal/cri/server/images/image_pull_test.go @@ -834,3 +834,66 @@ func TestPullProgressReporter(t *testing.T) { } }) } + +// fakeObserver records every Observe call so tests can assert both the +// presence and the value of observations without touching the real histogram. +type fakeObserver struct { + samples []float64 +} + +func (f *fakeObserver) Observe(v float64) { + f.samples = append(f.samples, v) +} + +func TestRecordImagePullThroughput(t *testing.T) { + for _, tc := range []struct { + name string + bytesPulled uint64 + duration time.Duration + wantSamples int + wantValue float64 // only checked when wantSamples == 1 + }{ + { + name: "fully cached pull is not observed", + bytesPulled: 0, + duration: 2 * time.Second, + wantSamples: 0, + }, + { + name: "zero duration is not observed", + bytesPulled: 10 * mibToByte, + duration: 0, + wantSamples: 0, + }, + { + name: "cold pull observes MiB/s from fetched bytes", + bytesPulled: 10 * mibToByte, + duration: 2 * time.Second, + wantSamples: 1, + wantValue: 5.0, + }, + { + name: "partial cache hit observes only fetched bytes", + // 200 MiB image, 150 MiB cached, 50 MiB actually fetched over 1s. + bytesPulled: 50 * mibToByte, + duration: 1 * time.Second, + wantSamples: 1, + wantValue: 50.0, + }, + { + name: "sub-second pull observes correctly", + bytesPulled: 25 * mibToByte, + duration: 500 * time.Millisecond, + wantSamples: 1, + wantValue: 50.0, + }, + } { + t.Run(tc.name, func(t *testing.T) { + obs := &fakeObserver{} + recordImagePullThroughput(obs, tc.bytesPulled, tc.duration) + if assert.Len(t, obs.samples, tc.wantSamples) && tc.wantSamples == 1 { + assert.InDelta(t, tc.wantValue, obs.samples[0], 0.001) + } + }) + } +} diff --git a/internal/cri/server/images/metrics.go b/internal/cri/server/images/metrics.go index a5b07fbd192d9..5b2b47256702f 100644 --- a/internal/cri/server/images/metrics.go +++ b/internal/cri/server/images/metrics.go @@ -17,15 +17,29 @@ package images import ( + "time" + "github.com/docker/go-metrics" prom "github.com/prometheus/client_golang/prometheus" ) +const mibToByte = 1024 * 1024 + var ( imagePulls metrics.LabeledCounter inProgressImagePulls metrics.Gauge - // image size in MB / image pull duration in seconds + // imagePullThroughput observes one MiB/s sample per image pull: bytes + // actually fetched from the registry over end-to-end pull duration. + // Fully-cached pulls are skipped. + // + // Deprecated: use imagePullThroughputMiBps instead. The new metric has + // the same semantics but more useful buckets — DefBuckets tops out at + // 10 MiB/s and saturates almost immediately on real hardware. imagePullThroughput prom.Histogram + // imagePullThroughputMiBps observes one MiB/s sample per image pull (not + // per layer): bytes actually fetched from the registry over end-to-end + // pull duration (includes extraction). Fully-cached pulls are skipped. + imagePullThroughputMiBps prom.Histogram ) func init() { @@ -44,10 +58,40 @@ func init() { Namespace: namespace, Subsystem: subsystem, Name: "image_pulling_throughput", - Help: "image pull throughput", + Help: "Deprecated: use image_pulling_throughput_mibps instead. Image pull throughput in MiB/s (fetched bytes / pull duration; cached layers excluded).", Buckets: prom.DefBuckets, }, ) + imagePullThroughputMiBps = prom.NewHistogram( + prom.HistogramOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: "image_pulling_throughput_mibps", + Help: "image pull throughput in MiB/s (fetched bytes / pull duration; cached layers excluded)", + // Buckets cover everything from slow registry pulls (0.1 MiB/s) + // to 4000 MiB/s (~31 Gbps), enough for modern 10G+ NICs. The + // top end is intentionally generous: past ~4 GiB/s, disk write + // throughput becomes the bottleneck rather than the network, so + // we don't need finer buckets above that. + Buckets: []float64{0.1, 1, 10, 25, 75, 150, 300, 500, 1000, 2000, 4000}, + }, + ) ns.Add(imagePullThroughput) + ns.Add(imagePullThroughputMiBps) metrics.Register(ns) } + +// recordImagePullThroughput observes one MiB/s sample on obs (intended for +// imagePullThroughputMiBps). bytesPulled is bytes actually fetched from the +// registry — cached layers never trigger a fetch, so they are excluded. +// duration is the end-to-end pull duration (includes extraction, not just +// network transfer). +// +// Pulls that fetched nothing (fully cached) are skipped rather than recorded +// as zero or near-infinite samples, which would pollute the histogram. +func recordImagePullThroughput(obs prom.Observer, bytesPulled uint64, duration time.Duration) { + if bytesPulled == 0 || duration <= 0 { + return + } + obs.Observe(float64(bytesPulled) / mibToByte / duration.Seconds()) +} diff --git a/pkg/archive/tar_windows.go b/pkg/archive/tar_windows.go index dc8f64ee41248..51e8e462f85fb 100644 --- a/pkg/archive/tar_windows.go +++ b/pkg/archive/tar_windows.go @@ -23,7 +23,7 @@ import ( "os" "strings" - "github.com/moby/sys/sequential" + "golang.org/x/sys/windows" ) // chmodTarEntry is used to adjust the file permissions used in tar header based @@ -44,13 +44,21 @@ func setHeaderForSpecialDevice(*tar.Header, string, os.FileInfo) error { func open(p string) (*os.File, error) { // We use sequential file access to avoid depleting the standby list on // Windows. - return sequential.Open(p) + // + // Refer to the [Win32 API documentation] for details on sequential file access. + // + // [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN + return os.OpenFile(p, os.O_RDONLY|windows.O_FILE_FLAG_SEQUENTIAL_SCAN, 0) } func openFile(name string, flag int, perm os.FileMode) (*os.File, error) { // Source is regular file. We use sequential file access to avoid depleting // the standby list on Windows. - return sequential.OpenFile(name, flag, perm) + // + // Refer to the [Win32 API documentation] for details on sequential file access. + // + // [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN + return os.OpenFile(name, flag|windows.O_FILE_FLAG_SEQUENTIAL_SCAN, perm) } func mkdir(path string, perm os.FileMode) error { diff --git a/pkg/oci/spec_opts_user_bounds_test.go b/pkg/oci/spec_opts_user_bounds_test.go index 54384f79a1672..30315c6871ba3 100644 --- a/pkg/oci/spec_opts_user_bounds_test.go +++ b/pkg/oci/spec_opts_user_bounds_test.go @@ -30,6 +30,8 @@ import ( // TestOpenUserFileCapsReads asserts the boundary behavior of the read cap: // well below, ending exactly at, and past maxUserFileBytes. +// +// Regression test for CVE-2026-47262 / GHSA-jpcc-p29g-p8mq func TestOpenUserFileCapsReads(t *testing.T) { t.Parallel() @@ -60,7 +62,13 @@ func TestOpenUserFileCapsReads(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() - data := append(bytes.Repeat([]byte{0}, tc.padBytes), beyond...) + pattern := []byte("# padding\n") + pad := bytes.Repeat(pattern, (tc.padBytes+len(pattern)-1)/len(pattern))[:tc.padBytes] + if len(pad) > 0 { + pad[len(pad)-1] = '\n' + } + + data := append(pad, beyond...) fsys := fstest.MapFS{ "etc/group": &fstest.MapFile{Data: data, Mode: 0o644}, } diff --git a/plugins/snapshots/devmapper/snapshotter.go b/plugins/snapshots/devmapper/snapshotter.go index 5ec9baed8dbf5..538ef123578a1 100644 --- a/plugins/snapshots/devmapper/snapshotter.go +++ b/plugins/snapshots/devmapper/snapshotter.go @@ -428,8 +428,13 @@ func (s *Snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, k errs = append(errs, sErr) } + poolStatus := "unavailable" + if status != nil { + poolStatus = status.RawOutput + } + // Rollback thin device creation if mkfs failed - log.G(ctx).WithError(errors.Join(errs...)).Errorf("failed to initialize thin device %q for snapshot %s pool status %s", deviceName, snap.ID, status.RawOutput) + log.G(ctx).WithError(errors.Join(errs...)).Errorf("failed to initialize thin device %q for snapshot %s pool status %s", deviceName, snap.ID, poolStatus) return nil, errors.Join(append(errs, s.pool.RemoveDevice(ctx, deviceName))...) } } else { diff --git a/vendor/github.com/moby/sys/sequential/LICENSE b/vendor/github.com/moby/sys/sequential/LICENSE deleted file mode 100644 index d645695673349..0000000000000 --- a/vendor/github.com/moby/sys/sequential/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/moby/sys/sequential/doc.go b/vendor/github.com/moby/sys/sequential/doc.go deleted file mode 100644 index af2817504b7a0..0000000000000 --- a/vendor/github.com/moby/sys/sequential/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Package sequential provides a set of functions for managing sequential -// files on Windows. -// -// The origin of these functions are the golang OS and windows packages, -// slightly modified to only cope with files, not directories due to the -// specific use case. -// -// The alteration is to allow a file on Windows to be opened with -// FILE_FLAG_SEQUENTIAL_SCAN (particular for docker load), to avoid eating -// the standby list, particularly when accessing large files such as layer.tar. -// -// For non-Windows platforms, the package provides wrappers for the equivalents -// in the os packages. They are passthrough on Unix platforms, and only relevant -// on Windows. -package sequential diff --git a/vendor/github.com/moby/sys/sequential/sequential_unix.go b/vendor/github.com/moby/sys/sequential/sequential_unix.go deleted file mode 100644 index 24c7c4be4e18a..0000000000000 --- a/vendor/github.com/moby/sys/sequential/sequential_unix.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build !windows - -package sequential - -import "os" - -// Create is an alias for [os.Create] on non-Windows platforms. -func Create(name string) (*os.File, error) { - return os.Create(name) -} - -// Open is an alias for [os.Open] on non-Windows platforms. -func Open(name string) (*os.File, error) { - return os.Open(name) -} - -// OpenFile is an alias for [os.OpenFile] on non-Windows platforms. -func OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) { - return os.OpenFile(name, flag, perm) -} - -// CreateTemp is an alias for [os.CreateTemp] on non-Windows platforms. -func CreateTemp(dir, prefix string) (f *os.File, err error) { - return os.CreateTemp(dir, prefix) -} diff --git a/vendor/github.com/moby/sys/sequential/sequential_windows.go b/vendor/github.com/moby/sys/sequential/sequential_windows.go deleted file mode 100644 index a8bfc3265d3a0..0000000000000 --- a/vendor/github.com/moby/sys/sequential/sequential_windows.go +++ /dev/null @@ -1,91 +0,0 @@ -//go:build windows - -package sequential - -import ( - "os" - "path/filepath" - "strconv" - "sync" - "time" -) - -// Create is a copy of [os.Create], modified to use sequential file access. -// -// It uses the Windows sequential scan file flag. Refer to the [Win32 API -// documentation] for details on sequential file access. -// -// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN -func Create(name string) (*os.File, error) { - return openFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666) -} - -// Open is a copy of [os.Open], modified to use sequential file access. -// -// It uses the Windows sequential scan file flag. Refer to the [Win32 API -// documentation] for details on sequential file access. -// -// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN -func Open(name string) (*os.File, error) { - return openFileSequential(name, os.O_RDONLY, 0) -} - -// OpenFile is a copy of [os.OpenFile], modified to use sequential file access. -// -// It uses the Windows sequential scan file flag. Refer to the [Win32 API -// documentation] for details on sequential file access. -// -// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN -func OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) { - return openFileSequential(name, flag, perm) -} - -// Helpers for CreateTemp -var ( - rand uint32 - randmu sync.Mutex -) - -func reseed() uint32 { - return uint32(time.Now().UnixNano() + int64(os.Getpid())) -} - -func nextSuffix() string { - randmu.Lock() - r := rand - if r == 0 { - r = reseed() - } - r = r*1664525 + 1013904223 // constants from Numerical Recipes - rand = r - randmu.Unlock() - return strconv.Itoa(int(1e9 + r%1e9))[1:] -} - -// CreateTemp is a copy of [os.CreateTemp], modified to use sequential file access. -// -// It uses the Windows sequential scan file flag. Refer to the [Win32 API -// documentation] for details on sequential file access. -// -// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN -func CreateTemp(dir, prefix string) (f *os.File, err error) { - if dir == "" { - dir = os.TempDir() - } - - nconflict := 0 - for range 10000 { - name := filepath.Join(dir, prefix+nextSuffix()) - f, err = openFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o600) - if os.IsExist(err) { - if nconflict++; nconflict > 10 { - randmu.Lock() - rand = reseed() - randmu.Unlock() - } - continue - } - break - } - return -} diff --git a/vendor/github.com/moby/sys/sequential/sequential_windows_go126.go b/vendor/github.com/moby/sys/sequential/sequential_windows_go126.go deleted file mode 100644 index 926c4201d3c77..0000000000000 --- a/vendor/github.com/moby/sys/sequential/sequential_windows_go126.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:build windows && go1.26 - -package sequential - -import ( - "os" - - "golang.org/x/sys/windows" -) - -func openFileSequential(name string, flag int, perm os.FileMode) (*os.File, error) { - return os.OpenFile(name, flag|windows.O_FILE_FLAG_SEQUENTIAL_SCAN, perm) -} diff --git a/vendor/github.com/moby/sys/sequential/sequential_windows_pre126.go b/vendor/github.com/moby/sys/sequential/sequential_windows_pre126.go deleted file mode 100644 index fa8129cf2688b..0000000000000 --- a/vendor/github.com/moby/sys/sequential/sequential_windows_pre126.go +++ /dev/null @@ -1,76 +0,0 @@ -//go:build windows && !go1.26 - -package sequential - -import ( - "os" - "unsafe" - - "golang.org/x/sys/windows" -) - -func openFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) { - if name == "" { - return nil, &os.PathError{Op: "open", Path: name, Err: windows.ERROR_FILE_NOT_FOUND} - } - r, e := openSequential(name, flag|windows.O_CLOEXEC) - if e != nil { - return nil, &os.PathError{Op: "open", Path: name, Err: e} - } - return os.NewFile(uintptr(r), name), nil -} - -func makeInheritSa() *windows.SecurityAttributes { - var sa windows.SecurityAttributes - sa.Length = uint32(unsafe.Sizeof(sa)) - sa.InheritHandle = 1 - return &sa -} - -func openSequential(path string, mode int) (fd windows.Handle, err error) { - if len(path) == 0 { - return windows.InvalidHandle, windows.ERROR_FILE_NOT_FOUND - } - pathp, err := windows.UTF16PtrFromString(path) - if err != nil { - return windows.InvalidHandle, err - } - var access uint32 - switch mode & (windows.O_RDONLY | windows.O_WRONLY | windows.O_RDWR) { - case windows.O_RDONLY: - access = windows.GENERIC_READ - case windows.O_WRONLY: - access = windows.GENERIC_WRITE - case windows.O_RDWR: - access = windows.GENERIC_READ | windows.GENERIC_WRITE - } - if mode&windows.O_CREAT != 0 { - access |= windows.GENERIC_WRITE - } - if mode&windows.O_APPEND != 0 { - access &^= windows.GENERIC_WRITE - access |= windows.FILE_APPEND_DATA - } - sharemode := uint32(windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE) - var sa *windows.SecurityAttributes - if mode&windows.O_CLOEXEC == 0 { - sa = makeInheritSa() - } - var createmode uint32 - switch { - case mode&(windows.O_CREAT|windows.O_EXCL) == (windows.O_CREAT | windows.O_EXCL): - createmode = windows.CREATE_NEW - case mode&(windows.O_CREAT|windows.O_TRUNC) == (windows.O_CREAT | windows.O_TRUNC): - createmode = windows.CREATE_ALWAYS - case mode&windows.O_CREAT == windows.O_CREAT: - createmode = windows.OPEN_ALWAYS - case mode&windows.O_TRUNC == windows.O_TRUNC: - createmode = windows.TRUNCATE_EXISTING - default: - createmode = windows.OPEN_EXISTING - } - // Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang. - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN - h, e := windows.CreateFile(pathp, access, sharemode, sa, createmode, windows.FILE_FLAG_SEQUENTIAL_SCAN, 0) - return h, e -} diff --git a/vendor/modules.txt b/vendor/modules.txt index b27624c35e2c8..5e999a43af4ea 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -417,9 +417,6 @@ github.com/moby/sys/capability # github.com/moby/sys/mountinfo v0.7.2 ## explicit; go 1.17 github.com/moby/sys/mountinfo -# github.com/moby/sys/sequential v0.7.0 -## explicit; go 1.24.0 -github.com/moby/sys/sequential # github.com/moby/sys/signal v0.7.1 ## explicit; go 1.17 github.com/moby/sys/signal