config: fix file/folder ownership

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2024-10-18 13:28:45 +02:00
parent 1de332530f
commit f89f861999
44 changed files with 2514 additions and 122 deletions

5
vendor/github.com/tonistiigi/dchapes-mode/.hgignore generated vendored Normal file
View File

@ -0,0 +1,5 @@
syntax: glob
bench*.out*
cmode
coverage.out
coverage.txt

29
vendor/github.com/tonistiigi/dchapes-mode/Dockerfile generated vendored Normal file
View File

@ -0,0 +1,29 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.23
ARG XX_VERSION=1.5.0
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS base
RUN apk add --no-cache git
COPY --from=xx / /
WORKDIR /src
FROM base AS build
ARG TARGETPLATFORM
RUN --mount=target=. --mount=target=/go/pkg/mod,type=cache \
--mount=target=/root/.cache,type=cache \
xx-go build ./...
FROM base AS test
ARG TESTFLAGS
RUN --mount=target=. --mount=target=/go/pkg/mod,type=cache \
--mount=target=/root/.cache,type=cache \
xx-go test -v -coverprofile=/tmp/coverage.txt -covermode=atomic ${TESTFLAGS} ./...
FROM scratch AS test-coverage
COPY --from=test /tmp/coverage.txt /coverage-root.txt
FROM build

22
vendor/github.com/tonistiigi/dchapes-mode/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
Copyright © 2016-2018, Dave Chapeskie
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

26
vendor/github.com/tonistiigi/dchapes-mode/README.md generated vendored Normal file
View File

@ -0,0 +1,26 @@
Mode
========
This is a fork of [hg.sr.ht/~dchapes/mode](https://hg.sr.ht/~dchapes/mode) with minimal patches and basic CI.
[Mode](https://hg.sr.ht/~dchapes/mode)
is a [Go](http://golang.org/) package that provides
a native Go implementation of BSD's
[`setmode`](https://www.freebsd.org/cgi/man.cgi?query=setmode&sektion=3)
and `getmode` which can be used to modify the mode bits of
an [`os.FileMode`](https://golang.org/pkg/os#FileMode) value
based on a symbolic value as described by the
Unix [`chmod`](https://www.freebsd.org/cgi/man.cgi?query=chmod&sektion=1) command.
[![Go Reference](https://pkg.go.dev/badge/hg.sr.ht/~dchapes/mode.svg)](https://pkg.go.dev/hg.sr.ht/~dchapes/mode)
Online package documentation is available via
[pkg.go.dev](https://pkg.go.dev/hg.sr.ht/~dchapes/mode).
To install:
go get hg.sr.ht/~dchapes/mode
or `go build` any Go code that imports it:
import "hg.sr.ht/~dchapes/mode"

76
vendor/github.com/tonistiigi/dchapes-mode/bits.go generated vendored Normal file
View File

@ -0,0 +1,76 @@
package mode
import "os"
type modet uint16
// Although many of these can be found in the syscall package
// we don't use those to avoid the dependency, add some more
// values, use non-exported Go names, and use octal for better clarity.
//
// Note that Go only uses the the nine least significant bits as "Unix
// permission bits" (os.ModePerm == 0777). We use chmod(1)'s octal
// definitions that include three further bits: isUID, isGID, and
// isTXT (07000). Go has os.ModeSetuid=1<<23, os.ModeSetgid=1<<22,
// and os.ModeSticy=1<<20 for these. We do this so that absolute
// octal values can include those bits as defined by chmod(1).
const (
//ifDir = 040000 // directory
isUID = 04000 // set user id on execution
isGID = 02000 // set group id on execution
isTXT = 01000 // sticky bit
iRWXU = 00700 // RWX mask for owner
iRUser = 00400 // R for owner
iWUser = 00200 // W for owner
iXUser = 00100 // X for owner
iRWXG = 00070 // RWX mask for group
iRGroup = 00040 // R for group
iWGroup = 00020 // W for group
iXGroup = 00010 // X for group
iRWXO = 00007 // RWX mask for other
iROther = 00004 // R for other
iWOther = 00002 // W for other
iXOther = 00001 // X for other
standardBits = isUID | isGID | iRWXU | iRWXG | iRWXO
// os.FileMode bits we touch
fmBits = os.ModeSetuid | os.ModeSetgid | os.ModeSticky | os.ModePerm
)
func fileModeToBits(fm os.FileMode) modet {
m := modet(fm.Perm())
/*
if fm&os.ModeSetuid != 0 {
m |= isUID
}
if fm&os.ModeSetgid != 0 {
m |= isGID
}
if fm&os.ModeSticky != 0 {
m |= isTXT
}
*/
m |= modet(fm & (os.ModeSetuid | os.ModeSetgid) >> 12)
m |= modet(fm & os.ModeSticky >> 11)
return m
}
func bitsToFileMode(old os.FileMode, m modet) os.FileMode {
fm := old &^ fmBits
fm |= os.FileMode(m) & os.ModePerm
/*
if m&isUID != 0 {
fm |= os.ModeSetuid
}
if m&isGID != 0 {
fm |= os.ModeSetgid
}
if m&isTXT != 0 {
fm |= os.ModeSticky
}
*/
fm |= os.FileMode(m&(isUID|isGID)) << 12
fm |= os.FileMode(m&isTXT) << 11
return fm
}

View File

@ -0,0 +1,24 @@
variable "GO_VERSION" {
default = null
}
group "default" {
targets = ["build"]
}
target "build" {
args = {
GO_VERSION = GO_VERSION
}
output = ["type=cacheonly"]
}
target "test" {
inherits = ["build"]
target = "test"
}
target "cross" {
inherits = ["build"]
platforms = ["linux/amd64", "linux/386", "linux/arm64", "linux/arm", "linux/ppc64le", "linux/s390x", "darwin/amd64", "darwin/arm64", "windows/amd64", "windows/arm64", "freebsd/amd64", "freebsd/arm64"]
}

546
vendor/github.com/tonistiigi/dchapes-mode/mode.go generated vendored Normal file
View File

@ -0,0 +1,546 @@
/*
Parts of this file are a heavily modified C to Go
translation of BSD's /usr/src/lib/libc/gen/setmode.c
that contains the following copyright notice:
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Dave Borman at Cray Research, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
// Package mode provides a native Go implementation of BSD's setmode and getmode
// which can be used to modify the mode bits of an os.FileMode value based on
// a symbolic value as described by the Unix chmod command.
//
// For a full description of the mode string see chmod(1).
// Some examples include:
//
// 644 make a file readable by anyone and writable by the owner
// only.
//
// go-w deny write permission to group and others.
//
// =rw,+X set the read and write permissions to the usual defaults,
// but retain any execute permissions that are currently set.
//
// +X make a directory or file searchable/executable by everyone
// if it is already searchable/executable by anyone.
//
// 755
// u=rwx,go=rx
// u=rwx,go=u-w make a file readable/executable by everyone and writable by
// the owner only.
//
// go= clear all mode bits for group and others.
//
// go=u-w set the group bits equal to the user bits, but clear the
// group write bit.
//
// See Also:
//
// setmode(3): https://www.freebsd.org/cgi/man.cgi?query=setmode&sektion=3
// chmod(1): https://www.freebsd.org/cgi/man.cgi?query=chmod&sektion=1
package mode
import (
"errors"
"fmt"
"os"
"strconv"
"strings"
)
// Set is a set of changes to apply to an os.FileMode.
// Changes include setting or clearing specific bits, copying bits from one
// user class to another (e.g. "u=go" sets the user permissions to a copy of
// the group and other permsissions), etc.
type Set struct {
cmds []bitcmd
}
type bitcmd struct {
cmd byte
cmd2 byte
bits modet
}
const (
cmd2Clear byte = 1 << iota
cmd2Set
cmd2GBits
cmd2OBits
cmd2UBits
)
func (c bitcmd) String() string {
c2 := ""
if c.cmd2 != 0 {
c2 = " cmd2:"
if c.cmd2&cmd2Clear != 0 {
c2 += " CLR"
}
if c.cmd2&cmd2Set != 0 {
c2 += " SET"
}
if c.cmd2&cmd2UBits != 0 {
c2 += " UBITS"
}
if c.cmd2&cmd2GBits != 0 {
c2 += " GBITS"
}
if c.cmd2&cmd2OBits != 0 {
c2 += " OBITS"
}
}
return fmt.Sprintf("cmd: %q bits %#05o%s", c.cmd, c.bits, c2)
}
// The String method will likely only be useful when testing.
func (s Set) String() string {
var buf strings.Builder
buf.Grow(21*len(s.cmds) + 10)
_, _ = buf.WriteString("set: {\n")
for _, c := range s.cmds {
_, _ = buf.WriteString(c.String())
_ = buf.WriteByte('\n')
}
_, _ = buf.WriteString("}")
return buf.String()
}
// ErrSyntax indicates an argument does not represent a valid mode.
var ErrSyntax = errors.New("invalid syntax")
// Apply changes the provided os.FileMode based on the given umask and
// absolute or symbolic mode value.
//
// Apply is a convience to calling ParseWithUmask followed by Apply.
// Since it needs to parse the mode value string on each call it
// should only be used when mode value string will not be reapplied.
func Apply(s string, perm os.FileMode, umask uint) (os.FileMode, error) {
set, err := ParseWithUmask(s, umask)
if err != nil {
return 0, err
}
return set.Apply(perm), nil
}
// Parse takes an absolute (octal) or symbolic mode value,
// as described in chmod(1), as an argument and returns
// the set of bit operations representing the mode value
// that can be applied to specific os.FileMode values.
//
// Same as ParseWithUmask(s, 0).
func Parse(s string) (Set, error) {
return ParseWithUmask(s, 0)
}
// TODO(dchapes): A Set.Parse method that reuses existing memory.
// TODO(dchapes): Only call syscall.Umask when abosolutely necessary and
// provide a Set method to query if set is umask dependant (and perhaps
// the umask that was in effect when parsed).
// ParseWithUmask is like Parse but uses the provided
// file creation mask instead of calling syscall.Umask.
func ParseWithUmask(s string, umask uint) (Set, error) {
var m Set
if s == "" {
return m, ErrSyntax
}
// If an absolute number, get it and return;
// disallow non-octal digits or illegal bits.
if d := s[0]; '0' <= d && d <= '9' {
v, err := strconv.ParseInt(s, 8, 16)
if err != nil {
return m, err
}
if v&^(standardBits|isTXT) != 0 {
return m, ErrSyntax
}
// We know this takes exactly two bitcmds.
m.cmds = make([]bitcmd, 0, 2)
m.addcmd('=', standardBits|isTXT, modet(v), 0)
return m, nil
}
// Get a copy of the mask for the permissions that are mask relative.
// Flip the bits, we want what's not set.
var mask modet = ^modet(umask)
// Pre-allocate room for several commands.
//m.cmds = make([]bitcmd, 0, 8)
// Build list of bitcmd structs to set/clear/copy bits as described by
// each clause of the symbolic mode.
equalOpDone := false
for {
// First, find out which bits might be modified.
var who modet
whoLoop:
for {
if len(s) == 0 {
return Set{}, ErrSyntax
}
switch s[0] {
case 'a':
who |= standardBits
case 'u':
who |= isUID | iRWXU
case 'g':
who |= isGID | iRWXG
case 'o':
who |= iRWXO
default:
break whoLoop
}
s = s[1:]
}
var op byte
getop:
op, s = s[0], s[1:]
switch op {
case '+', '-':
// Nothing.
case '=':
equalOpDone = false
default:
return Set{}, ErrSyntax
}
who &^= isTXT
permLoop:
for perm, permX := modet(0), modet(0); ; s = s[1:] {
var b byte
if len(s) > 0 {
b = s[0]
}
switch b {
case 'r':
perm |= iRUser | iRGroup | iROther
case 's':
// If only "other" bits ignore set-id.
if who == 0 || who&^iRWXO != 0 {
perm |= isUID | isGID
}
case 't':
// If only "other bits ignore sticky.
if who == 0 || who&^iRWXO != 0 {
who |= isTXT
perm |= isTXT
}
case 'w':
perm |= iWUser | iWGroup | iWOther
case 'X':
if op == '+' {
permX = iXUser | iXGroup | iXOther
}
case 'x':
perm |= iXUser | iXGroup | iXOther
case 'u', 'g', 'o':
// Whenever we hit 'u', 'g', or 'o', we have
// to flush out any partial mode that we have,
// and then do the copying of the mode bits.
if perm != 0 {
m.addcmd(op, who, perm, mask)
perm = 0
}
if op == '=' {
equalOpDone = true
}
if permX != 0 {
m.addcmd('X', who, permX, mask)
permX = 0
}
m.addcmd(b, who, modet(op), mask)
default:
// Add any permissions that we haven't alread done.
if perm != 0 || op == '=' && !equalOpDone {
if op == '=' {
equalOpDone = true
}
m.addcmd(op, who, perm, mask)
//perm = 0
}
if permX != 0 {
m.addcmd('X', who, permX, mask)
//permX = 0
}
break permLoop
}
}
if s == "" {
break
}
if s[0] != ',' {
goto getop
}
s = s[1:]
}
m.compress()
return m, nil
}
// Apply returns the os.FileMode after applying the set of changes.
func (s Set) Apply(perm os.FileMode) os.FileMode {
omode := fileModeToBits(perm)
newmode := omode
// When copying the user, group or other bits around, we "know"
// where the bits are in the mode so that we can do shifts to
// copy them around. If we don't use shifts, it gets real
// grundgy with lots of single bit checks and bit sets.
common := func(c bitcmd, value modet) {
if c.cmd2&cmd2Clear != 0 {
var clrval modet
if c.cmd2&cmd2Set != 0 {
clrval = iRWXO
} else {
clrval = value
}
if c.cmd2&cmd2UBits != 0 {
newmode &^= clrval << 6 & c.bits
}
if c.cmd2&cmd2GBits != 0 {
newmode &^= clrval << 3 & c.bits
}
if c.cmd2&cmd2OBits != 0 {
newmode &^= clrval & c.bits
}
}
if c.cmd2&cmd2Set != 0 {
if c.cmd2&cmd2UBits != 0 {
newmode |= value << 6 & c.bits
}
if c.cmd2&cmd2GBits != 0 {
newmode |= value << 3 & c.bits
}
if c.cmd2&cmd2OBits != 0 {
newmode |= value & c.bits
}
}
}
for _, c := range s.cmds {
switch c.cmd {
case 'u':
common(c, newmode&iRWXU>>6)
case 'g':
common(c, newmode&iRWXG>>3)
case 'o':
common(c, newmode&iRWXO)
case '+':
newmode |= c.bits
case '-':
newmode &^= c.bits
case 'X':
if omode&(iXUser|iXGroup|iXOther) != 0 || perm.IsDir() {
newmode |= c.bits
}
}
}
return bitsToFileMode(perm, newmode)
}
// Chmod is a convience routine that applies the changes in
// Set to the named file. To avoid some race conditions,
// it opens the file and uses os.File.Stat and
// os.File.Chmod rather than os.Stat and os.Chmod if possible.
func (s *Set) Chmod(name string) (old, new os.FileMode, err error) {
if f, err := os.Open(name); err == nil { // nolint: vetshadow
defer f.Close() // nolint: errcheck
return s.ChmodFile(f)
}
// Fallback to os.Stat and os.Chmod if we
// don't have permission to open the file.
fi, err := os.Stat(name)
if err != nil {
return 0, 0, err
}
old = fi.Mode()
new = s.Apply(old)
if new != old {
err = os.Chmod(name, new)
}
return old, new, err
}
// ChmodFile is a convience routine that applies
// the changes in Set to the open file f.
func (s *Set) ChmodFile(f *os.File) (old, new os.FileMode, err error) {
fi, err := f.Stat()
if err != nil {
return 0, 0, err
}
old = fi.Mode()
new = s.Apply(old)
if new != old {
err = f.Chmod(new)
}
return old, new, err
}
func (s *Set) addcmd(op byte, who, oparg, mask modet) {
c := bitcmd{}
switch op {
case '=':
c.cmd = '-'
if who != 0 {
c.bits = who
} else {
c.bits = standardBits
}
s.cmds = append(s.cmds, c)
//c = bitcmd{} // reset, not actually needed
op = '+'
fallthrough
case '+', '-', 'X':
c.cmd = op
if who != 0 {
c.bits = who & oparg
} else {
c.bits = mask & oparg
}
case 'u', 'g', 'o':
c.cmd = op
if who != 0 {
if who&iRUser != 0 {
c.cmd2 |= cmd2UBits
}
if who&iRGroup != 0 {
c.cmd2 |= cmd2GBits
}
if who&iROther != 0 {
c.cmd2 |= cmd2OBits
}
c.bits = ^modet(0)
} else {
c.cmd2 = cmd2UBits | cmd2GBits | cmd2OBits
c.bits = mask
}
switch oparg {
case '+':
c.cmd2 |= cmd2Set
case '-':
c.cmd2 |= cmd2Clear
case '=':
c.cmd2 |= cmd2Set | cmd2Clear
}
default:
panic("unreachable")
}
s.cmds = append(s.cmds, c)
}
// compress by compacting consecutive '+', '-' and 'X'
// commands into at most 3 commands, one of each. The 'u',
// 'g' and 'o' commands continue to be separate. They could
// probably be compacted, but it's not worth the effort.
func (s *Set) compress() {
//log.Println("before:", *m)
//log.Println("Start compress:")
j := 0
for i := 0; i < len(s.cmds); i++ {
c := s.cmds[i]
//log.Println(" read", i, c)
if strings.IndexByte("+-X", c.cmd) < 0 {
// Copy over any 'u', 'g', and 'o' commands.
if i != j {
s.cmds[j] = c
}
//log.Println(" wrote", j, "from", i)
j++
continue
}
var setbits, clrbits, Xbits modet
for ; i < len(s.cmds); i++ {
c = s.cmds[i]
//log.Println(" scan", i, c)
switch c.cmd {
case '-':
clrbits |= c.bits
setbits &^= c.bits
Xbits &^= c.bits
continue
case '+':
setbits |= c.bits
clrbits &^= c.bits
Xbits &^= c.bits
continue
case 'X':
Xbits |= c.bits &^ setbits
continue
default:
i--
}
break
}
if clrbits != 0 {
s.cmds[j].cmd = '-'
s.cmds[j].cmd2 = 0
s.cmds[j].bits = clrbits
//log.Println(" wrote", j, "clrbits")
j++
}
if setbits != 0 {
s.cmds[j].cmd = '+'
s.cmds[j].cmd2 = 0
s.cmds[j].bits = setbits
//log.Println(" wrote", j, "setbits")
j++
}
if Xbits != 0 {
s.cmds[j].cmd = 'X'
s.cmds[j].cmd2 = 0
s.cmds[j].bits = Xbits
//log.Println(" wrote", j, "Xbits")
j++
}
}
/*
if len(m.cmds) != j {
log.Println("compressed", len(m.cmds), "down to", j)
}
*/
s.cmds = s.cmds[:j]
//log.Println("after:", *m)
}