mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-10 05:27:07 +08:00
config: fix file/folder ownership
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
5
vendor/github.com/tonistiigi/dchapes-mode/.hgignore
generated
vendored
Normal file
5
vendor/github.com/tonistiigi/dchapes-mode/.hgignore
generated
vendored
Normal 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
29
vendor/github.com/tonistiigi/dchapes-mode/Dockerfile
generated
vendored
Normal 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
22
vendor/github.com/tonistiigi/dchapes-mode/LICENSE
generated
vendored
Normal 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
26
vendor/github.com/tonistiigi/dchapes-mode/README.md
generated
vendored
Normal 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.
|
||||
|
||||
[](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
76
vendor/github.com/tonistiigi/dchapes-mode/bits.go
generated
vendored
Normal 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
|
||||
}
|
24
vendor/github.com/tonistiigi/dchapes-mode/docker-bake.hcl
generated
vendored
Normal file
24
vendor/github.com/tonistiigi/dchapes-mode/docker-bake.hcl
generated
vendored
Normal 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
546
vendor/github.com/tonistiigi/dchapes-mode/mode.go
generated
vendored
Normal 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)
|
||||
}
|
Reference in New Issue
Block a user