mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-10-14 09:57:41 +00:00
Merge pull request #28642 from mheon/check_buildah_vendor
Vendor container-libs and Buildah at main
This commit is contained in:
commit
dac8c35dd6
31 changed files with 788 additions and 615 deletions
12
go.mod
12
go.mod
|
|
@ -63,10 +63,10 @@ require (
|
|||
github.com/stretchr/testify v1.11.1
|
||||
github.com/vbauerster/mpb/v8 v8.12.0
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
go.podman.io/buildah v1.42.1-0.20260421143840-0acb6b8cca85
|
||||
go.podman.io/common v0.67.2-0.20260430194920-3ceb1b29d72d
|
||||
go.podman.io/image/v5 v5.39.3-0.20260430194920-3ceb1b29d72d
|
||||
go.podman.io/storage v1.62.1-0.20260430194920-3ceb1b29d72d
|
||||
go.podman.io/buildah v1.42.1-0.20260501153811-377cf64e213b
|
||||
go.podman.io/common v0.67.2-0.20260504145149-b5d50461d3b9
|
||||
go.podman.io/image/v5 v5.39.3-0.20260504145149-b5d50461d3b9
|
||||
go.podman.io/storage v1.62.1-0.20260504145149-b5d50461d3b9
|
||||
golang.org/x/crypto v0.50.0
|
||||
golang.org/x/net v0.53.0
|
||||
golang.org/x/sync v0.20.0
|
||||
|
|
@ -112,7 +112,7 @@ require (
|
|||
github.com/docker/docker-credential-helpers v0.9.6 // indirect
|
||||
github.com/ebitengine/purego v0.10.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.10.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.10.1 // indirect
|
||||
github.com/fsouza/go-dockerclient v1.13.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
|
|
@ -168,7 +168,7 @@ require (
|
|||
github.com/tklauser/numcpus v0.11.0 // indirect
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
|
||||
github.com/ulikunitz/xz v0.5.15 // indirect
|
||||
github.com/vbatts/tar-split v0.12.2 // indirect
|
||||
github.com/vbatts/tar-split v0.12.3 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.etcd.io/bbolt v1.4.3 // indirect
|
||||
|
|
|
|||
28
go.sum
28
go.sum
|
|
@ -98,8 +98,8 @@ github.com/disiqueira/gotree/v3 v3.0.2 h1:ik5iuLQQoufZBNPY518dXhiO5056hyNBIK9lWh
|
|||
github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v29.4.1+incompatible h1:02RT8QqqwtGRn+6SYypv8IUEbD/ltY6sfKCJIoUcGzk=
|
||||
github.com/docker/cli v29.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v29.4.2+incompatible h1:nhxMY4v7wB0QMMc5ppeqV6FBMwzqv0n4t2gogu/R2DQ=
|
||||
github.com/docker/cli v29.4.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker-credential-helpers v0.9.6 h1:cT2PbRPSlnMmNTfT2TDMXRyQ1KMWHG7xoTLBcn1ZNv0=
|
||||
|
|
@ -119,8 +119,8 @@ github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/
|
|||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fsnotify/fsnotify v1.10.0 h1:Xx/5Ydg9CeBDX/wi4VJqStNtohYjitZhhlHt4h3St1M=
|
||||
github.com/fsnotify/fsnotify v1.10.0/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||
github.com/fsouza/go-dockerclient v1.13.1 h1:HbkJO8UPUhuQ1wHIgX+ho7AUucBmjtOfzSWYUgmWL/8=
|
||||
github.com/fsouza/go-dockerclient v1.13.1/go.mod h1:0gx0SIFGV1F+79sM9p5K+UCc8enYKA8DBp7BlwlixpM=
|
||||
github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs=
|
||||
|
|
@ -383,8 +383,8 @@ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8
|
|||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
|
||||
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
||||
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4=
|
||||
github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
|
||||
github.com/vbatts/tar-split v0.12.3 h1:Cd46rkGXI3Td4yrVNwU8ripbxFaQbmesqhjBUUYAJSw=
|
||||
github.com/vbatts/tar-split v0.12.3/go.mod h1:sQOc6OlqGCr7HkGx/IDBeKiTIvqhmj8KffNhEXG4Nq0=
|
||||
github.com/vbauerster/mpb/v8 v8.12.0 h1:+gneY3ifzc88tKDzOtfG8k8gfngCx615S2ZmFM4liWg=
|
||||
github.com/vbauerster/mpb/v8 v8.12.0/go.mod h1:V02YIuMVo301Y1VE9VtZlD8s84OMsk+EKN6mwvf/588=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
|
|
@ -429,14 +429,14 @@ go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfC
|
|||
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
|
||||
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
|
||||
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
|
||||
go.podman.io/buildah v1.42.1-0.20260421143840-0acb6b8cca85 h1:rVKRagobPO6kGHOg2NhGNs6xWVgZctiOn4tmxa3cytA=
|
||||
go.podman.io/buildah v1.42.1-0.20260421143840-0acb6b8cca85/go.mod h1:JjFirF1zlILz55ZkVYYhLRnted7mPlmoS2w2ihYw8iw=
|
||||
go.podman.io/common v0.67.2-0.20260430194920-3ceb1b29d72d h1:cfi7hq9/Y8BaCppWFnRfSYQq6VARfEpdbrd7Tysosy4=
|
||||
go.podman.io/common v0.67.2-0.20260430194920-3ceb1b29d72d/go.mod h1:iRT7GS3Ju8VxV8cyPQ6Ts5z4Zu1l8NHG7k+3sU17Xww=
|
||||
go.podman.io/image/v5 v5.39.3-0.20260430194920-3ceb1b29d72d h1:CW23G56hYIAb+nHiRSa+J8UE+G6DS3MSvAnz05fk2o4=
|
||||
go.podman.io/image/v5 v5.39.3-0.20260430194920-3ceb1b29d72d/go.mod h1:VBEYYXmGMYh+oAZZc1tPCVYWiCnbW16SAZfLGJMfxwE=
|
||||
go.podman.io/storage v1.62.1-0.20260430194920-3ceb1b29d72d h1:JHvCWd1irnPVwjP2srHfLEs+tpHLqNq81g9XTLXmQ4g=
|
||||
go.podman.io/storage v1.62.1-0.20260430194920-3ceb1b29d72d/go.mod h1:c2/RBYEPTpqJ4BQfI3nDZB5zUKXuhX1nSGgrunZV2TM=
|
||||
go.podman.io/buildah v1.42.1-0.20260501153811-377cf64e213b h1:i8ntFzITajbJA3ojnA0ZdpbC+I+ccweZvZaGIhQb4i8=
|
||||
go.podman.io/buildah v1.42.1-0.20260501153811-377cf64e213b/go.mod h1:hPvgsjBU09C+15fKoIZJvKvNaxR+c0QvMg/n4NgBS7A=
|
||||
go.podman.io/common v0.67.2-0.20260504145149-b5d50461d3b9 h1:rhSZjo2liJOlaa3SzPLvDTD93MDi4bl6E3RKTME9Hrc=
|
||||
go.podman.io/common v0.67.2-0.20260504145149-b5d50461d3b9/go.mod h1:TYI+ocF4gfL8QCBo5GqOSUAOA3QnVgkjjg/nQZRG3o0=
|
||||
go.podman.io/image/v5 v5.39.3-0.20260504145149-b5d50461d3b9 h1:xAeC/aqHQ01RWHq60B1FETR65XW2kfIaOBEmYNJFunc=
|
||||
go.podman.io/image/v5 v5.39.3-0.20260504145149-b5d50461d3b9/go.mod h1:D+09OPzsrFuzeKqsJEaaxtItkSd12+eZyOdFyuJF8TY=
|
||||
go.podman.io/storage v1.62.1-0.20260504145149-b5d50461d3b9 h1:1rviLyzh9boijwxX4UK6U6XUmE1Qyl21XPUSHNKTh0s=
|
||||
go.podman.io/storage v1.62.1-0.20260504145149-b5d50461d3b9/go.mod h1:eZIqDigffFi9NlPezLvUVw/nsUIruaui436E5E4GmXs=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
|
|
|
|||
15
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
15
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
|
|
@ -1,5 +1,20 @@
|
|||
# Changelog
|
||||
|
||||
1.10.1 2026-05-04
|
||||
-----------------
|
||||
|
||||
### Changes and fixes
|
||||
|
||||
- inotify: don't remove sibling watches sharing a path prefix ([#754])
|
||||
|
||||
- inotify, windows: don't rename sibling watches sharing a path prefix
|
||||
([#755])
|
||||
|
||||
|
||||
[#754]: https://github.com/fsnotify/fsnotify/pull/754
|
||||
[#755]: https://github.com/fsnotify/fsnotify/pull/755
|
||||
|
||||
|
||||
1.10.0 2026-04-30
|
||||
-----------------
|
||||
This version of fsnotify needs Go 1.23.
|
||||
|
|
|
|||
32
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
32
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
|
|
@ -171,6 +171,38 @@ distro's documentation):
|
|||
fs.inotify.max_user_watches=200000
|
||||
fs.inotify.max_user_instances=256
|
||||
|
||||
### Windows
|
||||
Recursive watching is not currently enabled through fsnotify's public API
|
||||
(see the FAQ "Are subdirectories watched?" above). The notes below
|
||||
describe Windows backend behavior observed when recursive watching is
|
||||
enabled internally (for example, in fsnotify's own tests). They are kept
|
||||
here as a reference for maintainers and contributors who encounter the
|
||||
behavior, since the recursive code path still exists in the backend.
|
||||
|
||||
When recursive watching is enabled and you watch a directory, you may
|
||||
receive a `Write` event for an intermediate directory whenever a child
|
||||
entry inside it is created, renamed, or removed. For example, with a
|
||||
recursive watch on `/a` and a new file `/a/b/c`, you will receive
|
||||
`Create /a/b/c` and may also receive `Write /a/b`.
|
||||
|
||||
This happens because, on NTFS-backed volumes, modifying the entries of a
|
||||
directory updates that directory's last-write time, and the Windows
|
||||
backend requests `FILE_NOTIFY_CHANGE_LAST_WRITE` to support `Write` events
|
||||
on files. The same `Write` filter therefore picks up the directory's
|
||||
metadata update.
|
||||
|
||||
kqueue has the same "directory `Write` = directory contents changed"
|
||||
semantics, so portable code that treats `Write` on a directory as
|
||||
"something inside it changed" works on Windows and BSD/macOS, but not on
|
||||
Linux (inotify uses `Write` only for file-content changes). If you only
|
||||
care about file content, filter out `Write` events whose path refers to a
|
||||
directory.
|
||||
|
||||
Whether the directory `Write` is actually delivered alongside the child
|
||||
events is not guaranteed: it depends on `ReadDirectoryChangesW` buffering,
|
||||
NTFS metadata update timing, and event coalescing, none of which fsnotify
|
||||
controls.
|
||||
|
||||
|
||||
### kqueue (macOS, all BSD systems)
|
||||
kqueue requires opening a file descriptor for every file that's being watched;
|
||||
|
|
|
|||
11
vendor/github.com/fsnotify/fsnotify/backend_inotify.go
generated
vendored
11
vendor/github.com/fsnotify/fsnotify/backend_inotify.go
generated
vendored
|
|
@ -82,6 +82,13 @@ func (w *watches) len() int { return len(w.wd) }
|
|||
func (w *watches) add(ww *watch) { w.wd[ww.wd] = ww; w.path[ww.path] = ww.wd }
|
||||
func (w *watches) remove(watch *watch) { delete(w.path, watch.path); delete(w.wd, watch.wd) }
|
||||
|
||||
func isSameOrDescendantPath(path, root string) bool {
|
||||
if path == root {
|
||||
return true
|
||||
}
|
||||
return strings.HasPrefix(path, root+string(os.PathSeparator))
|
||||
}
|
||||
|
||||
func (w *watches) removePath(path string) ([]uint32, error) {
|
||||
path, recurse := recursivePath(path)
|
||||
wd, ok := w.path[path]
|
||||
|
|
@ -103,7 +110,7 @@ func (w *watches) removePath(path string) ([]uint32, error) {
|
|||
wds := make([]uint32, 0, 8)
|
||||
wds = append(wds, wd)
|
||||
for p, rwd := range w.path {
|
||||
if strings.HasPrefix(p, path) {
|
||||
if isSameOrDescendantPath(p, path) {
|
||||
delete(w.path, p)
|
||||
delete(w.wd, rwd)
|
||||
wds = append(wds, rwd)
|
||||
|
|
@ -501,7 +508,7 @@ func (w *inotify) handleEvent(inEvent *unix.InotifyEvent, buf *[65536]byte, offs
|
|||
if k == watch.wd || ww.path == ev.Name {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(ww.path, ev.renamedFrom) {
|
||||
if isSameOrDescendantPath(ww.path, ev.renamedFrom) {
|
||||
ww.path = strings.Replace(ww.path, ev.renamedFrom, ev.Name, 1)
|
||||
w.watches.wd[k] = ww
|
||||
}
|
||||
|
|
|
|||
9
vendor/github.com/fsnotify/fsnotify/backend_windows.go
generated
vendored
9
vendor/github.com/fsnotify/fsnotify/backend_windows.go
generated
vendored
|
|
@ -36,6 +36,13 @@ type readDirChangesW struct {
|
|||
|
||||
var defaultBufferSize = 50
|
||||
|
||||
func isSameOrDescendantPath(path, root string) bool {
|
||||
if path == root {
|
||||
return true
|
||||
}
|
||||
return strings.HasPrefix(path, root+string(os.PathSeparator))
|
||||
}
|
||||
|
||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
|
||||
port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0)
|
||||
if err != nil {
|
||||
|
|
@ -605,7 +612,7 @@ func (w *readDirChangesW) readEvents() {
|
|||
w.mu.Lock()
|
||||
for _, watchMap := range w.watches {
|
||||
for _, ww := range watchMap {
|
||||
if strings.HasPrefix(ww.path, old) {
|
||||
if isSameOrDescendantPath(ww.path, old) {
|
||||
ww.path = filepath.Join(fullname, strings.TrimPrefix(ww.path, old))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
34
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
34
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
|
|
@ -92,6 +92,28 @@ import (
|
|||
// Sometimes it will send events for all files, sometimes it will send no
|
||||
// events, and often only for some files.
|
||||
//
|
||||
// Recursive watching is not currently enabled through fsnotify's public
|
||||
// API; the recursive code path is gated and only exercised by fsnotify's
|
||||
// own tests. The note below describes backend behavior observed when
|
||||
// recursive watching is enabled internally, and is kept here as a
|
||||
// reference for maintainers and contributors who encounter it.
|
||||
//
|
||||
// When recursive watching is enabled and you watch a directory, you may
|
||||
// receive a Write event for an intermediate directory whenever a child
|
||||
// entry inside it is created, renamed, or removed. For example, with a
|
||||
// recursive watch on /a and a new file /a/b/c, you will receive
|
||||
// Create /a/b/c and may also receive Write /a/b.
|
||||
//
|
||||
// This happens because, on NTFS-backed volumes, modifying the entries of a
|
||||
// directory updates that directory's last-write time, and the Windows
|
||||
// backend requests FILE_NOTIFY_CHANGE_LAST_WRITE to support Write events
|
||||
// on files. The same Write filter therefore picks up the directory's
|
||||
// metadata update.
|
||||
//
|
||||
// Whether the directory Write is actually delivered alongside the child
|
||||
// events is not guaranteed; it depends on ReadDirectoryChangesW buffering,
|
||||
// NTFS metadata update timing, and event coalescing.
|
||||
//
|
||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
||||
// events in quick succession this may not be enough, and you will have to use
|
||||
|
|
@ -128,8 +150,12 @@ type Watcher struct {
|
|||
// want to wait until you've stopped receiving them
|
||||
// (see the dedup example in cmd/fsnotify).
|
||||
//
|
||||
// Some systems may send Write event for directories
|
||||
// when the directory content changes.
|
||||
// Some systems also send Write events for directories
|
||||
// when the directory contents change. This is the
|
||||
// case for kqueue, and on Windows for the directory
|
||||
// that contains a created, renamed, or removed child
|
||||
// entry. It does not happen on inotify. See the
|
||||
// per-platform notes on [Watcher].
|
||||
//
|
||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
||||
// when a file is removed (or more accurately, when a
|
||||
|
|
@ -178,7 +204,9 @@ const (
|
|||
Create Op = 1 << iota
|
||||
|
||||
// The pathname was written to; this does *not* mean the write has finished,
|
||||
// and a write can be followed by more writes.
|
||||
// and a write can be followed by more writes. On Windows and kqueue, a
|
||||
// Write on a directory can also indicate that its contents changed; see
|
||||
// the per-platform notes on [Watcher].
|
||||
Write
|
||||
|
||||
// The path was removed; any watches on it will be removed. Some "remove"
|
||||
|
|
|
|||
20
vendor/github.com/opencontainers/runc/libcontainer/devices/device_deprecated.go
generated
vendored
20
vendor/github.com/opencontainers/runc/libcontainer/devices/device_deprecated.go
generated
vendored
|
|
@ -1,20 +0,0 @@
|
|||
package devices
|
||||
|
||||
import "github.com/opencontainers/cgroups/devices/config"
|
||||
|
||||
// Deprecated: use [github.com/opencontainers/cgroups/devices/config].
|
||||
const (
|
||||
Wildcard = config.Wildcard
|
||||
WildcardDevice = config.WildcardDevice
|
||||
BlockDevice = config.BlockDevice
|
||||
CharDevice = config.CharDevice
|
||||
FifoDevice = config.FifoDevice
|
||||
)
|
||||
|
||||
// Deprecated: use [github.com/opencontainers/cgroups/devices/config].
|
||||
type (
|
||||
Device = config.Device
|
||||
Permissions = config.Permissions
|
||||
Type = config.Type
|
||||
Rule = config.Rule
|
||||
)
|
||||
112
vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go
generated
vendored
112
vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go
generated
vendored
|
|
@ -1,112 +0,0 @@
|
|||
//go:build !windows
|
||||
|
||||
package devices
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// ErrNotADevice denotes that a file is not a valid linux device.
|
||||
var ErrNotADevice = errors.New("not a device node")
|
||||
|
||||
// Testing dependencies
|
||||
var (
|
||||
unixLstat = unix.Lstat
|
||||
osReadDir = os.ReadDir
|
||||
)
|
||||
|
||||
// DeviceFromPath takes the path to a device and its cgroup_permissions (which
|
||||
// cannot be easily queried) to look up the information about a linux device
|
||||
// and returns that information as a Device struct.
|
||||
func DeviceFromPath(path, permissions string) (*Device, error) {
|
||||
var stat unix.Stat_t
|
||||
err := unixLstat(path, &stat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
devType Type
|
||||
mode = stat.Mode
|
||||
devNumber = uint64(stat.Rdev) //nolint:unconvert // Rdev is uint32 on e.g. MIPS.
|
||||
major = unix.Major(devNumber)
|
||||
minor = unix.Minor(devNumber)
|
||||
)
|
||||
switch mode & unix.S_IFMT {
|
||||
case unix.S_IFBLK:
|
||||
devType = BlockDevice
|
||||
case unix.S_IFCHR:
|
||||
devType = CharDevice
|
||||
case unix.S_IFIFO:
|
||||
devType = FifoDevice
|
||||
default:
|
||||
return nil, ErrNotADevice
|
||||
}
|
||||
return &Device{
|
||||
Rule: Rule{
|
||||
Type: devType,
|
||||
Major: int64(major),
|
||||
Minor: int64(minor),
|
||||
Permissions: Permissions(permissions),
|
||||
},
|
||||
Path: path,
|
||||
FileMode: os.FileMode(mode &^ unix.S_IFMT),
|
||||
Uid: stat.Uid,
|
||||
Gid: stat.Gid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// HostDevices returns all devices that can be found under /dev directory.
|
||||
func HostDevices() ([]*Device, error) {
|
||||
return GetDevices("/dev")
|
||||
}
|
||||
|
||||
// GetDevices recursively traverses a directory specified by path
|
||||
// and returns all devices found there.
|
||||
func GetDevices(path string) ([]*Device, error) {
|
||||
files, err := osReadDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []*Device
|
||||
for _, f := range files {
|
||||
switch {
|
||||
case f.IsDir():
|
||||
switch f.Name() {
|
||||
// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
|
||||
// ".udev" added to address https://github.com/opencontainers/runc/issues/2093
|
||||
case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev":
|
||||
continue
|
||||
default:
|
||||
sub, err := GetDevices(filepath.Join(path, f.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, sub...)
|
||||
continue
|
||||
}
|
||||
case f.Name() == "console":
|
||||
continue
|
||||
}
|
||||
device, err := DeviceFromPath(filepath.Join(path, f.Name()), "rwm")
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrNotADevice) {
|
||||
continue
|
||||
}
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if device.Type == FifoDevice {
|
||||
continue
|
||||
}
|
||||
out = append(out, device)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
6
vendor/github.com/vbatts/tar-split/archive/tar/format.go
generated
vendored
6
vendor/github.com/vbatts/tar-split/archive/tar/format.go
generated
vendored
|
|
@ -147,6 +147,12 @@ const (
|
|||
// Max length of a special file (PAX header, GNU long name or link).
|
||||
// This matches the limit used by libarchive.
|
||||
maxSpecialFileSize = 1 << 20
|
||||
|
||||
// Maximum number of sparse file entries.
|
||||
// We should never actually hit this limit
|
||||
// (every sparse encoding will first be limited by maxSpecialFileSize),
|
||||
// but this adds an additional layer of defense.
|
||||
maxSparseFileEntries = 1 << 20
|
||||
)
|
||||
|
||||
// blockPadding computes the number of bytes needed to pad offset up to the
|
||||
|
|
|
|||
28
vendor/github.com/vbatts/tar-split/archive/tar/reader.go
generated
vendored
28
vendor/github.com/vbatts/tar-split/archive/tar/reader.go
generated
vendored
|
|
@ -537,7 +537,8 @@ func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, err
|
|||
}
|
||||
s := blk.GNU().Sparse()
|
||||
spd := make(sparseDatas, 0, s.MaxEntries())
|
||||
for {
|
||||
totalSize := len(s)
|
||||
for totalSize < maxSpecialFileSize {
|
||||
for i := 0; i < s.MaxEntries(); i++ {
|
||||
// This termination condition is identical to GNU and BSD tar.
|
||||
if s.Entry(i).Offset()[0] == 0x00 {
|
||||
|
|
@ -548,7 +549,11 @@ func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, err
|
|||
if p.err != nil {
|
||||
return nil, p.err
|
||||
}
|
||||
spd = append(spd, sparseEntry{Offset: offset, Length: length})
|
||||
var err error
|
||||
spd, err = appendSparseEntry(spd, sparseEntry{Offset: offset, Length: length})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if s.IsExtended()[0] > 0 {
|
||||
|
|
@ -560,10 +565,12 @@ func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, err
|
|||
tr.rawBytes.Write(blk[:])
|
||||
}
|
||||
s = blk.Sparse()
|
||||
totalSize += len(s)
|
||||
continue
|
||||
}
|
||||
return spd, nil // Done
|
||||
}
|
||||
return nil, errSparseTooLong
|
||||
}
|
||||
|
||||
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
|
||||
|
|
@ -636,7 +643,10 @@ func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
|
|||
if err1 != nil || err2 != nil {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
spd = append(spd, sparseEntry{Offset: offset, Length: length})
|
||||
spd, err = appendSparseEntry(spd, sparseEntry{Offset: offset, Length: length})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return spd, nil
|
||||
}
|
||||
|
|
@ -670,12 +680,22 @@ func readGNUSparseMap0x1(paxHdrs map[string]string) (sparseDatas, error) {
|
|||
if err1 != nil || err2 != nil {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
spd = append(spd, sparseEntry{Offset: offset, Length: length})
|
||||
spd, err = appendSparseEntry(spd, sparseEntry{Offset: offset, Length: length})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sparseMap = sparseMap[2:]
|
||||
}
|
||||
return spd, nil
|
||||
}
|
||||
|
||||
func appendSparseEntry(spd sparseDatas, ent sparseEntry) (sparseDatas, error) {
|
||||
if len(spd) >= maxSparseFileEntries {
|
||||
return nil, errSparseTooLong
|
||||
}
|
||||
return append(spd, ent), nil
|
||||
}
|
||||
|
||||
// Read reads from the current file in the tar archive.
|
||||
// It returns (0, io.EOF) when it reaches the end of that file,
|
||||
// until Next is called to advance to the next file.
|
||||
|
|
|
|||
325
vendor/github.com/vbatts/tar-split/tar/asm/disassemble.go
generated
vendored
325
vendor/github.com/vbatts/tar-split/tar/asm/disassemble.go
generated
vendored
|
|
@ -1,23 +1,168 @@
|
|||
package asm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/vbatts/tar-split/archive/tar"
|
||||
"github.com/vbatts/tar-split/tar/storage"
|
||||
)
|
||||
|
||||
// NewInputTarStream wraps the Reader stream of a tar archive and provides a
|
||||
// Reader stream of the same.
|
||||
// runInputTarStreamGoroutine is the goroutine entrypoint.
|
||||
//
|
||||
// In the middle it will pack the segments and file metadata to storage.Packer
|
||||
// `p`.
|
||||
// It centralizes the goroutine protocol so the core parsing logic can be
|
||||
// written as ordinary Go code that just "returns an error".
|
||||
//
|
||||
// The the storage.FilePutter is where payload of files in the stream are
|
||||
// stashed. If this stashing is not needed, you can provide a nil
|
||||
// storage.FilePutter. Since the checksumming is still needed, then a default
|
||||
// of NewDiscardFilePutter will be used internally
|
||||
func NewInputTarStream(r io.Reader, p storage.Packer, fp storage.FilePutter) (io.Reader, error) {
|
||||
// Protocol guarantees:
|
||||
// - pW is always closed exactly once (CloseWithError(nil) == Close()).
|
||||
// - if done != nil, exactly one value is sent (nil on success, non-nil on failure).
|
||||
// - panics are converted into a non-nil error (and the panic is rethrown).
|
||||
func runInputTarStreamGoroutine(outputRdr io.Reader, pW *io.PipeWriter, p storage.Packer, fp storage.FilePutter, done chan<- error) {
|
||||
// Default to a non-nil error so a panic can't accidentally look like success.
|
||||
err := errors.New("panic in runInputTarStream")
|
||||
defer func() {
|
||||
// CloseWithError(nil) is equivalent to Close().
|
||||
pW.CloseWithError(err)
|
||||
|
||||
if done != nil {
|
||||
done <- err
|
||||
}
|
||||
|
||||
// Preserve panic semantics while still ensuring the protocol above runs.
|
||||
if r := recover(); r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
err = runInputTarStream(outputRdr, p, fp)
|
||||
}
|
||||
|
||||
// runInputTarStream drives tar-split parsing.
|
||||
//
|
||||
// It reads a tar stream from outputRdr and records tar-split metadata into the
|
||||
// provided storage.Packer.
|
||||
//
|
||||
// Abort behavior: if the consumer closes the read end early, the tee reader will
|
||||
// stop producing bytes (due to pipe write failure) and tar parsing will return
|
||||
// an error. We propagate that error so the goroutine terminates promptly rather
|
||||
// than draining the input stream for no benefit.
|
||||
func runInputTarStream(outputRdr io.Reader, p storage.Packer, fp storage.FilePutter) error {
|
||||
tr := tar.NewReader(outputRdr)
|
||||
tr.RawAccounting = true
|
||||
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
return err
|
||||
}
|
||||
// Even when EOF is reached, there is often 1024 null bytes at the end
|
||||
// of an archive. Collect them too.
|
||||
if b := tr.RawBytes(); len(b) > 0 {
|
||||
if _, err := p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: b,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
break // Not return: we still need to drain any additional padding.
|
||||
}
|
||||
if hdr == nil {
|
||||
break // Not return: we still need to drain any additional padding.
|
||||
}
|
||||
|
||||
if b := tr.RawBytes(); len(b) > 0 {
|
||||
if _, err := p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: b,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var csum []byte
|
||||
if hdr.Size > 0 {
|
||||
_, csum, err = fp.Put(hdr.Name, tr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
entry := storage.Entry{
|
||||
Type: storage.FileType,
|
||||
Size: hdr.Size,
|
||||
Payload: csum,
|
||||
}
|
||||
// For proper marshalling of non-utf8 characters
|
||||
entry.SetName(hdr.Name)
|
||||
|
||||
// File entries added, regardless of size
|
||||
if _, err := p.AddEntry(entry); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if b := tr.RawBytes(); len(b) > 0 {
|
||||
if _, err := p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: b,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It is allowable, and not uncommon that there is further padding on
|
||||
// the end of an archive, apart from the expected 1024 null bytes. We
|
||||
// do this in chunks rather than in one go to avoid cases where a
|
||||
// maliciously crafted tar file tries to trick us into reading many GBs
|
||||
// into memory.
|
||||
const paddingChunkSize = 1024 * 1024
|
||||
var paddingChunk [paddingChunkSize]byte
|
||||
for {
|
||||
n, err := outputRdr.Read(paddingChunk[:])
|
||||
if n != 0 {
|
||||
if _, aerr := p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: paddingChunk[:n],
|
||||
}); aerr != nil {
|
||||
return aerr
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// newInputTarStreamCommon sets up the shared plumbing for NewInputTarStream and
|
||||
// NewInputTarStreamWithDone.
|
||||
//
|
||||
// It constructs an io.Pipe and an io.TeeReader such that:
|
||||
//
|
||||
// - The caller reads tar bytes from the returned *io.PipeReader.
|
||||
// - The background goroutine simultaneously reads the same stream from the
|
||||
// TeeReader to perform tar-split parsing and metadata packing.
|
||||
//
|
||||
// Abort and synchronization semantics:
|
||||
//
|
||||
// - Closing the returned PipeReader causes the TeeReader to fail its write to
|
||||
// the pipe, which in turn causes the background goroutine to exit promptly.
|
||||
// - If withDone is true, a done channel is returned that receives exactly one
|
||||
// error value (nil on success) once the background goroutine has fully
|
||||
// terminated. This allows callers to safely wait until the input reader `r`
|
||||
// is no longer in use.
|
||||
func newInputTarStreamCommon(
|
||||
r io.Reader,
|
||||
p storage.Packer,
|
||||
fp storage.FilePutter,
|
||||
done chan<- error,
|
||||
) (pr *io.PipeReader) {
|
||||
// What to do here... folks will want their own access to the Reader that is
|
||||
// their tar archive stream, but we'll need that same stream to use our
|
||||
// forked 'archive/tar'.
|
||||
|
|
@ -34,123 +179,59 @@ func NewInputTarStream(r io.Reader, p storage.Packer, fp storage.FilePutter) (io
|
|||
// only read what the outputRdr Read's. Since Tar archives have padding on
|
||||
// the end, we want to be the one reading the padding, even if the user's
|
||||
// `archive/tar` doesn't care.
|
||||
pR, pW := io.Pipe()
|
||||
outputRdr := io.TeeReader(r, pW)
|
||||
pr, pw := io.Pipe()
|
||||
|
||||
// we need a putter that will generate the crc64 sums of file payloads
|
||||
if fp == nil {
|
||||
fp = storage.NewDiscardFilePutter()
|
||||
}
|
||||
|
||||
go func() {
|
||||
tr := tar.NewReader(outputRdr)
|
||||
tr.RawAccounting = true
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
// even when an EOF is reached, there is often 1024 null bytes on
|
||||
// the end of an archive. Collect them too.
|
||||
if b := tr.RawBytes(); len(b) > 0 {
|
||||
_, err := p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: b,
|
||||
})
|
||||
if err != nil {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
break // not return. We need the end of the reader.
|
||||
}
|
||||
if hdr == nil {
|
||||
break // not return. We need the end of the reader.
|
||||
}
|
||||
outputRdr := io.TeeReader(r, pw)
|
||||
go runInputTarStreamGoroutine(outputRdr, pw, p, fp, done)
|
||||
|
||||
if b := tr.RawBytes(); len(b) > 0 {
|
||||
_, err := p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: b,
|
||||
})
|
||||
if err != nil {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var csum []byte
|
||||
if hdr.Size > 0 {
|
||||
var err error
|
||||
_, csum, err = fp.Put(hdr.Name, tr)
|
||||
if err != nil {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
entry := storage.Entry{
|
||||
Type: storage.FileType,
|
||||
Size: hdr.Size,
|
||||
Payload: csum,
|
||||
}
|
||||
// For proper marshalling of non-utf8 characters
|
||||
entry.SetName(hdr.Name)
|
||||
|
||||
// File entries added, regardless of size
|
||||
_, err = p.AddEntry(entry)
|
||||
if err != nil {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if b := tr.RawBytes(); len(b) > 0 {
|
||||
_, err = p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: b,
|
||||
})
|
||||
if err != nil {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It is allowable, and not uncommon that there is further padding on
|
||||
// the end of an archive, apart from the expected 1024 null bytes. We
|
||||
// do this in chunks rather than in one go to avoid cases where a
|
||||
// maliciously crafted tar file tries to trick us into reading many GBs
|
||||
// into memory.
|
||||
const paddingChunkSize = 1024 * 1024
|
||||
var paddingChunk [paddingChunkSize]byte
|
||||
for {
|
||||
var isEOF bool
|
||||
n, err := outputRdr.Read(paddingChunk[:])
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
isEOF = true
|
||||
}
|
||||
if n != 0 {
|
||||
_, err = p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: paddingChunk[:n],
|
||||
})
|
||||
if err != nil {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if isEOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
pW.Close()
|
||||
}()
|
||||
|
||||
return pR, nil
|
||||
return pr
|
||||
}
|
||||
|
||||
// NewInputTarStream wraps the Reader stream of a tar archive and provides a
|
||||
// Reader stream of the same.
|
||||
//
|
||||
// In the middle it will pack the segments and file metadata to storage.Packer
|
||||
// `p`.
|
||||
//
|
||||
// The storage.FilePutter is where payload of files in the stream are
|
||||
// stashed. If this stashing is not needed, you can provide a nil
|
||||
// storage.FilePutter. Since the checksumming is still needed, then a default
|
||||
// of NewDiscardFilePutter will be used internally
|
||||
//
|
||||
// If callers need to be able to abort early and/or wait for goroutine termination,
|
||||
// prefer NewInputTarStreamWithDone.
|
||||
//
|
||||
// Deprecated: This leaves a goroutine around if the consumer aborts without consuming
|
||||
// the whole stream, and does not allow the caller to know when r is safe to deallocate
|
||||
// or when p has written everything. Use NewInputTarStreamWithDone instead.
|
||||
func NewInputTarStream(r io.Reader, p storage.Packer, fp storage.FilePutter) (io.Reader, error) {
|
||||
pr := newInputTarStreamCommon(r, p, fp, nil)
|
||||
return pr, nil
|
||||
}
|
||||
|
||||
// NewInputTarStreamWithDone wraps the Reader stream of a tar archive and provides a
|
||||
// Reader stream of the same.
|
||||
//
|
||||
// In the middle it will pack the segments and file metadata to storage.Packer `p`.
|
||||
//
|
||||
// It also returns a done channel that will receive exactly one error value
|
||||
// (nil on success) when the internal goroutine has fully completed parsing
|
||||
// the tar stream (including the final paddingChunk draining loop) and has
|
||||
// finished writing all entries to `p`.
|
||||
//
|
||||
// The returned reader is an io.ReadCloser so callers can stop early; closing it
|
||||
// aborts the pipe so the internal goroutine can terminate promptly (rather than
|
||||
// hanging on a blocked pipe write).
|
||||
//
|
||||
// The caller is expected to consume the returned reader fully until EOF
|
||||
// (not just the tar EOF marker); closing the returned reader earlier will
|
||||
// cause the done channel to return a failure.
|
||||
func NewInputTarStreamWithDone(r io.Reader, p storage.Packer, fp storage.FilePutter) (io.ReadCloser, <-chan error, error) {
|
||||
done := make(chan error, 1)
|
||||
pr := newInputTarStreamCommon(r, p, fp, done)
|
||||
return pr, done, nil
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/vbatts/tar-split/tar/asm/iterate.go
generated
vendored
2
vendor/github.com/vbatts/tar-split/tar/asm/iterate.go
generated
vendored
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
// IterateHeaders calls handler for each tar header provided by Unpacker
|
||||
func IterateHeaders(unpacker storage.Unpacker, handler func(hdr *tar.Header) error) error {
|
||||
// We assume about NewInputTarStream:
|
||||
// We assume about NewInputTarStreamWithDone:
|
||||
// - There is a separate SegmentType entry for every tar header, but only one SegmentType entry for the full header incl. any extensions
|
||||
// - (There is a FileType entry for every tar header, we ignore it)
|
||||
// - Trailing padding of a file, if any, is included in the next SegmentType entry
|
||||
|
|
|
|||
6
vendor/go.podman.io/buildah/.packit.yaml
generated
vendored
6
vendor/go.podman.io/buildah/.packit.yaml
generated
vendored
|
|
@ -121,12 +121,16 @@ jobs:
|
|||
id: https://copr.fedorainfracloud.org/coprs/rhcontainerbot/podman-next/repo/centos-stream-$releasever/rhcontainerbot-podman-next-centos-stream-$releasever.repo
|
||||
|
||||
# Sync to Fedora
|
||||
# NOTE: Breaking changes related to Podman6 will only be shipped to Fedora
|
||||
# Rawhide (to be Fedora 45) and newer.
|
||||
# TODO: Update dist_git_branches as and when new Fedora releases are
|
||||
# available.
|
||||
- job: propose_downstream
|
||||
trigger: release
|
||||
packages: [buildah-fedora]
|
||||
update_release: false
|
||||
dist_git_branches: &fedora_targets
|
||||
- fedora-all
|
||||
- fedora-rawhide
|
||||
|
||||
# Sync to CentOS Stream
|
||||
- job: propose_downstream
|
||||
|
|
|
|||
3
vendor/go.podman.io/buildah/GOVERNANCE.md
generated
vendored
3
vendor/go.podman.io/buildah/GOVERNANCE.md
generated
vendored
|
|
@ -7,6 +7,5 @@ except sections found in this document, which override those found in Podman's G
|
|||
|
||||
# Maintainers File
|
||||
|
||||
The definitive source of truth for maintainers of this repository is the local [MAINTAINERS.md](./MAINTAINERS.md) file. The [MAINTAINERS.md](https://github.com/containers/podman/blob/main/MAINTAINERS.md) file in the main Podman repository is used for project-spanning roles, including Core Maintainer and Community Manager. Some repositories in the project will also have a local [OWNERS](./OWNERS) file, which the CI system uses to map users to roles. Any changes to the [OWNERS](./OWNERS) file must make a corresponding change to the [MAINTAINERS.md](./MAINTAINERS.md) file to ensure that the file remains up to date. Most changes to [MAINTAINERS.md](./MAINTAINERS.md) will require a change to the repository’s [OWNERS](.OWNERS) file (e.g., adding a Reviewer), but some will not (e.g., promoting a Maintainer to a Core Maintainer, which comes with no additional CI-related privileges).
|
||||
The definitive source of truth for maintainers of this repository is the local [MAINTAINERS.md](./MAINTAINERS.md) file. The [MAINTAINERS.md](https://github.com/containers/podman/blob/main/MAINTAINERS.md) file in the main Podman repository is used for project-spanning roles, including Core Maintainer and Community Manager.
|
||||
|
||||
Any Core Maintainers listed in Podman’s [MAINTAINERS.md](https://github.com/containers/podman/blob/main/MAINTAINERS.md) file should also be added to the list of “approvers” in the local [OWNERS](./OWNERS) file and as a Core Maintainer in the list of “Maintainers” in the local [MAINTAINERS.md](./MAINTAINERS.md) file.
|
||||
|
|
|
|||
2
vendor/go.podman.io/buildah/Makefile
generated
vendored
2
vendor/go.podman.io/buildah/Makefile
generated
vendored
|
|
@ -132,7 +132,7 @@ bin/grpcnoop: tests/rpc/noop/noop.go
|
|||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) -r bin tests/testreport/testreport tests/conformance/testdata/mount-targets/true internal/mkcw/embed/entrypoint_amd64 internal/mkcw/embed/entrypoint_arm64 internal/mkcw/embed/entrypoint_ppc64le internal/mkcw/embed/entrypoint_s390x internal/mkcw/embed/*.gz internal/mkcw/embed/asm/*.o
|
||||
$(RM) -r bin tests/testreport/testreport tests/conformance/testdata/mount-targets/true internal/mkcw/embed/entrypoint_arm64 internal/mkcw/embed/entrypoint_ppc64le internal/mkcw/embed/entrypoint_s390x internal/mkcw/embed/entrypoint_arm64.gz internal/mkcw/embed/entrypoint_ppc64le.gz internal/mkcw/embed/entrypoint_s390x.gz internal/mkcw/embed/asm/*.o
|
||||
$(MAKE) -C docs clean
|
||||
|
||||
.PHONY: docs
|
||||
|
|
|
|||
25
vendor/go.podman.io/buildah/OWNERS
generated
vendored
25
vendor/go.podman.io/buildah/OWNERS
generated
vendored
|
|
@ -1,25 +0,0 @@
|
|||
approvers:
|
||||
- baude
|
||||
- flouthoc
|
||||
- giuseppe
|
||||
- lsm5
|
||||
- Luap99
|
||||
- mheon
|
||||
- mtrmac
|
||||
- nalind
|
||||
- rhatdan
|
||||
- TomSweeneyRedHat
|
||||
reviewers:
|
||||
- ashley-cui
|
||||
- baude
|
||||
- flouthoc
|
||||
- giuseppe
|
||||
- Honny1
|
||||
- lsm5
|
||||
- Luap99
|
||||
- mheon
|
||||
- mtrmac
|
||||
- nalind
|
||||
- rhatdan
|
||||
- TomSweeneyRedHat
|
||||
- vrothberg
|
||||
9
vendor/go.podman.io/buildah/copier/copier.go
generated
vendored
9
vendor/go.podman.io/buildah/copier/copier.go
generated
vendored
|
|
@ -566,7 +566,7 @@ func convertToRelSubdirectory(root, directory string) (relative string, err erro
|
|||
return "", fmt.Errorf("expected root directory to be an absolute path, got %q", root)
|
||||
}
|
||||
if directory == "" || !filepath.IsAbs(directory) {
|
||||
return "", fmt.Errorf("expected directory to be an absolute path, got %q", root)
|
||||
return "", fmt.Errorf("expected directory to be an absolute path, got %q", directory)
|
||||
}
|
||||
if filepath.VolumeName(root) != filepath.VolumeName(directory) {
|
||||
return "", fmt.Errorf("%q and %q are on different volumes", root, directory)
|
||||
|
|
@ -866,7 +866,6 @@ func copierMain() {
|
|||
fmt.Fprintf(os.Stderr, "error: can't change location of chroot from %q to %q", previousRequestRoot, req.Root)
|
||||
os.Exit(1)
|
||||
}
|
||||
previousRequestRoot = req.Root
|
||||
} else {
|
||||
// Figure out where to chroot to, if we weren't told.
|
||||
if req.Root == "" {
|
||||
|
|
@ -884,6 +883,8 @@ func copierMain() {
|
|||
fmt.Fprintf(os.Stderr, "%v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
previousRequestRoot = req.Root
|
||||
}
|
||||
|
||||
req.preservedRoot = req.Root
|
||||
|
|
@ -1786,7 +1787,7 @@ func copierHandlerGetOne(srcfi os.FileInfo, symlinkTarget, name, contentPath str
|
|||
return fmt.Errorf("copying %s: %w", contentPath, err)
|
||||
}
|
||||
if n != hdr.Size {
|
||||
return fmt.Errorf("copying %s: incorrect size (expected %d bytes, read %d bytes)", contentPath, n, hdr.Size)
|
||||
return fmt.Errorf("copying %s: incorrect size (expected %d bytes, read %d bytes)", contentPath, hdr.Size, n)
|
||||
}
|
||||
tw.Flush()
|
||||
}
|
||||
|
|
@ -1828,7 +1829,7 @@ func copierHandlerPut(bulkReader io.Reader, req request, idMappings *idtools.IDM
|
|||
containerFilePair := idtools.IDPair{UID: *fileUID, GID: *fileGID}
|
||||
hostFilePair, err := idMappings.ToHost(containerFilePair)
|
||||
if err != nil {
|
||||
return errorResponse("copier: put: error mapping container filesystem owner %d:%d to host filesystem owners: %v", fileUID, fileGID, err)
|
||||
return errorResponse("copier: put: error mapping container filesystem owner %d:%d to host filesystem owners: %v", *fileUID, *fileGID, err)
|
||||
}
|
||||
fileUID, fileGID = &hostFilePair.UID, &hostFilePair.GID
|
||||
}
|
||||
|
|
|
|||
4
vendor/go.podman.io/buildah/define/types_unix.go
generated
vendored
4
vendor/go.podman.io/buildah/define/types_unix.go
generated
vendored
|
|
@ -3,14 +3,14 @@
|
|||
package define
|
||||
|
||||
import (
|
||||
"github.com/opencontainers/runc/libcontainer/devices"
|
||||
"github.com/opencontainers/cgroups/devices/config"
|
||||
)
|
||||
|
||||
// BuildahDevice is a wrapper around devices.Device
|
||||
// with additional support for renaming a device
|
||||
// using bind-mount in rootless environments.
|
||||
type BuildahDevice struct {
|
||||
devices.Device
|
||||
config.Device
|
||||
Source string
|
||||
Destination string
|
||||
}
|
||||
|
|
|
|||
102
vendor/go.podman.io/buildah/install.md
generated
vendored
102
vendor/go.podman.io/buildah/install.md
generated
vendored
|
|
@ -231,11 +231,11 @@ This project is using [go modules](https://github.com/golang/go/wiki/Modules) fo
|
|||
The following configuration files are required in order for Buildah to run appropriately. The
|
||||
majority of these files are commonly contained in the `containers-common` package.
|
||||
|
||||
### [registries.conf](https://github.com/containers/buildah/blob/main/docs/samples/registries.conf)
|
||||
### [registries.conf](https://github.com/containers/container-libs/blob/main/image/registries.conf)
|
||||
|
||||
#### Man Page: [registries.conf.5](https://github.com/containers/image/blob/main/docs/containers-registries.conf.5.md)
|
||||
#### Man Page: [containers-registries.conf.5](https://github.com/containers/container-libs/blob/main/image/docs/containers-registries.conf.5.md)
|
||||
|
||||
`/etc/containers/registries.conf`
|
||||
`/usr/share/containers/registries.conf`, `/etc/containers/registries.conf`, `$HOME/.config/containers/registries.conf`
|
||||
|
||||
registries.conf is the configuration file which specifies which container registries should be consulted when completing image names which do not include a registry or domain portion.
|
||||
|
||||
|
|
@ -243,31 +243,79 @@ registries.conf is the configuration file which specifies which container regist
|
|||
|
||||
```
|
||||
cat /etc/containers/registries.conf
|
||||
# This is a system-wide configuration file used to
|
||||
# keep track of registries for various container backends.
|
||||
# It adheres to TOML format and does not support recursive
|
||||
# lists of registries.
|
||||
|
||||
# The default location for this configuration file is /etc/containers/registries.conf.
|
||||
|
||||
# The only valid categories are: 'registries.search', 'registries.insecure',
|
||||
# and 'registries.block'.
|
||||
|
||||
[registries.search]
|
||||
registries = ['docker.io', 'registry.fedoraproject.org', 'quay.io', 'registry.access.redhat.com']
|
||||
|
||||
# If you need to access insecure registries, add the registry's fully-qualified name.
|
||||
# An insecure registry is one that does not have a valid SSL certificate or only does HTTP.
|
||||
[registries.insecure]
|
||||
registries = []
|
||||
|
||||
|
||||
# If you need to block pull access from a registry, uncomment the section below
|
||||
# and add the registries fully-qualified name.
|
||||
# For more information on this configuration file, see containers-registries.conf(5).
|
||||
#
|
||||
# Docker only
|
||||
[registries.block]
|
||||
registries = []
|
||||
# NOTE: RISK OF USING UNQUALIFIED IMAGE NAMES
|
||||
# We recommend always using fully qualified image names including the registry
|
||||
# server (full dns name), namespace, image name, and tag
|
||||
# (e.g., registry.redhat.io/ubi8/ubi:latest). Pulling by digest (i.e.,
|
||||
# quay.io/repository/name@digest) further eliminates the ambiguity of tags.
|
||||
# When using short names, there is always an inherent risk that the image being
|
||||
# pulled could be spoofed. For example, a user wants to pull an image named
|
||||
# `foobar` from a registry and expects it to come from myregistry.com. If
|
||||
# myregistry.com is not first in the search list, an attacker could place a
|
||||
# different `foobar` image at a registry earlier in the search list. The user
|
||||
# would accidentally pull and run the attacker's image and code rather than the
|
||||
# intended content. We recommend only adding registries which are completely
|
||||
# trusted (i.e., registries which don't allow unknown or anonymous users to
|
||||
# create accounts with arbitrary names). This will prevent an image from being
|
||||
# spoofed, squatted or otherwise made insecure. If it is necessary to use one
|
||||
# of these registries, it should be added at the end of the list.
|
||||
#
|
||||
# # An array of host[:port] registries to try when pulling an unqualified image, in order.
|
||||
unqualified-search-registries = ["registry.fedoraproject.org", "registry.access.redhat.com", "docker.io", "quay.io"]
|
||||
#
|
||||
# [[registry]]
|
||||
# # The "prefix" field is used to choose the relevant [[registry]] TOML table;
|
||||
# # (only) the TOML table with the longest match for the input image name
|
||||
# # (taking into account namespace/repo/tag/digest separators) is used.
|
||||
# #
|
||||
# # If the prefix field is missing, it defaults to be the same as the "location" field.
|
||||
# prefix = "example.com/foo"
|
||||
#
|
||||
# # If true, unencrypted HTTP as well as TLS connections with untrusted
|
||||
# # certificates are allowed.
|
||||
# insecure = false
|
||||
#
|
||||
# # If true, pulling images with matching names is forbidden.
|
||||
# blocked = false
|
||||
#
|
||||
# # The physical location of the "prefix"-rooted namespace.
|
||||
# #
|
||||
# # By default, this equal to "prefix" (in which case "prefix" can be omitted
|
||||
# # and the [[registry]] TOML table can only specify "location").
|
||||
# #
|
||||
# # Example: Given
|
||||
# # prefix = "example.com/foo"
|
||||
# # location = "internal-registry-for-example.net/bar"
|
||||
# # requests for the image example.com/foo/myimage:latest will actually work with the
|
||||
# # internal-registry-for-example.net/bar/myimage:latest image.
|
||||
# location = "internal-registry-for-example.com/bar"
|
||||
#
|
||||
# # (Possibly-partial) mirrors for the "prefix"-rooted namespace.
|
||||
# #
|
||||
# # The mirrors are attempted in the specified order; the first one that can be
|
||||
# # contacted and contains the image will be used (and if none of the mirrors contains the image,
|
||||
# # the primary location specified by the "registry.location" field, or using the unmodified
|
||||
# # user-specified reference, is tried last).
|
||||
# #
|
||||
# # Each TOML table in the "mirror" array can contain the following fields, with the same semantics
|
||||
# # as if specified in the [[registry]] TOML table directly:
|
||||
# # - location
|
||||
# # - insecure
|
||||
# [[registry.mirror]]
|
||||
# location = "example-mirror-0.local/mirror-for-foo"
|
||||
# [[registry.mirror]]
|
||||
# location = "example-mirror-1.local/mirrors/foo"
|
||||
# insecure = true
|
||||
# # Given the above, a pull of example.com/foo/image:latest will try:
|
||||
# # 1. example-mirror-0.local/mirror-for-foo/image:latest
|
||||
# # 2. example-mirror-1.local/mirrors/foo/image:latest
|
||||
# # 3. internal-registry-for-example.net/bar/image:latest
|
||||
# # in order, and use the first one that exists.
|
||||
|
||||
# Enforcing mode for short names is default for Fedora 34 and newer
|
||||
short-name-mode="enforcing"
|
||||
```
|
||||
|
||||
### [mounts.conf](https://src.fedoraproject.org/rpms/skopeo/blob/main/f/mounts.conf)
|
||||
|
|
|
|||
2
vendor/go.podman.io/buildah/pkg/parse/parse_unix.go
generated
vendored
2
vendor/go.podman.io/buildah/pkg/parse/parse_unix.go
generated
vendored
|
|
@ -7,8 +7,8 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/moby/sys/devices"
|
||||
"github.com/opencontainers/cgroups/devices/config"
|
||||
"github.com/opencontainers/runc/libcontainer/devices"
|
||||
"go.podman.io/buildah/define"
|
||||
)
|
||||
|
||||
|
|
|
|||
3
vendor/go.podman.io/buildah/run.go
generated
vendored
3
vendor/go.podman.io/buildah/run.go
generated
vendored
|
|
@ -189,6 +189,9 @@ type RunOptions struct {
|
|||
// made to contents of those changes when the container is subsequently
|
||||
// committed.
|
||||
CompatBuiltinVolumes types.OptionalBool
|
||||
// ValidExitCodes is a list of exit codes which should be considered
|
||||
// successful. If empty, only exit code 0 is considered success.
|
||||
ValidExitCodes []int32
|
||||
}
|
||||
|
||||
// RunMountArtifacts are the artifacts created when using a run mount.
|
||||
|
|
|
|||
35
vendor/go.podman.io/buildah/run_common.go
generated
vendored
35
vendor/go.podman.io/buildah/run_common.go
generated
vendored
|
|
@ -387,13 +387,6 @@ func DefaultNamespaceOptions() (define.NamespaceOptions, error) {
|
|||
func checkAndOverrideIsolationOptions(isolation define.Isolation, options *RunOptions) error {
|
||||
switch isolation {
|
||||
case IsolationOCIRootless:
|
||||
// only change the netns if the caller did not set it
|
||||
if ns := options.NamespaceOptions.Find(string(specs.NetworkNamespace)); ns == nil {
|
||||
if _, err := exec.LookPath("slirp4netns"); err != nil {
|
||||
// if slirp4netns is not installed we have to use the hosts net namespace
|
||||
options.NamespaceOptions.AddOrReplace(define.NamespaceOption{Name: string(specs.NetworkNamespace), Host: true})
|
||||
}
|
||||
}
|
||||
fallthrough
|
||||
case IsolationOCI:
|
||||
pidns := options.NamespaceOptions.Find(string(specs.PIDNamespace))
|
||||
|
|
@ -2234,3 +2227,31 @@ func (b *Builder) createMountTargets(spec *specs.Spec) ([]copier.ConditionalRemo
|
|||
// to clear them out itself now instead of waiting until commit-time
|
||||
return remove, nil
|
||||
}
|
||||
|
||||
func checkExitCodeError(err error, validExitCodes []int32) error {
|
||||
if len(validExitCodes) == 0 {
|
||||
return err
|
||||
}
|
||||
exitCode, ok := exitCodeFromError(err)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
if slices.Contains(validExitCodes, exitCode) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("exit status %d is not in the valid exit codes list", exitCode)
|
||||
}
|
||||
|
||||
func exitCodeFromError(err error) (int32, bool) {
|
||||
if err == nil {
|
||||
return 0, true
|
||||
}
|
||||
var ee *exec.ExitError
|
||||
if errors.As(err, &ee) {
|
||||
return int32(ee.ExitCode()), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
|
|
|||
2
vendor/go.podman.io/buildah/run_freebsd.go
generated
vendored
2
vendor/go.podman.io/buildah/run_freebsd.go
generated
vendored
|
|
@ -357,7 +357,7 @@ func (b *Builder) Run(command []string, options RunOptions) error {
|
|||
default:
|
||||
err = errors.New("don't know how to run this command")
|
||||
}
|
||||
return err
|
||||
return checkExitCodeError(err, options.ValidExitCodes)
|
||||
}
|
||||
|
||||
func addCommonOptsToSpec(commonOpts *define.CommonBuildOptions, g *generate.Generator) error {
|
||||
|
|
|
|||
48
vendor/go.podman.io/buildah/run_linux.go
generated
vendored
48
vendor/go.podman.io/buildah/run_linux.go
generated
vendored
|
|
@ -12,7 +12,6 @@ import (
|
|||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
|
|
@ -33,7 +32,6 @@ import (
|
|||
"go.podman.io/common/libnetwork/etchosts"
|
||||
"go.podman.io/common/libnetwork/pasta"
|
||||
"go.podman.io/common/libnetwork/resolvconf"
|
||||
"go.podman.io/common/libnetwork/slirp4netns"
|
||||
nettypes "go.podman.io/common/libnetwork/types"
|
||||
netUtil "go.podman.io/common/libnetwork/util"
|
||||
"go.podman.io/common/pkg/capabilities"
|
||||
|
|
@ -596,7 +594,7 @@ rootless=%d
|
|||
default:
|
||||
err = errors.New("don't know how to run this command")
|
||||
}
|
||||
return err
|
||||
return checkExitCodeError(err, options.ValidExitCodes)
|
||||
}
|
||||
|
||||
func (b *Builder) setupOCIHooks(config *specs.Spec, hasVolumes bool) (map[string][]specs.Hook, error) {
|
||||
|
|
@ -689,46 +687,6 @@ func addCommonOptsToSpec(commonOpts *define.CommonBuildOptions, g *generate.Gene
|
|||
return nil
|
||||
}
|
||||
|
||||
func setupSlirp4netnsNetwork(config *config.Config, netns, cid string, options, hostnames []string) (func(), *netResult, error) {
|
||||
// we need the TmpDir for the slirp4netns code
|
||||
if err := os.MkdirAll(config.Engine.TmpDir, 0o751); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create tempdir: %w", err)
|
||||
}
|
||||
res, err := slirp4netns.Setup(&slirp4netns.SetupOptions{
|
||||
Config: config,
|
||||
ContainerID: cid,
|
||||
Netns: netns,
|
||||
ExtraOptions: options,
|
||||
Pdeathsig: syscall.SIGKILL,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ip, err := slirp4netns.GetIP(res.Subnet)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("get slirp4netns ip: %w", err)
|
||||
}
|
||||
|
||||
dns, err := slirp4netns.GetDNS(res.Subnet)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("get slirp4netns dns ip: %w", err)
|
||||
}
|
||||
|
||||
result := &netResult{
|
||||
entries: etchosts.HostEntries{{IP: ip.String(), Names: hostnames}},
|
||||
dnsServers: []string{dns.String()},
|
||||
ipv6: res.IPv6,
|
||||
keepHostResolvers: true,
|
||||
}
|
||||
|
||||
return func() {
|
||||
syscall.Kill(res.Pid, syscall.SIGKILL) //nolint:errcheck
|
||||
var status syscall.WaitStatus
|
||||
syscall.Wait4(res.Pid, &status, 0, nil) //nolint:errcheck
|
||||
}, result, nil
|
||||
}
|
||||
|
||||
func setupPasta(config *config.Config, netns string, options, hostnames []string) (func(), *netResult, error) {
|
||||
res, err := pasta.Setup(&pasta.SetupOptions{
|
||||
Config: config,
|
||||
|
|
@ -776,8 +734,6 @@ func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, optio
|
|||
}
|
||||
if isolation == IsolationOCIRootless && name == "" {
|
||||
switch defConfig.Network.DefaultRootlessNetworkCmd {
|
||||
case slirp4netns.BinaryName, "":
|
||||
name = slirp4netns.BinaryName
|
||||
case pasta.BinaryName:
|
||||
name = pasta.BinaryName
|
||||
default:
|
||||
|
|
@ -787,8 +743,6 @@ func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, optio
|
|||
}
|
||||
|
||||
switch {
|
||||
case name == slirp4netns.BinaryName:
|
||||
return setupSlirp4netnsNetwork(defConfig, netns, containerName, netOpts, hostnames)
|
||||
case name == pasta.BinaryName:
|
||||
return setupPasta(defConfig, netns, netOpts, hostnames)
|
||||
|
||||
|
|
|
|||
4
vendor/go.podman.io/buildah/troubleshooting.md
generated
vendored
4
vendor/go.podman.io/buildah/troubleshooting.md
generated
vendored
|
|
@ -26,8 +26,8 @@ error building: error creating build container: no such image "alpine" in regist
|
|||
|
||||
#### Solution
|
||||
|
||||
* Verify that the `/etc/containers/registries.conf` file exists. If not, verify that the containers-common package is installed.
|
||||
* Verify that the entries in the `[registries.search]` section of the /etc/containers/registries file are valid and reachable.
|
||||
* Verify that a `registries.conf` file exists, see [containers-registries.conf(5)](https://github.com/containers/container-libs/blob/main/image/docs/containers-registries.conf.5.md). If not, verify that the containers-common package is installed.
|
||||
* Verify that the `unqualified-search-registries` option contains valid registries and that they are reachable.
|
||||
* Verify that the image you requested is either fully qualified, or that it exists on one of your search registries.
|
||||
* Verify that the image is public or that you have logged in to at least one search registry which contains the private image.
|
||||
* Verify that the other required [Configuration Files](https://github.com/containers/buildah/blob/main/install.md#configuration-files) are installed.
|
||||
|
|
|
|||
54
vendor/go.podman.io/common/pkg/libartifact/events.go
generated
vendored
Normal file
54
vendor/go.podman.io/common/pkg/libartifact/events.go
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
//go:build !remote
|
||||
|
||||
package libartifact
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// EventType indicates the type of an event.
|
||||
type EventType int
|
||||
|
||||
const (
|
||||
// EventTypeUnknown is an uninitialized EventType.
|
||||
EventTypeUnknown EventType = iota
|
||||
// EventTypeArtifactPull represents an artifact pull.
|
||||
EventTypeArtifactPull
|
||||
// EventTypeArtifactPush represents an artifact push.
|
||||
EventTypeArtifactPush
|
||||
// EventTypeArtifactRemove represents an artifact removal.
|
||||
EventTypeArtifactRemove
|
||||
// EventTypeArtifactAdd represents an artifact being added.
|
||||
EventTypeArtifactAdd
|
||||
)
|
||||
|
||||
// Event represents an event such as an artifact pull or push.
|
||||
type Event struct {
|
||||
// ID of the object (e.g., artifact digest).
|
||||
ID string
|
||||
// Name of the object (e.g., artifact name "quay.io/foobar/artifact:special")
|
||||
Name string
|
||||
// Time of the event.
|
||||
Time time.Time
|
||||
// Type of the event.
|
||||
Type EventType
|
||||
// Error in case of failure.
|
||||
Error error
|
||||
}
|
||||
|
||||
// writeEvent writes the specified event to the store's event channel. The
|
||||
// event is discarded if no event channel has been registered (yet).
|
||||
func (as *ArtifactStore) writeEvent(event *Event) {
|
||||
select {
|
||||
case as.eventChannel <- event:
|
||||
// Done
|
||||
case <-time.After(2 * time.Second):
|
||||
// The store's event channel has a buffer of size 100 which
|
||||
// should be enough even under high load. However, we
|
||||
// shouldn't block too long in case the buffer runs full (could
|
||||
// be an honest user error or bug).
|
||||
logrus.Warnf("Discarding libartifact event which was not read within 2 seconds: %v", event)
|
||||
}
|
||||
}
|
||||
122
vendor/go.podman.io/common/pkg/libartifact/store.go
generated
vendored
122
vendor/go.podman.io/common/pkg/libartifact/store.go
generated
vendored
|
|
@ -41,6 +41,7 @@ type ArtifactStore struct {
|
|||
SystemContext *types.SystemContext
|
||||
storePath string
|
||||
lock *lockfile.LockFile
|
||||
eventChannel chan *Event
|
||||
}
|
||||
|
||||
// NewArtifactStore is a constructor for artifact stores. Most artifact dealings depend on this. Store path is
|
||||
|
|
@ -81,10 +82,22 @@ func NewArtifactStore(storePath string, sc *types.SystemContext) (*ArtifactStore
|
|||
return artifactStore, nil
|
||||
}
|
||||
|
||||
// EventChannel creates a buffered channel for events that the ArtifactStore will use
|
||||
// to write events to. Callers are expected to read from the channel in a
|
||||
// timely manner.
|
||||
// Can be called once for a given ArtifactStore.
|
||||
func (as *ArtifactStore) EventChannel() chan *Event {
|
||||
if as.eventChannel != nil {
|
||||
return as.eventChannel
|
||||
}
|
||||
as.eventChannel = make(chan *Event, 100)
|
||||
return as.eventChannel
|
||||
}
|
||||
|
||||
// lookupArtifactLocked looks up an artifact by fully qualified name,
|
||||
// or name@digest, full ID, or partial ID.
|
||||
// note: lookupArtifactLocked must be called while under a store lock
|
||||
func (as ArtifactStore) lookupArtifactLocked(ctx context.Context, asr ArtifactStoreReference) (*Artifact, error) {
|
||||
func (as *ArtifactStore) lookupArtifactLocked(ctx context.Context, asr ArtifactStoreReference) (*Artifact, error) {
|
||||
artifacts, err := as.getArtifacts(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -146,7 +159,7 @@ func (as ArtifactStore) lookupArtifactLocked(ctx context.Context, asr ArtifactSt
|
|||
}
|
||||
|
||||
// Remove an artifact from the local artifact store.
|
||||
func (as ArtifactStore) Remove(ctx context.Context, asr ArtifactStoreReference) (*digest.Digest, error) {
|
||||
func (as *ArtifactStore) Remove(ctx context.Context, asr ArtifactStoreReference) (_ *digest.Digest, removeErr error) {
|
||||
as.lock.Lock()
|
||||
defer as.lock.Unlock()
|
||||
|
||||
|
|
@ -154,15 +167,23 @@ func (as ArtifactStore) Remove(ctx context.Context, asr ArtifactStoreReference)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ir, err := layout.NewReference(as.storePath, arty.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &arty.Digest, ir.DeleteImage(ctx, as.SystemContext)
|
||||
if err := ir.DeleteImage(ctx, as.SystemContext); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if as.eventChannel != nil {
|
||||
as.writeEvent(&Event{ID: arty.Digest.String(), Name: arty.Name, Time: time.Now(), Type: EventTypeArtifactRemove})
|
||||
}
|
||||
return &arty.Digest, nil
|
||||
}
|
||||
|
||||
// Inspect an artifact in a local store.
|
||||
func (as ArtifactStore) Inspect(ctx context.Context, asr ArtifactStoreReference) (*Artifact, error) {
|
||||
func (as *ArtifactStore) Inspect(ctx context.Context, asr ArtifactStoreReference) (*Artifact, error) {
|
||||
as.lock.RLock()
|
||||
defer as.lock.Unlock()
|
||||
|
||||
|
|
@ -170,69 +191,78 @@ func (as ArtifactStore) Inspect(ctx context.Context, asr ArtifactStoreReference)
|
|||
}
|
||||
|
||||
// List artifacts in the local store.
|
||||
func (as ArtifactStore) List(ctx context.Context) (ArtifactList, error) {
|
||||
func (as *ArtifactStore) List(ctx context.Context) (ArtifactList, error) {
|
||||
as.lock.RLock()
|
||||
defer as.lock.Unlock()
|
||||
|
||||
return as.getArtifacts(ctx, nil)
|
||||
}
|
||||
|
||||
// Pull an artifact from an image registry to a local store.
|
||||
func (as ArtifactStore) Pull(ctx context.Context, ref ArtifactReference, opts libimage.CopyOptions) (digest.Digest, error) {
|
||||
srcRef, err := docker.NewReference(ref.ref)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Execute fn while holding the store lock and providing a reference to the local layout.
|
||||
func (as *ArtifactStore) withLockedLayout(localName string, fn func(localRef types.ImageReference) (digest.Digest, error)) (digest.Digest, error) {
|
||||
as.lock.Lock()
|
||||
defer as.lock.Unlock()
|
||||
|
||||
destRef, err := layout.NewReference(as.storePath, ref.String())
|
||||
ref, err := layout.NewReference(as.storePath, localName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fn(ref)
|
||||
}
|
||||
|
||||
// Copy artifact from srcRef to destRef and return the digest of the copied artifact.
|
||||
func (as *ArtifactStore) copyArtifact(ctx context.Context, srcRef types.ImageReference, destRef types.ImageReference, opts libimage.CopyOptions) (_ digest.Digest, err error) {
|
||||
copyer, err := libimage.NewCopier(&opts, as.SystemContext)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func() {
|
||||
closeErr := copyer.Close()
|
||||
if err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
}()
|
||||
artifactBytes, err := copyer.Copy(ctx, srcRef, destRef)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = copyer.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return digest.FromBytes(artifactBytes), nil
|
||||
}
|
||||
|
||||
// Pull an artifact from an image registry to a local store.
|
||||
func (as *ArtifactStore) Pull(ctx context.Context, ref ArtifactReference, opts libimage.CopyOptions) (_ digest.Digest, pullErr error) {
|
||||
srcRef, err := docker.NewReference(ref.ref)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
artifactDigest, err := as.withLockedLayout(ref.String(), func(localRef types.ImageReference) (digest.Digest, error) {
|
||||
return as.copyArtifact(ctx, srcRef, localRef, opts)
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if as.eventChannel != nil {
|
||||
as.writeEvent(&Event{ID: artifactDigest.String(), Name: ref.String(), Time: time.Now(), Type: EventTypeArtifactPull})
|
||||
}
|
||||
return artifactDigest, nil
|
||||
}
|
||||
|
||||
// Push an artifact to an image registry.
|
||||
func (as ArtifactStore) Push(ctx context.Context, src, dest ArtifactReference, opts libimage.CopyOptions) (digest.Digest, error) {
|
||||
func (as *ArtifactStore) Push(ctx context.Context, src, dest ArtifactReference, opts libimage.CopyOptions) (_ digest.Digest, pushErr error) {
|
||||
destRef, err := docker.NewReference(dest.ref)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
as.lock.Lock()
|
||||
defer as.lock.Unlock()
|
||||
|
||||
srcRef, err := layout.NewReference(as.storePath, src.String())
|
||||
artifactDigest, err := as.withLockedLayout(src.String(), func(localRef types.ImageReference) (digest.Digest, error) {
|
||||
return as.copyArtifact(ctx, localRef, destRef, opts)
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
copyer, err := libimage.NewCopier(&opts, as.SystemContext)
|
||||
if err != nil {
|
||||
return "", err
|
||||
if as.eventChannel != nil {
|
||||
as.writeEvent(&Event{ID: artifactDigest.String(), Name: dest.String(), Time: time.Now(), Type: EventTypeArtifactPush})
|
||||
}
|
||||
artifactBytes, err := copyer.Copy(ctx, srcRef, destRef)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = copyer.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
artifactDigest := digest.FromBytes(artifactBytes)
|
||||
return artifactDigest, nil
|
||||
}
|
||||
|
||||
|
|
@ -256,7 +286,7 @@ func createNewArtifactManifest(options *libartTypes.AddOptions) specV1.Manifest
|
|||
}
|
||||
|
||||
// cleanupAfterAppend removes previous image when doing an append.
|
||||
func cleanupAfterAppend(ctx context.Context, oldDigest digest.Digest, as ArtifactStore) error {
|
||||
func cleanupAfterAppend(ctx context.Context, oldDigest digest.Digest, as *ArtifactStore) error {
|
||||
lrs, err := layout.List(as.storePath)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -279,7 +309,7 @@ func cleanupAfterAppend(ctx context.Context, oldDigest digest.Digest, as Artifac
|
|||
|
||||
// Add takes one or more artifact blobs and add them to the local artifact store. The empty
|
||||
// string input is for possible custom artifact types.
|
||||
func (as ArtifactStore) Add(ctx context.Context, dest ArtifactReference, artifactBlobs []libartTypes.ArtifactBlob, options *libartTypes.AddOptions) (*digest.Digest, error) {
|
||||
func (as *ArtifactStore) Add(ctx context.Context, dest ArtifactReference, artifactBlobs []libartTypes.ArtifactBlob, options *libartTypes.AddOptions) (_ *digest.Digest, addErr error) {
|
||||
if options.Append && len(options.ArtifactMIMEType) > 0 {
|
||||
return nil, errors.New("append option is not compatible with type option")
|
||||
}
|
||||
|
|
@ -447,10 +477,14 @@ func (as ArtifactStore) Add(ctx context.Context, dest ArtifactReference, artifac
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if as.eventChannel != nil {
|
||||
as.writeEvent(&Event{ID: artifactManifestDigest.String(), Name: dest.String(), Time: time.Now(), Type: EventTypeArtifactAdd})
|
||||
}
|
||||
return &artifactManifestDigest, nil
|
||||
}
|
||||
|
||||
func getArtifactAndImageSource(ctx context.Context, as ArtifactStore, asr ArtifactStoreReference, options *libartTypes.FilterBlobOptions) (*Artifact, types.ImageSource, error) {
|
||||
func getArtifactAndImageSource(ctx context.Context, as *ArtifactStore, asr ArtifactStoreReference, options *libartTypes.FilterBlobOptions) (*Artifact, types.ImageSource, error) {
|
||||
if len(options.Digest) > 0 && len(options.Title) > 0 {
|
||||
return nil, nil, errors.New("cannot specify both digest and title")
|
||||
}
|
||||
|
|
@ -471,7 +505,7 @@ func getArtifactAndImageSource(ctx context.Context, as ArtifactStore, asr Artifa
|
|||
}
|
||||
|
||||
// BlobMountPaths allows the caller to access the file names from the store and how they should be mounted.
|
||||
func (as ArtifactStore) BlobMountPaths(ctx context.Context, asr ArtifactStoreReference, options *libartTypes.BlobMountPathOptions) ([]libartTypes.BlobMountPath, error) {
|
||||
func (as *ArtifactStore) BlobMountPaths(ctx context.Context, asr ArtifactStoreReference, options *libartTypes.BlobMountPathOptions) ([]libartTypes.BlobMountPath, error) {
|
||||
// FIX ME
|
||||
// LOCKING BUG: getArtifactAndImageSource assumes a locked ArtifactStore
|
||||
arty, imgSrc, err := getArtifactAndImageSource(ctx, as, asr, &options.FilterBlobOptions)
|
||||
|
|
@ -530,7 +564,7 @@ func (as ArtifactStore) BlobMountPaths(ctx context.Context, asr ArtifactStoreRef
|
|||
}
|
||||
|
||||
// Extract an artifact to local file or directory.
|
||||
func (as ArtifactStore) Extract(ctx context.Context, nameOrDigest ArtifactStoreReference, target string, options *libartTypes.ExtractOptions) error {
|
||||
func (as *ArtifactStore) Extract(ctx context.Context, nameOrDigest ArtifactStoreReference, target string, options *libartTypes.ExtractOptions) error {
|
||||
// FIX ME
|
||||
// LOCKING BUG: getArtifactAndImageSource assumes a locked ArtifactStore
|
||||
arty, imgSrc, err := getArtifactAndImageSource(ctx, as, nameOrDigest, &options.FilterBlobOptions)
|
||||
|
|
@ -599,7 +633,7 @@ func (as ArtifactStore) Extract(ctx context.Context, nameOrDigest ArtifactStoreR
|
|||
}
|
||||
|
||||
// Extract an artifact to tar stream.
|
||||
func (as ArtifactStore) ExtractTarStream(ctx context.Context, w io.Writer, asr ArtifactStoreReference, options *libartTypes.ExtractOptions) error {
|
||||
func (as *ArtifactStore) ExtractTarStream(ctx context.Context, w io.Writer, asr ArtifactStoreReference, options *libartTypes.ExtractOptions) error {
|
||||
if options == nil {
|
||||
options = &libartTypes.ExtractOptions{}
|
||||
}
|
||||
|
|
@ -798,7 +832,7 @@ func copyTrustedImageBlobToTarStream(ctx context.Context, imgSrc types.ImageSour
|
|||
return nil
|
||||
}
|
||||
|
||||
func (as ArtifactStore) createEmptyManifest() error {
|
||||
func (as *ArtifactStore) createEmptyManifest() error {
|
||||
as.lock.Lock()
|
||||
defer as.lock.Unlock()
|
||||
index := specV1.Index{
|
||||
|
|
@ -813,13 +847,13 @@ func (as ArtifactStore) createEmptyManifest() error {
|
|||
return os.WriteFile(as.indexPath(), rawData, 0o644)
|
||||
}
|
||||
|
||||
func (as ArtifactStore) indexPath() string {
|
||||
func (as *ArtifactStore) indexPath() string {
|
||||
return filepath.Join(as.storePath, specV1.ImageIndexFile)
|
||||
}
|
||||
|
||||
// getArtifacts returns an ArtifactList based on the artifact's store. The return error and
|
||||
// unused opts is meant for future growth like filters, etc so the API does not change.
|
||||
func (as ArtifactStore) getArtifacts(ctx context.Context, _ *libartTypes.GetArtifactOptions) (ArtifactList, error) {
|
||||
func (as *ArtifactStore) getArtifacts(ctx context.Context, _ *libartTypes.GetArtifactOptions) (ArtifactList, error) {
|
||||
var al ArtifactList
|
||||
|
||||
lrs, err := layout.List(as.storePath)
|
||||
|
|
|
|||
13
vendor/go.podman.io/storage/layers.go
generated
vendored
13
vendor/go.podman.io/storage/layers.go
generated
vendored
|
|
@ -2671,7 +2671,7 @@ func applyDiff(layerOptions *LayerOptions, diff io.Reader, tarSplitFile *os.File
|
|||
gidLog := make(map[uint32]struct{})
|
||||
var uncompressedCounter *ioutils.WriteCounter
|
||||
|
||||
size, err := func() (int64, error) { // A scope for defer
|
||||
size, err := func() (retSize int64, retErr error) { // A scope for defer
|
||||
compressor, err := pgzip.NewWriterLevel(tarSplitWriter, pgzip.BestSpeed)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
|
|
@ -2701,21 +2701,26 @@ func applyDiff(layerOptions *LayerOptions, diff io.Reader, tarSplitFile *os.File
|
|||
if uncompressedDigester != nil {
|
||||
uncompressedWriter = io.MultiWriter(uncompressedWriter, uncompressedDigester.Hash())
|
||||
}
|
||||
payload, err := asm.NewInputTarStream(io.TeeReader(uncompressed, uncompressedWriter), metadata, storage.NewDiscardFilePutter())
|
||||
payload, done, err := asm.NewInputTarStreamWithDone(io.TeeReader(uncompressed, uncompressedWriter), metadata, storage.NewDiscardFilePutter())
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
defer func() {
|
||||
payload.Close()
|
||||
if doneErr := <-done; doneErr != nil && retErr == nil {
|
||||
retErr = doneErr
|
||||
}
|
||||
}()
|
||||
|
||||
size, err := applyDriverFunc(payload)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
// Fully consume the payload; it may contain trailing zero padding, and we need all of that
|
||||
// recorded in tar-split (which happens when the data passes through NewInputTarStream).
|
||||
// recorded in tar-split (which happens when the data passes through NewInputTarStreamWithDone).
|
||||
if _, err := io.Copy(io.Discard, payload); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}()
|
||||
if err != nil {
|
||||
|
|
|
|||
320
vendor/go.podman.io/storage/pkg/chunked/compressor/compressor.go
generated
vendored
320
vendor/go.podman.io/storage/pkg/chunked/compressor/compressor.go
generated
vendored
|
|
@ -240,174 +240,186 @@ func writeZstdChunkedStream(destFile io.Writer, outMetadata map[string]string, r
|
|||
}
|
||||
}()
|
||||
|
||||
its, err := asm.NewInputTarStream(reader, tarSplitData.packer, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tr := tar.NewReader(its)
|
||||
tr.RawAccounting = true
|
||||
|
||||
buf := make([]byte, 4096)
|
||||
|
||||
zstdWriter, err := createZstdWriter(dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if zstdWriter != nil {
|
||||
zstdWriter.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
restartCompression := func() (int64, error) {
|
||||
var offset int64
|
||||
if zstdWriter != nil {
|
||||
if err := zstdWriter.Close(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
offset = dest.Count
|
||||
zstdWriter.Reset(dest)
|
||||
}
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
var metadata []minimal.FileMetadata
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
// Scope the NewInputTarStreamWithDone defer so we wait for done before
|
||||
// returning to the outer function, which then closes tarSplitData.zstd.
|
||||
metadata, err := func() (retMetadata []minimal.FileMetadata, retErr error) {
|
||||
its, done, err := asm.NewInputTarStreamWithDone(reader, tarSplitData.packer, nil)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
its.Close()
|
||||
if doneErr := <-done; doneErr != nil && retErr == nil {
|
||||
retErr = doneErr
|
||||
}
|
||||
return err
|
||||
}()
|
||||
|
||||
tr := tar.NewReader(its)
|
||||
tr.RawAccounting = true
|
||||
|
||||
buf := make([]byte, 4096)
|
||||
|
||||
zstdWriter, err := createZstdWriter(dest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if zstdWriter != nil {
|
||||
zstdWriter.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
restartCompression := func() (int64, error) {
|
||||
var offset int64
|
||||
if zstdWriter != nil {
|
||||
if err := zstdWriter.Close(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
offset = dest.Count
|
||||
zstdWriter.Reset(dest)
|
||||
}
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
var metadata []minimal.FileMetadata
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawBytes := tr.RawBytes()
|
||||
if _, err := zstdWriter.Write(rawBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payloadDigester := digest.Canonical.Digester()
|
||||
chunkDigester := digest.Canonical.Digester()
|
||||
|
||||
// Now handle the payload, if any
|
||||
startOffset := int64(0)
|
||||
lastOffset := int64(0)
|
||||
lastChunkOffset := int64(0)
|
||||
|
||||
checksum := ""
|
||||
|
||||
chunks := []chunk{}
|
||||
|
||||
hf := &holesFinder{
|
||||
threshold: holesThreshold,
|
||||
reader: bufio.NewReader(tr),
|
||||
}
|
||||
|
||||
rcReader := &rollingChecksumReader{
|
||||
reader: hf,
|
||||
rollsum: NewRollSum(),
|
||||
}
|
||||
|
||||
payloadDest := io.MultiWriter(payloadDigester.Hash(), chunkDigester.Hash(), zstdWriter)
|
||||
for {
|
||||
mustSplit, read, errRead := rcReader.Read(buf)
|
||||
if errRead != nil && errRead != io.EOF {
|
||||
return nil, errRead
|
||||
}
|
||||
// restart the compression only if there is a payload.
|
||||
if read > 0 {
|
||||
if startOffset == 0 {
|
||||
startOffset, err = restartCompression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lastOffset = startOffset
|
||||
}
|
||||
|
||||
if _, err := payloadDest.Write(buf[:read]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if (mustSplit || errRead == io.EOF) && startOffset > 0 {
|
||||
off, err := restartCompression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chunkSize := rcReader.WrittenOut - lastChunkOffset
|
||||
if chunkSize > 0 {
|
||||
chunkType := minimal.ChunkTypeData
|
||||
if rcReader.IsLastChunkZeros {
|
||||
chunkType = minimal.ChunkTypeZeros
|
||||
}
|
||||
|
||||
chunks = append(chunks, chunk{
|
||||
ChunkOffset: lastChunkOffset,
|
||||
Offset: lastOffset,
|
||||
Checksum: chunkDigester.Digest().String(),
|
||||
ChunkSize: chunkSize,
|
||||
ChunkType: chunkType,
|
||||
})
|
||||
}
|
||||
|
||||
lastOffset = off
|
||||
lastChunkOffset = rcReader.WrittenOut
|
||||
chunkDigester = digest.Canonical.Digester()
|
||||
payloadDest = io.MultiWriter(payloadDigester.Hash(), chunkDigester.Hash(), zstdWriter)
|
||||
}
|
||||
if errRead == io.EOF {
|
||||
if startOffset > 0 {
|
||||
checksum = payloadDigester.Digest().String()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
mainEntry, err := minimal.NewFileMetadata(hdr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mainEntry.Digest = checksum
|
||||
mainEntry.Offset = startOffset
|
||||
mainEntry.EndOffset = lastOffset
|
||||
entries := []minimal.FileMetadata{mainEntry}
|
||||
for i := 1; i < len(chunks); i++ {
|
||||
entries = append(entries, minimal.FileMetadata{
|
||||
Type: minimal.TypeChunk,
|
||||
Name: hdr.Name,
|
||||
ChunkOffset: chunks[i].ChunkOffset,
|
||||
})
|
||||
}
|
||||
if len(chunks) > 1 {
|
||||
for i := range chunks {
|
||||
entries[i].ChunkSize = chunks[i].ChunkSize
|
||||
entries[i].Offset = chunks[i].Offset
|
||||
entries[i].ChunkDigest = chunks[i].Checksum
|
||||
entries[i].ChunkType = chunks[i].ChunkType
|
||||
}
|
||||
}
|
||||
metadata = append(metadata, entries...)
|
||||
}
|
||||
|
||||
rawBytes := tr.RawBytes()
|
||||
if _, err := zstdWriter.Write(rawBytes); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payloadDigester := digest.Canonical.Digester()
|
||||
chunkDigester := digest.Canonical.Digester()
|
||||
|
||||
// Now handle the payload, if any
|
||||
startOffset := int64(0)
|
||||
lastOffset := int64(0)
|
||||
lastChunkOffset := int64(0)
|
||||
|
||||
checksum := ""
|
||||
|
||||
chunks := []chunk{}
|
||||
|
||||
hf := &holesFinder{
|
||||
threshold: holesThreshold,
|
||||
reader: bufio.NewReader(tr),
|
||||
// make sure the entire tarball is flushed to the output as it might contain
|
||||
// some trailing zeros that affect the checksum.
|
||||
if _, err := io.Copy(zstdWriter, its); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rcReader := &rollingChecksumReader{
|
||||
reader: hf,
|
||||
rollsum: NewRollSum(),
|
||||
if err := zstdWriter.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payloadDest := io.MultiWriter(payloadDigester.Hash(), chunkDigester.Hash(), zstdWriter)
|
||||
for {
|
||||
mustSplit, read, errRead := rcReader.Read(buf)
|
||||
if errRead != nil && errRead != io.EOF {
|
||||
return err
|
||||
}
|
||||
// restart the compression only if there is a payload.
|
||||
if read > 0 {
|
||||
if startOffset == 0 {
|
||||
startOffset, err = restartCompression()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lastOffset = startOffset
|
||||
}
|
||||
|
||||
if _, err := payloadDest.Write(buf[:read]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if (mustSplit || errRead == io.EOF) && startOffset > 0 {
|
||||
off, err := restartCompression()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chunkSize := rcReader.WrittenOut - lastChunkOffset
|
||||
if chunkSize > 0 {
|
||||
chunkType := minimal.ChunkTypeData
|
||||
if rcReader.IsLastChunkZeros {
|
||||
chunkType = minimal.ChunkTypeZeros
|
||||
}
|
||||
|
||||
chunks = append(chunks, chunk{
|
||||
ChunkOffset: lastChunkOffset,
|
||||
Offset: lastOffset,
|
||||
Checksum: chunkDigester.Digest().String(),
|
||||
ChunkSize: chunkSize,
|
||||
ChunkType: chunkType,
|
||||
})
|
||||
}
|
||||
|
||||
lastOffset = off
|
||||
lastChunkOffset = rcReader.WrittenOut
|
||||
chunkDigester = digest.Canonical.Digester()
|
||||
payloadDest = io.MultiWriter(payloadDigester.Hash(), chunkDigester.Hash(), zstdWriter)
|
||||
}
|
||||
if errRead == io.EOF {
|
||||
if startOffset > 0 {
|
||||
checksum = payloadDigester.Digest().String()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
mainEntry, err := minimal.NewFileMetadata(hdr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mainEntry.Digest = checksum
|
||||
mainEntry.Offset = startOffset
|
||||
mainEntry.EndOffset = lastOffset
|
||||
entries := []minimal.FileMetadata{mainEntry}
|
||||
for i := 1; i < len(chunks); i++ {
|
||||
entries = append(entries, minimal.FileMetadata{
|
||||
Type: minimal.TypeChunk,
|
||||
Name: hdr.Name,
|
||||
ChunkOffset: chunks[i].ChunkOffset,
|
||||
})
|
||||
}
|
||||
if len(chunks) > 1 {
|
||||
for i := range chunks {
|
||||
entries[i].ChunkSize = chunks[i].ChunkSize
|
||||
entries[i].Offset = chunks[i].Offset
|
||||
entries[i].ChunkDigest = chunks[i].Checksum
|
||||
entries[i].ChunkType = chunks[i].ChunkType
|
||||
}
|
||||
}
|
||||
metadata = append(metadata, entries...)
|
||||
}
|
||||
|
||||
rawBytes := tr.RawBytes()
|
||||
if _, err := zstdWriter.Write(rawBytes); err != nil {
|
||||
zstdWriter.Close()
|
||||
zstdWriter = nil
|
||||
return metadata, nil
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// make sure the entire tarball is flushed to the output as it might contain
|
||||
// some trailing zeros that affect the checksum.
|
||||
if _, err := io.Copy(zstdWriter, its); err != nil {
|
||||
zstdWriter.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := zstdWriter.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
zstdWriter = nil
|
||||
|
||||
if err := tarSplitData.zstd.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
15
vendor/modules.txt
vendored
15
vendor/modules.txt
vendored
|
|
@ -212,7 +212,7 @@ github.com/ebitengine/purego/internal/xreflect
|
|||
# github.com/felixge/httpsnoop v1.0.4
|
||||
## explicit; go 1.13
|
||||
github.com/felixge/httpsnoop
|
||||
# github.com/fsnotify/fsnotify v1.10.0
|
||||
# github.com/fsnotify/fsnotify v1.10.1
|
||||
## explicit; go 1.23
|
||||
github.com/fsnotify/fsnotify
|
||||
github.com/fsnotify/fsnotify/internal
|
||||
|
|
@ -503,7 +503,6 @@ github.com/opencontainers/image-spec/specs-go/v1
|
|||
github.com/opencontainers/runc/internal/linux
|
||||
github.com/opencontainers/runc/internal/pathrs
|
||||
github.com/opencontainers/runc/libcontainer/apparmor
|
||||
github.com/opencontainers/runc/libcontainer/devices
|
||||
# github.com/opencontainers/runtime-spec v1.3.0
|
||||
## explicit
|
||||
github.com/opencontainers/runtime-spec/specs-go
|
||||
|
|
@ -637,8 +636,8 @@ github.com/ulikunitz/xz
|
|||
github.com/ulikunitz/xz/internal/hash
|
||||
github.com/ulikunitz/xz/internal/xlog
|
||||
github.com/ulikunitz/xz/lzma
|
||||
# github.com/vbatts/tar-split v0.12.2
|
||||
## explicit; go 1.17
|
||||
# github.com/vbatts/tar-split v0.12.3
|
||||
## explicit; go 1.22.0
|
||||
github.com/vbatts/tar-split/archive/tar
|
||||
github.com/vbatts/tar-split/tar/asm
|
||||
github.com/vbatts/tar-split/tar/storage
|
||||
|
|
@ -699,7 +698,7 @@ go.opentelemetry.io/otel/trace
|
|||
go.opentelemetry.io/otel/trace/embedded
|
||||
go.opentelemetry.io/otel/trace/internal/telemetry
|
||||
go.opentelemetry.io/otel/trace/noop
|
||||
# go.podman.io/buildah v1.42.1-0.20260421143840-0acb6b8cca85
|
||||
# go.podman.io/buildah v1.42.1-0.20260501153811-377cf64e213b
|
||||
## explicit; go 1.25.6
|
||||
go.podman.io/buildah
|
||||
go.podman.io/buildah/bind
|
||||
|
|
@ -736,7 +735,7 @@ go.podman.io/buildah/pkg/sshagent
|
|||
go.podman.io/buildah/pkg/util
|
||||
go.podman.io/buildah/pkg/volumes
|
||||
go.podman.io/buildah/util
|
||||
# go.podman.io/common v0.67.2-0.20260430194920-3ceb1b29d72d
|
||||
# go.podman.io/common v0.67.2-0.20260504145149-b5d50461d3b9
|
||||
## explicit; go 1.25.6
|
||||
go.podman.io/common/internal
|
||||
go.podman.io/common/libimage
|
||||
|
|
@ -802,7 +801,7 @@ go.podman.io/common/pkg/umask
|
|||
go.podman.io/common/pkg/util
|
||||
go.podman.io/common/pkg/version
|
||||
go.podman.io/common/version
|
||||
# go.podman.io/image/v5 v5.39.3-0.20260430194920-3ceb1b29d72d
|
||||
# go.podman.io/image/v5 v5.39.3-0.20260504145149-b5d50461d3b9
|
||||
## explicit; go 1.25.6
|
||||
go.podman.io/image/v5/copy
|
||||
go.podman.io/image/v5/directory
|
||||
|
|
@ -879,7 +878,7 @@ go.podman.io/image/v5/transports
|
|||
go.podman.io/image/v5/transports/alltransports
|
||||
go.podman.io/image/v5/types
|
||||
go.podman.io/image/v5/version
|
||||
# go.podman.io/storage v1.62.1-0.20260430194920-3ceb1b29d72d
|
||||
# go.podman.io/storage v1.62.1-0.20260504145149-b5d50461d3b9
|
||||
## explicit; go 1.25.0
|
||||
go.podman.io/storage
|
||||
go.podman.io/storage/drivers
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue