forked from toolshed/abra
Compare commits
19 Commits
chore-deps
...
add_docker
| Author | SHA1 | Date | |
|---|---|---|---|
| 12d4252acb | |||
| 776693acc0 | |||
| 5dea5f7746 | |||
| 1d9a289888 | |||
| c7bd55e371 | |||
| 4276337b0f | |||
| 90ca856b64 | |||
| f2dd65491d | |||
| 0e902ed897 | |||
| db001c1ba4 | |||
| e4215c09aa | |||
| e0e6dcb710 | |||
| e7ddb74a08 | |||
| 24a5e6334f | |||
| 9d8eb2317e | |||
| 5945ea8e1b | |||
| e170d1c971 | |||
| 5eba3abb1b | |||
| df5a38e887 |
@ -15,7 +15,7 @@ WORKDIR /app
|
||||
|
||||
RUN CGO_ENABLED=0 make build
|
||||
|
||||
FROM alpine:3.22
|
||||
FROM alpine:3.23
|
||||
|
||||
RUN apk add --no-cache \
|
||||
ca-certificates \
|
||||
|
||||
@ -151,11 +151,12 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
||||
|
||||
stackName := app.StackName()
|
||||
deployOpts := stack.Deploy{
|
||||
Composefiles: composeFiles,
|
||||
Namespace: stackName,
|
||||
Prune: false,
|
||||
ResolveImage: stack.ResolveImageAlways,
|
||||
Detach: false,
|
||||
Composefiles: composeFiles,
|
||||
Namespace: stackName,
|
||||
Prune: false,
|
||||
ResolveImage: stack.ResolveImageAlways,
|
||||
Detach: false,
|
||||
SendRegistryAuth: true,
|
||||
}
|
||||
compose, err := appPkg.GetAppComposeConfig(app.Name, deployOpts, app.Env)
|
||||
if err != nil {
|
||||
|
||||
@ -166,11 +166,12 @@ beforehand. See "abra app backup" for more.`),
|
||||
|
||||
stackName := app.StackName()
|
||||
deployOpts := stack.Deploy{
|
||||
Composefiles: composeFiles,
|
||||
Namespace: stackName,
|
||||
Prune: false,
|
||||
ResolveImage: stack.ResolveImageAlways,
|
||||
Detach: false,
|
||||
Composefiles: composeFiles,
|
||||
Namespace: stackName,
|
||||
Prune: false,
|
||||
ResolveImage: stack.ResolveImageAlways,
|
||||
Detach: false,
|
||||
SendRegistryAuth: true,
|
||||
}
|
||||
|
||||
compose, err := appPkg.GetAppComposeConfig(app.Name, deployOpts, app.Env)
|
||||
|
||||
@ -178,11 +178,12 @@ beforehand. See "abra app backup" for more.`),
|
||||
|
||||
stackName := app.StackName()
|
||||
deployOpts := stack.Deploy{
|
||||
Composefiles: composeFiles,
|
||||
Namespace: stackName,
|
||||
Prune: false,
|
||||
ResolveImage: stack.ResolveImageAlways,
|
||||
Detach: false,
|
||||
Composefiles: composeFiles,
|
||||
Namespace: stackName,
|
||||
Prune: false,
|
||||
ResolveImage: stack.ResolveImageAlways,
|
||||
Detach: false,
|
||||
SendRegistryAuth: true,
|
||||
}
|
||||
|
||||
compose, err := appPkg.GetAppComposeConfig(app.Name, deployOpts, app.Env)
|
||||
|
||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1778443072,
|
||||
"narHash": "sha256-zi7/fsqM/kFdNuED//4WOCUtezGtKKqRNORjMvfwjnA=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "da5ad661ba4e5ef59ba743f0d112cbc30e474f32",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
37
flake.nix
Normal file
37
flake.nix
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
description = "The Co-op Cloud utility belt";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
packages = rec {
|
||||
abra = pkgs.callPackage ./package.nix { };
|
||||
default = abra;
|
||||
};
|
||||
apps = rec {
|
||||
abra = flake-utils.lib.mkApp { drv = self.packages.${system}.abra; };
|
||||
default = abra;
|
||||
};
|
||||
devShells.default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
go_1_26
|
||||
gnumake
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
22
go.mod
22
go.mod
@ -3,7 +3,7 @@ module coopcloud.tech/abra
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
coopcloud.tech/tagcmp v0.0.0-20250818180036-0ec1b205b5ca
|
||||
coopcloud.tech/tagcmp v0.0.0-20260515102403-c26951b55977
|
||||
git.coopcloud.tech/toolshed/godotenv v1.5.2-0.20250103171850-4d0ca41daa5c
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7
|
||||
github.com/charmbracelet/bubbletea v1.3.10
|
||||
@ -13,14 +13,14 @@ require (
|
||||
github.com/docker/cli v28.4.0+incompatible
|
||||
github.com/docker/docker v28.5.2+incompatible
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/go-git/go-git/v5 v5.17.2
|
||||
github.com/go-git/go-git/v5 v5.19.1
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/leonelquinteros/gotext v1.7.2
|
||||
github.com/moby/sys/signal v0.7.1
|
||||
github.com/moby/term v0.5.2
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/schollz/progressbar/v3 v3.19.0
|
||||
golang.org/x/term v0.41.0
|
||||
golang.org/x/term v0.43.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gotest.tools/v3 v3.5.2
|
||||
)
|
||||
@ -60,7 +60,7 @@ require (
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.8.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.9.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.1 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
@ -96,7 +96,7 @@ require (
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/runc v1.1.13 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.6.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.67.5 // indirect
|
||||
@ -124,10 +124,10 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.49.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
|
||||
golang.org/x/net v0.52.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
golang.org/x/crypto v0.50.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
|
||||
golang.org/x/net v0.53.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
|
||||
@ -155,9 +155,9 @@ require (
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
golang.org/x/sys v0.42.0
|
||||
golang.org/x/sys v0.45.0
|
||||
)
|
||||
|
||||
replace github.com/docker/cli v28.4.0+incompatible => git.coopcloud.tech/toolshed/docker-cli v28.5.3-0.20260202112816-30df2d0b3a00+incompatible
|
||||
|
||||
replace github.com/spf13/cobra => github.com/decentral1se/cobra v1.10.2-i18n
|
||||
replace github.com/spf13/cobra => github.com/decentral1se/cobra v1.10.2
|
||||
|
||||
44
go.sum
44
go.sum
@ -22,8 +22,8 @@ cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIA
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
coopcloud.tech/tagcmp v0.0.0-20250818180036-0ec1b205b5ca h1:gSD53tBAsbIGq4SnFfq+mEep6foekQ2a5ea7b38qkm0=
|
||||
coopcloud.tech/tagcmp v0.0.0-20250818180036-0ec1b205b5ca/go.mod h1:ESVm0wQKcbcFi06jItF3rI7enf4Jt2PvbkWpDDHk1DQ=
|
||||
coopcloud.tech/tagcmp v0.0.0-20260515102403-c26951b55977 h1:J7I0HFjwVAj/kkX6lwSTHmlXDRjQRsdIFNUUqu55ADY=
|
||||
coopcloud.tech/tagcmp v0.0.0-20260515102403-c26951b55977/go.mod h1:ESVm0wQKcbcFi06jItF3rI7enf4Jt2PvbkWpDDHk1DQ=
|
||||
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
@ -308,8 +308,8 @@ github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjI
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decentral1se/cobra v1.10.2-i18n h1:XR+6AHHfnf4k5NM9f09oLMrEVwz3rkQIAIcqgL8R08g=
|
||||
github.com/decentral1se/cobra v1.10.2-i18n/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||
github.com/decentral1se/cobra v1.10.2 h1:MZ8Ifi/jRels9sZrpSccDbUlK++3b2HlBODfv0Bh6x0=
|
||||
github.com/decentral1se/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||
github.com/decentral1se/passgen v1.0.1 h1:j2AxK/kHKxDHWZZfkJj8Wgae9+O+DYEqR5sjKthIYKA=
|
||||
github.com/decentral1se/passgen v1.0.1/go.mod h1:530V+lNoPhKtkrX2fIVsIfLhkl47CuiOM7HRgi7C+SU=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
@ -389,12 +389,12 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0=
|
||||
github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY=
|
||||
github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA=
|
||||
github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.17.2 h1:B+nkdlxdYrvyFK4GPXVU8w1U+YkbsgciIR7f2sZJ104=
|
||||
github.com/go-git/go-git/v5 v5.17.2/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo=
|
||||
github.com/go-git/go-git/v5 v5.19.1 h1:nX27AnaU43/K5bKktKwgBmR9lawoYVe1Ckg0rgzzN00=
|
||||
github.com/go-git/go-git/v5 v5.19.1/go.mod h1:Pb1v0c7/g8aGQJwx9Us09W85yGoyvSwuhEGMH7zjDKQ=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@ -753,8 +753,8 @@ github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuh
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
|
||||
github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
|
||||
github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU=
|
||||
github.com/pjbgf/sha1cd v0.6.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@ -966,8 +966,8 @@ golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWP
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -978,8 +978,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
|
||||
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
|
||||
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@ -1043,8 +1043,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -1140,13 +1140,13 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
||||
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
|
||||
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -1156,8 +1156,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
||||
54
package.nix
Normal file
54
package.nix
Normal file
@ -0,0 +1,54 @@
|
||||
{
|
||||
buildGo126Module,
|
||||
fetchgit,
|
||||
lib,
|
||||
installShellFiles,
|
||||
}:
|
||||
|
||||
buildGo126Module rec {
|
||||
pname = "abra";
|
||||
version = "0.13.0-beta";
|
||||
rev = "06a57ded025a43c80f94d4e65299add8a31830dc";
|
||||
|
||||
src = fetchgit {
|
||||
url = "https://git.coopcloud.tech/toolshed/abra.git";
|
||||
tag = version;
|
||||
hash = "sha256-rgoK0TY0WLSQ39lPvVM80zW/qJF40VFBSxYDOaKXZQo=";
|
||||
};
|
||||
|
||||
vendorHash = null;
|
||||
|
||||
nativeBuildInputs = [
|
||||
installShellFiles
|
||||
];
|
||||
|
||||
env.CGO_ENABLED = 0;
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
go build -ldflags="-s -w -X 'main.Commit=${rev}' -X 'main.Version=${version}'" ./cmd/abra
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
install -D abra $out/bin/abra
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
export ABRA_DIR="$out"
|
||||
$out/bin/abra autocomplete bash >abra.bash
|
||||
$out/bin/abra autocomplete fish >abra.fish
|
||||
$out/bin/abra autocomplete zsh >abra.zsh
|
||||
installShellCompletion abra.{bash,fish,zsh}
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "The Co-op Cloud utility belt";
|
||||
homepage = "https://docs.coopcloud.tech/abra";
|
||||
changelog = "https://git.coopcloud.tech/toolshed/abra/releases/tag/${version}";
|
||||
mainProgram = "abra";
|
||||
license = licenses.gpl3Plus;
|
||||
maintainers = "devydave";
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: nginx:1.21.0
|
||||
image: nginx:1.31.1
|
||||
secrets:
|
||||
- test_pass_one
|
||||
- test_pass_two
|
||||
|
||||
@ -3,7 +3,7 @@ version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: nginx:1.29.0
|
||||
image: nginx:1.31.1
|
||||
networks:
|
||||
- proxy
|
||||
deploy:
|
||||
|
||||
6
vendor/coopcloud.tech/tagcmp/.drone.yml
vendored
6
vendor/coopcloud.tech/tagcmp/.drone.yml
vendored
@ -3,16 +3,16 @@ kind: pipeline
|
||||
name: coopcloud.tech/tagcmp
|
||||
steps:
|
||||
- name: gofmt
|
||||
image: golang:1.21
|
||||
image: golang:1.26
|
||||
commands:
|
||||
- test -z "$(gofmt -l .)"
|
||||
|
||||
- name: go build
|
||||
image: golang:1.21
|
||||
image: golang:1.26
|
||||
commands:
|
||||
- go build -v .
|
||||
|
||||
- name: go test
|
||||
image: golang:1.21
|
||||
image: golang:1.26
|
||||
commands:
|
||||
- go test . -cover
|
||||
|
||||
6
vendor/coopcloud.tech/tagcmp/renovate.json
vendored
Normal file
6
vendor/coopcloud.tech/tagcmp/renovate.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
]
|
||||
}
|
||||
4
vendor/github.com/go-git/go-billy/v5/README.md
generated
vendored
4
vendor/github.com/go-git/go-billy/v5/README.md
generated
vendored
@ -5,6 +5,10 @@ Billy implements an interface based on the `os` standard library, allowing to de
|
||||
|
||||
Billy was born as part of [go-git/go-git](https://github.com/go-git/go-git) project.
|
||||
|
||||
## Version support
|
||||
|
||||
go-billy v5 is in maintenance mode. Users should upgrade to [go-billy v6](https://pkg.go.dev/github.com/go-git/go-billy/v6) where possible.
|
||||
|
||||
## Installation
|
||||
|
||||
```go
|
||||
|
||||
208
vendor/github.com/go-git/go-billy/v5/helper/chroot/chroot.go
generated
vendored
208
vendor/github.com/go-git/go-billy/v5/helper/chroot/chroot.go
generated
vendored
@ -3,19 +3,25 @@ package chroot
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/go-git/go-billy/v5"
|
||||
"github.com/go-git/go-billy/v5/helper/polyfill"
|
||||
)
|
||||
|
||||
// ChrootHelper is a helper to implement billy.Chroot.
|
||||
// It is not a security boundary, callers that need containment should use a
|
||||
// filesystem implementation that enforces paths at the OS boundary instead.
|
||||
type ChrootHelper struct {
|
||||
underlying billy.Filesystem
|
||||
base string
|
||||
}
|
||||
|
||||
const maxFollowedSymlinks = 8 // Aligns with POSIX_SYMLOOP_MAX
|
||||
|
||||
// New creates a new filesystem wrapping up the given 'fs'.
|
||||
// The created filesystem has its base in the given ChrootHelperectory of the
|
||||
// underlying filesystem.
|
||||
@ -34,15 +40,184 @@ func (fs *ChrootHelper) underlyingPath(filename string) (string, error) {
|
||||
return fs.Join(fs.Root(), filename), nil
|
||||
}
|
||||
|
||||
func isCrossBoundaries(path string) bool {
|
||||
path = filepath.ToSlash(path)
|
||||
path = filepath.Clean(path)
|
||||
func (fs *ChrootHelper) followedPath(filename string, followFinal bool, op string) (string, error) {
|
||||
fullpath, err := fs.underlyingPath(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strings.HasPrefix(path, ".."+string(filepath.Separator))
|
||||
sl, ok := fs.underlying.(billy.Symlink)
|
||||
if !ok {
|
||||
return fullpath, nil
|
||||
}
|
||||
|
||||
rel, err := fs.relativeToRoot(fullpath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fullpath, err = fs.resolveFollowedPath(rel, followFinal, op, sl)
|
||||
if errors.Is(err, billy.ErrNotSupported) {
|
||||
return fs.underlyingPath(filename)
|
||||
}
|
||||
|
||||
return fullpath, err
|
||||
}
|
||||
|
||||
func (fs *ChrootHelper) resolveFollowedPath(rel string, followFinal bool, op string, sl billy.Symlink) (string, error) {
|
||||
if rel == "" {
|
||||
return fs.resolveFollowedRoot(followFinal, op, sl)
|
||||
}
|
||||
|
||||
parts := splitRelativePath(rel)
|
||||
resolved := ""
|
||||
followed := 0
|
||||
|
||||
for len(parts) > 0 {
|
||||
part := parts[0]
|
||||
parts = parts[1:]
|
||||
|
||||
currentRel := joinRelativePath(resolved, part)
|
||||
currentPath := fs.Join(fs.Root(), currentRel)
|
||||
if len(parts) == 0 && !followFinal {
|
||||
return currentPath, nil
|
||||
}
|
||||
|
||||
fi, err := sl.Lstat(currentPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return fs.Join(fs.Root(), joinRelativePath(append([]string{currentRel}, parts...)...)), nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
if fi.Mode()&os.ModeSymlink == 0 {
|
||||
resolved = currentRel
|
||||
continue
|
||||
}
|
||||
|
||||
followed++
|
||||
if followed > maxFollowedSymlinks {
|
||||
return "", symlinkLoopError(op, currentPath)
|
||||
}
|
||||
|
||||
target, err := sl.Readlink(currentPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
targetRel, err := fs.linkTargetRel(currentPath, target)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if targetRel == currentRel {
|
||||
return "", symlinkLoopError(op, currentPath)
|
||||
}
|
||||
|
||||
parts = append(splitRelativePath(targetRel), parts...)
|
||||
resolved = ""
|
||||
}
|
||||
|
||||
return fs.Join(fs.Root(), resolved), nil
|
||||
}
|
||||
|
||||
func symlinkLoopError(op, path string) error {
|
||||
return &os.PathError{Op: op, Path: path, Err: syscall.ELOOP}
|
||||
}
|
||||
|
||||
func (fs *ChrootHelper) resolveFollowedRoot(followFinal bool, op string, sl billy.Symlink) (string, error) {
|
||||
root := fs.Join(fs.Root(), "")
|
||||
if !followFinal {
|
||||
return root, nil
|
||||
}
|
||||
|
||||
fi, err := sl.Lstat(root)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return root, nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
if fi.Mode()&os.ModeSymlink == 0 {
|
||||
return root, nil
|
||||
}
|
||||
|
||||
target, err := sl.Readlink(root)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
targetRel, err := fs.linkTargetRel(root, target)
|
||||
if err != nil {
|
||||
return root, err
|
||||
}
|
||||
if targetRel == "" {
|
||||
return "", symlinkLoopError(op, root)
|
||||
}
|
||||
|
||||
return fs.resolveFollowedPath(targetRel, followFinal, op, sl)
|
||||
}
|
||||
|
||||
func (fs *ChrootHelper) relativeToRoot(filename string) (string, error) {
|
||||
rel, err := filepath.Rel(filepath.Clean(fs.Root()), filepath.Clean(filename))
|
||||
if err != nil || isCrossBoundaries(rel) {
|
||||
return "", billy.ErrCrossedBoundary
|
||||
}
|
||||
|
||||
if rel == "." {
|
||||
return "", nil
|
||||
}
|
||||
return rel, nil
|
||||
}
|
||||
|
||||
func (fs *ChrootHelper) linkTargetRel(linkPath, target string) (string, error) {
|
||||
target = filepath.FromSlash(target)
|
||||
if filepath.IsAbs(target) || strings.HasPrefix(target, string(filepath.Separator)) {
|
||||
return fs.relativeToRoot(target)
|
||||
}
|
||||
|
||||
return fs.relativeToRoot(fs.Join(filepath.Dir(linkPath), target))
|
||||
}
|
||||
|
||||
func splitRelativePath(filename string) []string {
|
||||
filename = filepath.Clean(filename)
|
||||
if filename == "" || filename == "." {
|
||||
return nil
|
||||
}
|
||||
|
||||
return strings.Split(filepath.ToSlash(filename), "/")
|
||||
}
|
||||
|
||||
func joinRelativePath(elem ...string) string {
|
||||
parts := make([]string, 0, len(elem))
|
||||
for _, part := range elem {
|
||||
if part == "" || part == "." {
|
||||
continue
|
||||
}
|
||||
parts = append(parts, part)
|
||||
}
|
||||
|
||||
if len(parts) == 0 {
|
||||
return ""
|
||||
}
|
||||
return filepath.Join(parts...)
|
||||
}
|
||||
|
||||
func isCreateExclusive(flag int) bool {
|
||||
return flag&os.O_CREATE != 0 && flag&os.O_EXCL != 0
|
||||
}
|
||||
|
||||
func isCrossBoundaries(name string) bool {
|
||||
name = filepath.ToSlash(name)
|
||||
name = strings.TrimLeft(name, "/")
|
||||
name = path.Clean(name)
|
||||
|
||||
return name == ".." || strings.HasPrefix(name, "../")
|
||||
}
|
||||
|
||||
func (fs *ChrootHelper) Create(filename string) (billy.File, error) {
|
||||
fullpath, err := fs.underlyingPath(filename)
|
||||
fullpath, err := fs.followedPath(filename, true, "create")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -56,7 +231,7 @@ func (fs *ChrootHelper) Create(filename string) (billy.File, error) {
|
||||
}
|
||||
|
||||
func (fs *ChrootHelper) Open(filename string) (billy.File, error) {
|
||||
fullpath, err := fs.underlyingPath(filename)
|
||||
fullpath, err := fs.followedPath(filename, true, "open")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -70,7 +245,7 @@ func (fs *ChrootHelper) Open(filename string) (billy.File, error) {
|
||||
}
|
||||
|
||||
func (fs *ChrootHelper) OpenFile(filename string, flag int, mode os.FileMode) (billy.File, error) {
|
||||
fullpath, err := fs.underlyingPath(filename)
|
||||
fullpath, err := fs.followedPath(filename, !isCreateExclusive(flag), "open")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -84,12 +259,16 @@ func (fs *ChrootHelper) OpenFile(filename string, flag int, mode os.FileMode) (b
|
||||
}
|
||||
|
||||
func (fs *ChrootHelper) Stat(filename string) (os.FileInfo, error) {
|
||||
fullpath, err := fs.underlyingPath(filename)
|
||||
fullpath, err := fs.followedPath(filename, true, "stat")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return fs.underlying.Stat(fullpath)
|
||||
fi, err := fs.underlying.Stat(fullpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fileInfo{FileInfo: fi, name: filepath.Base(filename)}, nil
|
||||
}
|
||||
|
||||
func (fs *ChrootHelper) Rename(from, to string) error {
|
||||
@ -135,7 +314,7 @@ func (fs *ChrootHelper) TempFile(dir, prefix string) (billy.File, error) {
|
||||
}
|
||||
|
||||
func (fs *ChrootHelper) ReadDir(path string) ([]os.FileInfo, error) {
|
||||
fullpath, err := fs.underlyingPath(path)
|
||||
fullpath, err := fs.followedPath(path, true, "readdir")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -241,6 +420,11 @@ type file struct {
|
||||
name string
|
||||
}
|
||||
|
||||
type fileInfo struct {
|
||||
os.FileInfo
|
||||
name string
|
||||
}
|
||||
|
||||
func newFile(fs billy.Filesystem, f billy.File, filename string) billy.File {
|
||||
filename = fs.Join(fs.Root(), filename)
|
||||
filename, _ = filepath.Rel(fs.Root(), filename)
|
||||
@ -254,3 +438,7 @@ func newFile(fs billy.Filesystem, f billy.File, filename string) billy.File {
|
||||
func (f *file) Name() string {
|
||||
return f.name
|
||||
}
|
||||
|
||||
func (fi fileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
|
||||
5
vendor/github.com/go-git/go-billy/v5/osfs/os.go
generated
vendored
5
vendor/github.com/go-git/go-billy/v5/osfs/os.go
generated
vendored
@ -24,6 +24,9 @@ var Default = &ChrootOS{}
|
||||
// New returns a new OS filesystem.
|
||||
// By default paths are deduplicated, but still enforced
|
||||
// under baseDir. For more info refer to WithDeduplicatePath.
|
||||
//
|
||||
// New returns ChrootOS by default for v5 compatibility. Users should prefer
|
||||
// New with WithBoundOS.
|
||||
func New(baseDir string, opts ...Option) billy.Filesystem {
|
||||
o := &options{
|
||||
deduplicatePath: true,
|
||||
@ -47,6 +50,8 @@ func WithBoundOS() Option {
|
||||
}
|
||||
|
||||
// WithChrootOS returns the option of using a Chroot filesystem OS.
|
||||
//
|
||||
// Deprecated: use WithBoundOS instead.
|
||||
func WithChrootOS() Option {
|
||||
return func(o *options) {
|
||||
o.Type = ChrootOSFS
|
||||
|
||||
100
vendor/github.com/go-git/go-billy/v5/osfs/os_bound.go
generated
vendored
100
vendor/github.com/go-git/go-billy/v5/osfs/os_bound.go
generated
vendored
@ -20,6 +20,7 @@
|
||||
package osfs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -29,6 +30,31 @@ import (
|
||||
"github.com/go-git/go-billy/v5"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrBaseDirCannotBeRemoved is returned when removing the BoundOS base dir.
|
||||
ErrBaseDirCannotBeRemoved = errors.New("base dir cannot be removed")
|
||||
|
||||
// ErrBaseDirCannotBeRenamed is returned when renaming the BoundOS base dir.
|
||||
ErrBaseDirCannotBeRenamed = errors.New("base dir cannot be renamed")
|
||||
|
||||
dotPrefixes = dotPathPrefixes()
|
||||
dotSeparators = dotPathSeparators()
|
||||
)
|
||||
|
||||
func dotPathPrefixes() []string {
|
||||
if filepath.Separator == '\\' {
|
||||
return []string{"./", ".\\"}
|
||||
}
|
||||
return []string{"./"}
|
||||
}
|
||||
|
||||
func dotPathSeparators() string {
|
||||
if filepath.Separator == '\\' {
|
||||
return `/\`
|
||||
}
|
||||
return `/`
|
||||
}
|
||||
|
||||
// BoundOS is a fs implementation based on the OS filesystem which is bound to
|
||||
// a base dir.
|
||||
// Prefer this fs implementation over ChrootOS.
|
||||
@ -54,6 +80,7 @@ func (fs *BoundOS) Create(filename string) (billy.File, error) {
|
||||
}
|
||||
|
||||
func (fs *BoundOS) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) {
|
||||
filename = fs.expandDot(filename)
|
||||
fn, err := fs.abs(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -62,6 +89,7 @@ func (fs *BoundOS) OpenFile(filename string, flag int, perm os.FileMode) (billy.
|
||||
}
|
||||
|
||||
func (fs *BoundOS) ReadDir(path string) ([]os.FileInfo, error) {
|
||||
path = fs.expandDot(path)
|
||||
dir, err := fs.abs(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -71,6 +99,12 @@ func (fs *BoundOS) ReadDir(path string) ([]os.FileInfo, error) {
|
||||
}
|
||||
|
||||
func (fs *BoundOS) Rename(from, to string) error {
|
||||
if fs.isBaseDir(from) {
|
||||
return ErrBaseDirCannotBeRenamed
|
||||
}
|
||||
from = fs.expandDot(from)
|
||||
to = fs.expandDot(to)
|
||||
|
||||
f, err := fs.abs(from)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -89,6 +123,7 @@ func (fs *BoundOS) Rename(from, to string) error {
|
||||
}
|
||||
|
||||
func (fs *BoundOS) MkdirAll(path string, perm os.FileMode) error {
|
||||
path = fs.expandDot(path)
|
||||
dir, err := fs.abs(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -101,6 +136,7 @@ func (fs *BoundOS) Open(filename string) (billy.File, error) {
|
||||
}
|
||||
|
||||
func (fs *BoundOS) Stat(filename string) (os.FileInfo, error) {
|
||||
filename = fs.expandDot(filename)
|
||||
filename, err := fs.abs(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -109,6 +145,11 @@ func (fs *BoundOS) Stat(filename string) (os.FileInfo, error) {
|
||||
}
|
||||
|
||||
func (fs *BoundOS) Remove(filename string) error {
|
||||
if fs.isBaseDir(filename) {
|
||||
return ErrBaseDirCannotBeRemoved
|
||||
}
|
||||
filename = fs.expandDot(filename)
|
||||
|
||||
fn, err := fs.abs(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -122,6 +163,7 @@ func (fs *BoundOS) Remove(filename string) error {
|
||||
func (fs *BoundOS) TempFile(dir, prefix string) (billy.File, error) {
|
||||
if dir != "" {
|
||||
var err error
|
||||
dir = fs.expandDot(dir)
|
||||
dir, err = fs.abs(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -144,6 +186,11 @@ func (fs *BoundOS) Join(elem ...string) string {
|
||||
}
|
||||
|
||||
func (fs *BoundOS) RemoveAll(path string) error {
|
||||
if fs.isBaseDir(path) {
|
||||
return ErrBaseDirCannotBeRemoved
|
||||
}
|
||||
path = fs.expandDot(path)
|
||||
|
||||
dir, err := fs.abs(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -152,6 +199,7 @@ func (fs *BoundOS) RemoveAll(path string) error {
|
||||
}
|
||||
|
||||
func (fs *BoundOS) Symlink(target, link string) error {
|
||||
link = fs.expandDot(link)
|
||||
ln, err := fs.abs(link)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -164,6 +212,7 @@ func (fs *BoundOS) Symlink(target, link string) error {
|
||||
}
|
||||
|
||||
func (fs *BoundOS) Lstat(filename string) (os.FileInfo, error) {
|
||||
filename = fs.expandDot(filename)
|
||||
filename = filepath.Clean(filename)
|
||||
if !filepath.IsAbs(filename) {
|
||||
filename = filepath.Join(fs.baseDir, filename)
|
||||
@ -175,6 +224,7 @@ func (fs *BoundOS) Lstat(filename string) (os.FileInfo, error) {
|
||||
}
|
||||
|
||||
func (fs *BoundOS) Readlink(link string) (string, error) {
|
||||
link = fs.expandDot(link)
|
||||
if !filepath.IsAbs(link) {
|
||||
link = filepath.Clean(filepath.Join(fs.baseDir, link))
|
||||
}
|
||||
@ -185,6 +235,7 @@ func (fs *BoundOS) Readlink(link string) (string, error) {
|
||||
}
|
||||
|
||||
func (fs *BoundOS) Chmod(path string, mode os.FileMode) error {
|
||||
path = fs.expandDot(path)
|
||||
abspath, err := fs.abs(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -199,7 +250,7 @@ func (fs *BoundOS) Chroot(path string) (billy.Filesystem, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return New(joined), nil
|
||||
return New(joined, WithBoundOS()), nil
|
||||
}
|
||||
|
||||
// Root returns the current base dir of the billy.Filesystem.
|
||||
@ -220,6 +271,37 @@ func (fs *BoundOS) createDir(fullpath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *BoundOS) expandDot(path string) string {
|
||||
if path == "." {
|
||||
return fs.baseDir
|
||||
}
|
||||
for _, prefix := range dotPrefixes {
|
||||
if strings.HasPrefix(path, prefix) {
|
||||
path = strings.TrimLeft(strings.TrimPrefix(path, prefix), dotSeparators)
|
||||
if path == "" {
|
||||
return fs.baseDir
|
||||
}
|
||||
return path
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (fs *BoundOS) isBaseDir(path string) bool {
|
||||
if path == "" || filepath.Clean(path) == "." {
|
||||
return true
|
||||
}
|
||||
path = fs.expandDot(path)
|
||||
if filepath.Clean(path) == filepath.Clean(fs.baseDir) {
|
||||
return true
|
||||
}
|
||||
abspath, err := fs.abs(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return filepath.Clean(abspath) == filepath.Clean(fs.baseDir)
|
||||
}
|
||||
|
||||
// abs transforms filename to an absolute path, taking into account the base dir.
|
||||
// Relative paths won't be allowed to ascend the base dir, so `../file` will become
|
||||
// `/working-dir/file`.
|
||||
@ -233,7 +315,7 @@ func (fs *BoundOS) abs(filename string) (string, error) {
|
||||
|
||||
path, err := securejoin.SecureJoin(fs.baseDir, filename)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
return "", err
|
||||
}
|
||||
|
||||
if fs.deduplicatePath {
|
||||
@ -246,24 +328,12 @@ func (fs *BoundOS) abs(filename string) (string, error) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// insideBaseDir checks whether filename is located within
|
||||
// the fs.baseDir.
|
||||
func (fs *BoundOS) insideBaseDir(filename string) (bool, error) {
|
||||
if filename == fs.baseDir {
|
||||
return true, nil
|
||||
}
|
||||
if !strings.HasPrefix(filename, fs.baseDir+string(filepath.Separator)) {
|
||||
return false, fmt.Errorf("path outside base dir")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// insideBaseDirEval checks whether filename is contained within
|
||||
// a dir that is within the fs.baseDir, by first evaluating any symlinks
|
||||
// that either filename or fs.baseDir may contain.
|
||||
func (fs *BoundOS) insideBaseDirEval(filename string) (bool, error) {
|
||||
// "/" contains all others.
|
||||
if fs.baseDir == "/" {
|
||||
if fs.baseDir == "/" || fs.baseDir == filename {
|
||||
return true, nil
|
||||
}
|
||||
dir, err := filepath.EvalSymlinks(filepath.Dir(filename))
|
||||
|
||||
10
vendor/github.com/go-git/go-billy/v5/osfs/os_chroot.go
generated
vendored
10
vendor/github.com/go-git/go-billy/v5/osfs/os_chroot.go
generated
vendored
@ -14,6 +14,8 @@ import (
|
||||
// ChrootOS is a legacy filesystem based on a "soft chroot" of the os filesystem.
|
||||
// Although this is still the default os filesystem, consider using BoundOS instead.
|
||||
//
|
||||
// Deprecated: use New with WithBoundOS instead.
|
||||
//
|
||||
// Behaviours of note:
|
||||
// 1. A "soft chroot" translates the base dir to "/" for the purposes of the
|
||||
// fs abstraction.
|
||||
@ -24,6 +26,14 @@ import (
|
||||
type ChrootOS struct{}
|
||||
|
||||
func newChrootOS(baseDir string) billy.Filesystem {
|
||||
if baseDir != "" {
|
||||
resolved, err := filepath.EvalSymlinks(baseDir)
|
||||
if err != nil {
|
||||
return chroot.New(&ChrootOS{}, baseDir)
|
||||
}
|
||||
baseDir = resolved
|
||||
}
|
||||
|
||||
return chroot.New(&ChrootOS{}, baseDir)
|
||||
}
|
||||
|
||||
|
||||
43
vendor/github.com/go-git/go-billy/v5/util/util.go
generated
vendored
43
vendor/github.com/go-git/go-billy/v5/util/util.go
generated
vendored
@ -16,8 +16,6 @@ import (
|
||||
// can but returns the first error it encounters. If the path does not exist,
|
||||
// RemoveAll returns nil (no error).
|
||||
func RemoveAll(fs billy.Basic, path string) error {
|
||||
fs, path = getUnderlyingAndPath(fs, path)
|
||||
|
||||
if r, ok := fs.(removerAll); ok {
|
||||
return r.RemoveAll(path)
|
||||
}
|
||||
@ -39,7 +37,7 @@ func removeAll(fs billy.Basic, path string) error {
|
||||
}
|
||||
|
||||
// Otherwise, is this a directory we need to recurse into?
|
||||
dir, serr := fs.Stat(path)
|
||||
dir, serr := lstat(fs, path)
|
||||
if serr != nil {
|
||||
if errors.Is(serr, os.ErrNotExist) {
|
||||
return nil
|
||||
@ -48,8 +46,8 @@ func removeAll(fs billy.Basic, path string) error {
|
||||
return serr
|
||||
}
|
||||
|
||||
if !dir.IsDir() {
|
||||
// Not a directory; return the error from Remove.
|
||||
if dir.Mode()&os.ModeSymlink != 0 || !dir.IsDir() {
|
||||
// Not a directory we should recurse into; return the error from Remove.
|
||||
return err
|
||||
}
|
||||
|
||||
@ -62,7 +60,7 @@ func removeAll(fs billy.Basic, path string) error {
|
||||
fis, err := dirfs.ReadDir(path)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// Race. It was deleted between the Lstat and Open.
|
||||
// Race. It was deleted between the Lstat and ReadDir.
|
||||
// Return nil per RemoveAll's docs.
|
||||
return nil
|
||||
}
|
||||
@ -91,7 +89,18 @@ func removeAll(fs billy.Basic, path string) error {
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func lstat(filesystem billy.Basic, path string) (os.FileInfo, error) {
|
||||
if sl, ok := filesystem.(billy.Symlink); ok {
|
||||
// Avoid following a symlink substituted after the initial Remove fails.
|
||||
fi, err := sl.Lstat(path)
|
||||
if err == nil || !errors.Is(err, billy.ErrNotSupported) {
|
||||
return fi, err
|
||||
}
|
||||
}
|
||||
|
||||
return filesystem.Stat(path)
|
||||
}
|
||||
|
||||
// WriteFile writes data to a file named by filename in the given filesystem.
|
||||
@ -123,8 +132,10 @@ func WriteFile(fs billy.Basic, filename string, data []byte, perm os.FileMode) (
|
||||
// We generate random temporary file names so that there's a good
|
||||
// chance the file doesn't exist yet - keeps the number of tries in
|
||||
// TempFile to a minimum.
|
||||
var rand uint32
|
||||
var randmu sync.Mutex
|
||||
var (
|
||||
rand uint32
|
||||
randmu sync.Mutex
|
||||
)
|
||||
|
||||
func reseed() uint32 {
|
||||
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
|
||||
@ -220,22 +231,6 @@ func getTempDir(fs billy.Basic) string {
|
||||
return ".tmp"
|
||||
}
|
||||
|
||||
type underlying interface {
|
||||
Underlying() billy.Basic
|
||||
}
|
||||
|
||||
func getUnderlyingAndPath(fs billy.Basic, path string) (billy.Basic, string) {
|
||||
u, ok := fs.(underlying)
|
||||
if !ok {
|
||||
return fs, path
|
||||
}
|
||||
if ch, ok := fs.(billy.Chroot); ok {
|
||||
path = fs.Join(ch.Root(), path)
|
||||
}
|
||||
|
||||
return u.Underlying(), path
|
||||
}
|
||||
|
||||
// ReadFile reads the named file and returns the contents from the given filesystem.
|
||||
// A successful call returns err == nil, not err == EOF.
|
||||
// Because ReadFile reads the whole file, it does not treat an EOF from Read
|
||||
|
||||
31
vendor/github.com/go-git/go-git/v5/config/config.go
generated
vendored
31
vendor/github.com/go-git/go-git/v5/config/config.go
generated
vendored
@ -61,6 +61,16 @@ type Config struct {
|
||||
CommentChar string
|
||||
// RepositoryFormatVersion identifies the repository format and layout version.
|
||||
RepositoryFormatVersion format.RepositoryFormatVersion
|
||||
// ProtectNTFS controls whether NTFS-specific path protections are
|
||||
// applied (e.g. rejecting .git trailing spaces/periods, alternate
|
||||
// data streams, 8.3 short names). When unset, defaults to true on
|
||||
// Windows.
|
||||
ProtectNTFS OptBool
|
||||
// ProtectHFS controls whether HFS+-specific path protections are
|
||||
// applied (e.g. rejecting .git with Unicode zero-width or
|
||||
// directional characters that HFS+ would normalize away).
|
||||
// When unset, defaults to true on macOS.
|
||||
ProtectHFS OptBool
|
||||
}
|
||||
|
||||
User struct {
|
||||
@ -266,6 +276,8 @@ const (
|
||||
repositoryFormatVersionKey = "repositoryformatversion"
|
||||
objectFormat = "objectformat"
|
||||
mirrorKey = "mirror"
|
||||
protectNTFSKey = "protectNTFS"
|
||||
protectHFSKey = "protectHFS"
|
||||
|
||||
// DefaultPackWindow holds the number of previous objects used to
|
||||
// generate deltas. The value 10 is the same used by git command.
|
||||
@ -309,6 +321,14 @@ func (c *Config) unmarshalCore() {
|
||||
|
||||
c.Core.Worktree = s.Options.Get(worktreeKey)
|
||||
c.Core.CommentChar = s.Options.Get(commentCharKey)
|
||||
|
||||
if parsed := parseConfigBool(s.Options.Get(protectNTFSKey)); parsed.IsSet() {
|
||||
c.Core.ProtectNTFS = parsed
|
||||
}
|
||||
|
||||
if parsed := parseConfigBool(s.Options.Get(protectHFSKey)); parsed.IsSet() {
|
||||
c.Core.ProtectHFS = parsed
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) unmarshalUser() {
|
||||
@ -379,7 +399,8 @@ func unmarshalSubmodules(fc *format.Config, submodules map[string]*Submodule) {
|
||||
m := &Submodule{}
|
||||
m.unmarshal(sub)
|
||||
|
||||
if m.Validate() == ErrModuleBadPath {
|
||||
if err := m.Validate(); errors.Is(err, ErrModuleBadPath) ||
|
||||
errors.Is(err, ErrModuleBadName) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -436,6 +457,14 @@ func (c *Config) marshalCore() {
|
||||
if c.Core.Worktree != "" {
|
||||
s.SetOption(worktreeKey, c.Core.Worktree)
|
||||
}
|
||||
|
||||
if c.Core.ProtectNTFS.IsSet() {
|
||||
s.SetOption(protectNTFSKey, c.Core.ProtectNTFS.FormatBool())
|
||||
}
|
||||
|
||||
if c.Core.ProtectHFS.IsSet() {
|
||||
s.SetOption(protectHFSKey, c.Core.ProtectHFS.FormatBool())
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) marshalExtensions() {
|
||||
|
||||
52
vendor/github.com/go-git/go-git/v5/config/modules.go
generated
vendored
52
vendor/github.com/go-git/go-git/v5/config/modules.go
generated
vendored
@ -3,8 +3,11 @@ package config
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5/internal/pathutil"
|
||||
format "github.com/go-git/go-git/v5/plumbing/format/config"
|
||||
)
|
||||
|
||||
@ -12,6 +15,7 @@ var (
|
||||
ErrModuleEmptyURL = errors.New("module config: empty URL")
|
||||
ErrModuleEmptyPath = errors.New("module config: empty path")
|
||||
ErrModuleBadPath = errors.New("submodule has an invalid path")
|
||||
ErrModuleBadName = errors.New("ignoring suspicious submodule name")
|
||||
)
|
||||
|
||||
var (
|
||||
@ -94,6 +98,10 @@ type Submodule struct {
|
||||
|
||||
// Validate validates the fields and sets the default values.
|
||||
func (m *Submodule) Validate() error {
|
||||
if err := validSubmoduleName(m.Name); err != nil {
|
||||
return fmt.Errorf("%w: %q", ErrModuleBadName, m.Name)
|
||||
}
|
||||
|
||||
if m.Path == "" {
|
||||
return ErrModuleEmptyPath
|
||||
}
|
||||
@ -109,6 +117,50 @@ func (m *Submodule) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validSubmoduleName mirrors canonical Git's check_submodule_name in
|
||||
// submodule-config.c [1]: reject empty names and any name with a ".."
|
||||
// path component, using both '/' and '\\' as separators so the rule
|
||||
// is consistent across platforms. The component check is delegated to
|
||||
// `pathutil.IsHFSDot` and `pathutil.IsNTFSDot` with `.` as the needle,
|
||||
// which both cover the bare ".." case and reject components that
|
||||
// resolve to ".." after HFS+ Unicode normalisation (ignored code
|
||||
// points, e.g. `.<U+200C>.`) or NTFS trailing-space/dot/ADS
|
||||
// canonicalisation (e.g. `.. `, `..::$INDEX_ALLOCATION`).
|
||||
// `.gitmodules` is attacker-controlled by definition, so both checks
|
||||
// run unconditionally regardless of host OS.
|
||||
//
|
||||
// The additional checks (bare ".", NUL byte, leading or trailing
|
||||
// separator, drive-letter prefix) close go-git-specific edge cases
|
||||
// the canonical loop does not exercise: canonical Git treats names
|
||||
// as opaque C strings, while Go strings carry NULs through and the
|
||||
// billy filesystem layer is path-aware in ways Git's working storage
|
||||
// is not.
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/submodule-config.c#L214-L237
|
||||
func validSubmoduleName(name string) error {
|
||||
if name == "" || name == "." {
|
||||
return ErrModuleBadName
|
||||
}
|
||||
for _, seg := range strings.FieldsFunc(name, isPathSep) {
|
||||
if pathutil.IsHFSDot(seg, ".") || pathutil.IsNTFSDot(seg, ".", "") {
|
||||
return ErrModuleBadName
|
||||
}
|
||||
}
|
||||
// go-git-specific defensive checks beyond canonical Git.
|
||||
if strings.ContainsRune(name, 0) {
|
||||
return ErrModuleBadName
|
||||
}
|
||||
if isPathSep(rune(name[0])) || isPathSep(rune(name[len(name)-1])) {
|
||||
return ErrModuleBadName
|
||||
}
|
||||
if len(name) >= 2 && name[1] == ':' {
|
||||
return ErrModuleBadName
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isPathSep(r rune) bool { return r == '/' || r == '\\' }
|
||||
|
||||
func (m *Submodule) unmarshal(s *format.Subsection) {
|
||||
m.raw = s
|
||||
|
||||
|
||||
82
vendor/github.com/go-git/go-git/v5/config/optbool.go
generated
vendored
Normal file
82
vendor/github.com/go-git/go-git/v5/config/optbool.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// OptBool is a tri-state boolean: unset, explicitly false, or explicitly true.
|
||||
// Its zero value (OptBoolUnset) means the setting was not specified, which
|
||||
// allows merge logic based on reflect.Value.IsZero to skip unset fields while
|
||||
// still letting an explicit "false" override a previously set "true".
|
||||
type OptBool byte
|
||||
|
||||
const (
|
||||
// OptBoolUnset indicates the setting was not specified.
|
||||
OptBoolUnset OptBool = iota
|
||||
// OptBoolFalse indicates the setting was explicitly set to false.
|
||||
OptBoolFalse
|
||||
// OptBoolTrue indicates the setting was explicitly set to true.
|
||||
OptBoolTrue
|
||||
)
|
||||
|
||||
// NewOptBool converts a plain bool into an OptBool.
|
||||
func NewOptBool(v bool) OptBool {
|
||||
if v {
|
||||
return OptBoolTrue
|
||||
}
|
||||
return OptBoolFalse
|
||||
}
|
||||
|
||||
// IsTrue returns whether the value is explicitly true.
|
||||
func (o OptBool) IsTrue() bool { return o == OptBoolTrue }
|
||||
|
||||
// IsSet returns whether the value was explicitly specified (true or false).
|
||||
func (o OptBool) IsSet() bool { return o != OptBoolUnset }
|
||||
|
||||
func (o OptBool) String() string {
|
||||
switch o {
|
||||
case OptBoolTrue:
|
||||
return "true"
|
||||
case OptBoolFalse:
|
||||
return "false"
|
||||
default:
|
||||
return "unset"
|
||||
}
|
||||
}
|
||||
|
||||
// FormatBool returns the strconv-formatted value. Only meaningful when IsSet.
|
||||
func (o OptBool) FormatBool() string {
|
||||
return strconv.FormatBool(o.IsTrue())
|
||||
}
|
||||
|
||||
// parseConfigBool mirrors upstream Git's git_parse_maybe_bool: it
|
||||
// accepts true/yes/on (→ OptBoolTrue) and false/no/off (→
|
||||
// OptBoolFalse) case-insensitively, plus any decimal integer (zero
|
||||
// → OptBoolFalse, non-zero → OptBoolTrue). Empty or otherwise
|
||||
// unrecognised values return OptBoolUnset, leaving the caller's
|
||||
// platform default in place. The empty-string handling is the only
|
||||
// intentional divergence from upstream, which returns false for
|
||||
// empty: in our unmarshalCore caller, an empty value means the key
|
||||
// is unset and the platform default should apply.
|
||||
//
|
||||
// Reference: upstream Git git_parse_maybe_bool_text at parse.c
|
||||
// L157-L173 and git_parse_maybe_bool at parse.c L174-L182 in tag
|
||||
// v2.54.0[1].
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/parse.c#L157-L182
|
||||
func parseConfigBool(v string) OptBool {
|
||||
switch strings.ToLower(v) {
|
||||
case "true", "yes", "on":
|
||||
return OptBoolTrue
|
||||
case "false", "no", "off":
|
||||
return OptBoolFalse
|
||||
}
|
||||
if i, err := strconv.Atoi(v); err == nil {
|
||||
if i != 0 {
|
||||
return OptBoolTrue
|
||||
}
|
||||
return OptBoolFalse
|
||||
}
|
||||
return OptBoolUnset
|
||||
}
|
||||
21
vendor/github.com/go-git/go-git/v5/internal/pathutil/dotgit.go
generated
vendored
Normal file
21
vendor/github.com/go-git/go-git/v5/internal/pathutil/dotgit.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
package pathutil
|
||||
|
||||
import "strings"
|
||||
|
||||
// IsDotGitName reports whether name is `.git` or its 8.3 NTFS short
|
||||
// alias `git~1`, case-insensitively. Both are forbidden as path
|
||||
// components (and as submodule names) because they refer to the
|
||||
// repository's own metadata directory.
|
||||
//
|
||||
// File names that do not conform to the 8.3 format (up to eight
|
||||
// characters for the basename, three for the file extension) are
|
||||
// associated with a so-called "short name" on NTFS — at least on
|
||||
// the `C:` drive by default — which means that `git~1/` is a valid
|
||||
// way to refer to `.git/`.
|
||||
func IsDotGitName(name string) bool {
|
||||
switch strings.ToLower(name) {
|
||||
case ".git", "git~1":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
99
vendor/github.com/go-git/go-git/v5/internal/pathutil/hfs.go
generated
vendored
Normal file
99
vendor/github.com/go-git/go-git/v5/internal/pathutil/hfs.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
package pathutil
|
||||
|
||||
import "unicode"
|
||||
|
||||
// hfsIgnoredCodepoints contains Unicode code points that HFS+ ignores
|
||||
// during path normalization. A path component containing these
|
||||
// characters between the bytes of ".git" (or ".gitmodules", etc.)
|
||||
// will be treated as that name by HFS+, so they have to be filtered
|
||||
// out before comparison.
|
||||
//
|
||||
// See upstream Git utf8.c next_hfs_char in tag v2.54.0[1].
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/utf8.c#L703-L740
|
||||
var hfsIgnoredCodepoints = map[rune]struct{}{
|
||||
0x200c: {}, // ZERO WIDTH NON-JOINER
|
||||
0x200d: {}, // ZERO WIDTH JOINER
|
||||
0x200e: {}, // LEFT-TO-RIGHT MARK
|
||||
0x200f: {}, // RIGHT-TO-LEFT MARK
|
||||
0x202a: {}, // LEFT-TO-RIGHT EMBEDDING
|
||||
0x202b: {}, // RIGHT-TO-LEFT EMBEDDING
|
||||
0x202c: {}, // POP DIRECTIONAL FORMATTING
|
||||
0x202d: {}, // LEFT-TO-RIGHT OVERRIDE
|
||||
0x202e: {}, // RIGHT-TO-LEFT OVERRIDE
|
||||
0x206a: {}, // INHIBIT SYMMETRIC SWAPPING
|
||||
0x206b: {}, // ACTIVATE SYMMETRIC SWAPPING
|
||||
0x206c: {}, // INHIBIT ARABIC FORM SHAPING
|
||||
0x206d: {}, // ACTIVATE ARABIC FORM SHAPING
|
||||
0x206e: {}, // NATIONAL DIGIT SHAPES
|
||||
0x206f: {}, // NOMINAL DIGIT SHAPES
|
||||
0xfeff: {}, // ZERO WIDTH NO-BREAK SPACE
|
||||
}
|
||||
|
||||
// IsHFSDot reports whether part would be treated as ".<needle>" on an
|
||||
// HFS+ filesystem after stripping ignored Unicode code points and
|
||||
// folding ASCII to lower case. The needle is the lowercase ASCII
|
||||
// suffix without the leading dot (e.g. "git", "gitmodules"). It
|
||||
// mirrors upstream Git's is_hfs_dot_generic and is the building
|
||||
// block of IsHFSDotGit / IsHFSDotGitmodules.
|
||||
//
|
||||
// Reference: upstream Git utf8.c is_hfs_dot_generic at L741-L774 and
|
||||
// the dotgit family at L784-L809 in tag v2.54.0[1].
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/utf8.c#L741-L809
|
||||
func IsHFSDot(part, needle string) bool {
|
||||
runes := []rune(part)
|
||||
i := 0
|
||||
|
||||
// skip ignored code points, then expect '.'
|
||||
for i < len(runes) {
|
||||
if _, ok := hfsIgnoredCodepoints[runes[i]]; !ok {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
if i >= len(runes) || runes[i] != '.' {
|
||||
return false
|
||||
}
|
||||
i++
|
||||
|
||||
// match needle case-insensitively, skipping ignored code points
|
||||
for _, expected := range needle {
|
||||
for i < len(runes) {
|
||||
if _, ok := hfsIgnoredCodepoints[runes[i]]; !ok {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
if i >= len(runes) {
|
||||
return false
|
||||
}
|
||||
r := runes[i]
|
||||
if r > 127 {
|
||||
return false
|
||||
}
|
||||
if unicode.ToLower(r) != expected {
|
||||
return false
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
// skip trailing ignored code points
|
||||
for i < len(runes) {
|
||||
if _, ok := hfsIgnoredCodepoints[runes[i]]; !ok {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
// must be at end of component
|
||||
return i == len(runes)
|
||||
}
|
||||
|
||||
// IsHFSDotGit reports whether part is an HFS+ equivalent of ".git".
|
||||
func IsHFSDotGit(part string) bool { return IsHFSDot(part, "git") }
|
||||
|
||||
// IsHFSDotGitmodules reports whether part is an HFS+ equivalent of
|
||||
// ".gitmodules", catching attempts to plant the file via Unicode
|
||||
// code points that HFS+ would strip during normalisation.
|
||||
func IsHFSDotGitmodules(part string) bool { return IsHFSDot(part, "gitmodules") }
|
||||
187
vendor/github.com/go-git/go-git/v5/internal/pathutil/ntfs.go
generated
vendored
Normal file
187
vendor/github.com/go-git/go-git/v5/internal/pathutil/ntfs.go
generated
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
package pathutil
|
||||
|
||||
import "strings"
|
||||
|
||||
// IsNTFSDotGit ports upstream Git's is_ntfs_dotgit. It detects path
|
||||
// components that NTFS would resolve to ".git": the canonical name
|
||||
// itself and its 8.3 short-name alias "git~1", each followed by any
|
||||
// number of trailing spaces or periods (which NTFS silently trims)
|
||||
// and an optional Alternate Data Stream suffix (":<stream>"). The
|
||||
// bare strings ".git" and "git~1" also match, mirroring upstream.
|
||||
//
|
||||
// Reference: upstream Git path.c is_ntfs_dotgit at L1415-L1449
|
||||
// in tag v2.54.0[1].
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/path.c#L1415-L1449
|
||||
func IsNTFSDotGit(part string) bool {
|
||||
var i int
|
||||
switch {
|
||||
case len(part) >= 4 && part[0] == '.' &&
|
||||
asciiToLower(part[1]) == 'g' &&
|
||||
asciiToLower(part[2]) == 'i' &&
|
||||
asciiToLower(part[3]) == 't':
|
||||
i = 4
|
||||
case len(part) >= 5 &&
|
||||
asciiToLower(part[0]) == 'g' &&
|
||||
asciiToLower(part[1]) == 'i' &&
|
||||
asciiToLower(part[2]) == 't' &&
|
||||
part[3] == '~' && part[4] == '1':
|
||||
i = 5
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
for ; i < len(part); i++ {
|
||||
c := part[i]
|
||||
if c == ':' {
|
||||
return true
|
||||
}
|
||||
if c != '.' && c != ' ' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// WindowsValidPath reports whether part is a valid Windows / NTFS
|
||||
// path component for the worktree filesystem abstraction. It rejects
|
||||
// NTFS-disguised variants of `.git` and `git~1` (trailing spaces,
|
||||
// periods, Alternate Data Streams) and Windows reserved device
|
||||
// names. Bare `.git` and `git~1` are allowed at this layer; the
|
||||
// caller decides whether they are permissible at the current path
|
||||
// position.
|
||||
func WindowsValidPath(part string) bool {
|
||||
if IsNTFSDotGit(part) && !IsDotGitName(part) {
|
||||
return false
|
||||
}
|
||||
return !isWindowsReservedName(part)
|
||||
}
|
||||
|
||||
// windowsReservedNames lists the Windows reserved device names.
|
||||
// A path component is reserved if its base name (ignoring trailing
|
||||
// spaces, extensions, and NTFS Alternate Data Streams) matches one of
|
||||
// these case-insensitively.
|
||||
//
|
||||
// See upstream Git compat/mingw.c is_valid_win32_path().
|
||||
var windowsReservedNames = []string{
|
||||
"CON", "PRN", "AUX", "NUL",
|
||||
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
|
||||
"CONIN$", "CONOUT$",
|
||||
}
|
||||
|
||||
func isWindowsReservedName(part string) bool {
|
||||
for _, name := range windowsReservedNames {
|
||||
if len(part) < len(name) {
|
||||
continue
|
||||
}
|
||||
if !strings.EqualFold(part[:len(name)], name) {
|
||||
continue
|
||||
}
|
||||
// Exact match or followed by space, dot, colon (ADS), or separator.
|
||||
if len(part) == len(name) {
|
||||
return true
|
||||
}
|
||||
switch part[len(name)] {
|
||||
case ' ', '.', ':':
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsNTFSDot ports upstream Git's is_ntfs_dot_generic. It detects NTFS
|
||||
// path-component variants of a dotfile name that attackers can use to
|
||||
// bypass case-insensitive comparisons against the canonical name on
|
||||
// Windows. The dotgit parameter is the lowercase name without the
|
||||
// leading dot (e.g. "gitmodules"); shortnamePrefix is the canonical
|
||||
// 6-character NTFS short-name prefix used as a fall-back match
|
||||
// (e.g. "gi7eba" for ".gitmodules").
|
||||
//
|
||||
// Reference: upstream Git path.c is_ntfs_dot_generic at L1451-L1507
|
||||
// in tag v2.54.0[1].
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/path.c#L1451-L1507
|
||||
func IsNTFSDot(name, dotgit, shortnamePrefix string) bool {
|
||||
// onlySpacesAndPeriods returns true when the suffix from start
|
||||
// onwards consists only of trailing spaces and periods, possibly
|
||||
// terminated by a NTFS Alternate Data Stream colon. Mirrors the
|
||||
// only_spaces_and_periods label in upstream's is_ntfs_dot_generic.
|
||||
onlySpacesAndPeriods := func(start int) bool {
|
||||
for i := start; i < len(name); i++ {
|
||||
c := name[i]
|
||||
if c == ':' {
|
||||
return true
|
||||
}
|
||||
if c != ' ' && c != '.' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Pattern 1: ".<dotgit>" prefix + trailing spaces / periods / ADS.
|
||||
if len(name) >= len(dotgit)+1 && name[0] == '.' &&
|
||||
strings.EqualFold(name[1:1+len(dotgit)], dotgit) {
|
||||
if onlySpacesAndPeriods(len(dotgit) + 1) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Pattern 2: standard NTFS short name <dotgit[:6]>~[1-4].
|
||||
if len(dotgit) >= 6 && len(name) >= 8 &&
|
||||
strings.EqualFold(name[:6], dotgit[:6]) &&
|
||||
name[6] == '~' && name[7] >= '1' && name[7] <= '4' {
|
||||
if onlySpacesAndPeriods(8) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Pattern 3: fall-back NTFS short name keyed by shortnamePrefix.
|
||||
if len(shortnamePrefix) < 6 || len(name) < 8 {
|
||||
return false
|
||||
}
|
||||
sawTilde := false
|
||||
i := 0
|
||||
for i < 8 {
|
||||
c := name[i]
|
||||
switch {
|
||||
case sawTilde:
|
||||
if c < '0' || c > '9' {
|
||||
return false
|
||||
}
|
||||
case c == '~':
|
||||
i++
|
||||
if i >= len(name) || name[i] < '1' || name[i] > '9' {
|
||||
return false
|
||||
}
|
||||
sawTilde = true
|
||||
case i >= 6:
|
||||
return false
|
||||
case c&0x80 != 0:
|
||||
return false
|
||||
default:
|
||||
if asciiToLower(c) != shortnamePrefix[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
return onlySpacesAndPeriods(8)
|
||||
}
|
||||
|
||||
// IsNTFSDotGitmodules reports whether part is an NTFS-equivalent of
|
||||
// ".gitmodules" — the file name (or any of its variants that NTFS
|
||||
// would resolve to it) that attackers can use to plant submodule
|
||||
// configuration disguised as a symlink. The 6-character canonical
|
||||
// short-name prefix "gi7eba" mirrors upstream Git's is_ntfs_dotgitmodules.
|
||||
func IsNTFSDotGitmodules(part string) bool {
|
||||
return IsNTFSDot(part, "gitmodules", "gi7eba")
|
||||
}
|
||||
|
||||
func asciiToLower(c byte) byte {
|
||||
if c >= 'A' && c <= 'Z' {
|
||||
return c + ('a' - 'A')
|
||||
}
|
||||
return c
|
||||
}
|
||||
66
vendor/github.com/go-git/go-git/v5/internal/pathutil/tree.go
generated
vendored
Normal file
66
vendor/github.com/go-git/go-git/v5/internal/pathutil/tree.go
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
package pathutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrInvalidPath is returned by ValidTreePath when its argument is
|
||||
// not a safe path to materialise into the worktree.
|
||||
var ErrInvalidPath = fmt.Errorf("invalid path")
|
||||
|
||||
// ValidTreePath rejects path strings that, if materialised into a
|
||||
// worktree, would let an attacker-controlled tree entry escape the
|
||||
// worktree or rewrite repository metadata. It rejects:
|
||||
//
|
||||
// - control characters (< 0x20, 0x7f);
|
||||
// - empty paths and "." / ".." components;
|
||||
// - Windows volume name prefixes (e.g. C:);
|
||||
// - .git, its 8.3 NTFS short-name git~1, plus their HFS+ and NTFS
|
||||
// variants — at every position, not just the root.
|
||||
//
|
||||
// HFS+/NTFS variants of `.git` are always rejected at this layer
|
||||
// regardless of runtime config: tree paths are canonical UTF-8 with
|
||||
// no zero-width characters or NTFS short-name forms, so an entry
|
||||
// that looks like a disguised `.git` is suspicious anywhere. Windows
|
||||
// reserved device names (CON, NUL, etc.) are not policed here — they
|
||||
// are legitimate filenames on non-Windows filesystems and upstream
|
||||
// Git accepts them. The wrapper layer (validPath in package git)
|
||||
// rejects them at materialisation time when core.protectNTFS is on.
|
||||
//
|
||||
// Mirrors upstream Git's verify_path_internal at read-cache.c#L987
|
||||
// in tag v2.54.0[1] with protect_hfs / protect_ntfs treated as
|
||||
// always-on for `.git`-disguise detection (tree paths are not
|
||||
// application-supplied) and is_valid_win32_path left to the wrapper.
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/read-cache.c#L987
|
||||
func ValidTreePath(p string) error {
|
||||
for i := 0; i < len(p); i++ {
|
||||
if p[i] < 0x20 || p[i] == 0x7f {
|
||||
return fmt.Errorf("%w %q: contains control character", ErrInvalidPath, p)
|
||||
}
|
||||
}
|
||||
|
||||
parts := strings.FieldsFunc(p, func(r rune) bool { return r == '\\' || r == '/' })
|
||||
if len(parts) == 0 {
|
||||
return fmt.Errorf("%w: %q", ErrInvalidPath, p)
|
||||
}
|
||||
|
||||
// Volume names are not supported, in both formats: \\ and <DRIVE_LETTER>:.
|
||||
if vol := filepath.VolumeName(p); vol != "" {
|
||||
return fmt.Errorf("%w: %q", ErrInvalidPath, p)
|
||||
}
|
||||
|
||||
for _, part := range parts {
|
||||
if part == "." || part == ".." {
|
||||
return fmt.Errorf("%w %q: cannot use %q", ErrInvalidPath, p, part)
|
||||
}
|
||||
|
||||
if IsDotGitName(part) || IsHFSDotGit(part) || IsNTFSDotGit(part) {
|
||||
return fmt.Errorf("%w component: %q", ErrInvalidPath, p)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
37
vendor/github.com/go-git/go-git/v5/internal/url/url.go
generated
vendored
37
vendor/github.com/go-git/go-git/v5/internal/url/url.go
generated
vendored
@ -2,12 +2,14 @@ package url
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
isSchemeRegExp = regexp.MustCompile(`^[^:]+://`)
|
||||
|
||||
// Ref: https://github.com/git/git/blob/master/Documentation/urls.txt#L37
|
||||
// Ref: https://github.com/git/git/blob/v2.54.0/Documentation/urls.adoc#L41-L48
|
||||
scpLikeUrlRegExp = regexp.MustCompile(`^(?:(?P<user>[^@]+)@)?(?P<host>[^:\s]+):(?:(?P<port>[0-9]{1,5}):)?(?P<path>[^\\].*)$`)
|
||||
)
|
||||
|
||||
@ -20,7 +22,38 @@ func MatchesScheme(url string) bool {
|
||||
// MatchesScpLike returns true if the given string matches an SCP-like
|
||||
// format scheme.
|
||||
func MatchesScpLike(url string) bool {
|
||||
return scpLikeUrlRegExp.MatchString(url)
|
||||
if !scpLikeUrlRegExp.MatchString(url) {
|
||||
return false
|
||||
}
|
||||
// Mirror canonical Git's url_is_local_not_ssh in connect.c[1] for
|
||||
// the cases the regex above cannot disambiguate by itself: a URL
|
||||
// is treated as a local path (not SCP-style SSH) when a `/`
|
||||
// precedes the first `:` (e.g. `./relative:path`,
|
||||
// `/abs/with:colon/file`), or — on Windows only — when it has a
|
||||
// DOS drive prefix like `C:foo` where the host is a single
|
||||
// ASCII letter.
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/connect.c#L710-L716
|
||||
if before, _, _ := strings.Cut(url, ":"); strings.Contains(before, "/") {
|
||||
return false
|
||||
}
|
||||
if runtime.GOOS == "windows" && hasDosDrivePrefix(url) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// hasDosDrivePrefix reports whether s begins with `<letter>:` (a
|
||||
// Windows drive prefix such as `C:` or `c:`). Mirrors canonical Git's
|
||||
// win32_has_dos_drive_prefix[1].
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/compat/win32/path-utils.c#L20-L29
|
||||
func hasDosDrivePrefix(s string) bool {
|
||||
if len(s) < 2 || s[1] != ':' {
|
||||
return false
|
||||
}
|
||||
c := s[0]
|
||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')
|
||||
}
|
||||
|
||||
// FindScpLikeComponents returns the user, host, port and path of the
|
||||
|
||||
164
vendor/github.com/go-git/go-git/v5/plumbing/format/idxfile/decoder.go
generated
vendored
164
vendor/github.com/go-git/go-git/v5/plumbing/format/idxfile/decoder.go
generated
vendored
@ -7,6 +7,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing/hash"
|
||||
"github.com/go-git/go-git/v5/utils/binary"
|
||||
@ -25,35 +26,88 @@ const (
|
||||
objectIDLength = hash.Size
|
||||
)
|
||||
|
||||
// Byte sizes of the idx v2 layout elements, used by the size formula
|
||||
// in [validateIdxV2Size]. See [gitformat-pack] for the canonical
|
||||
// layout.
|
||||
//
|
||||
// [gitformat-pack]: https://git-scm.com/docs/gitformat-pack
|
||||
const (
|
||||
headerLen = 8 // magic + version
|
||||
fanoutLen = fanout * 4 // uint32 per bucket
|
||||
crc32Len = 4 // CRC32 per object
|
||||
offset32Len = 4 // 32-bit offset per object
|
||||
offset64Len = 8 // 64-bit overflow offset
|
||||
trailerHashes = 2 // pack checksum + idx checksum, each hashsz
|
||||
)
|
||||
|
||||
// statInput is the optional shape the [Decoder] probes for at the
|
||||
// start of [Decoder.Decode] to learn the on-disk length of the idx
|
||||
// blob, which it uses to validate the canonical-Git size formula
|
||||
// before any allocations driven by the fanout table. Callers that
|
||||
// pass an [*os.File] or a `billy.File` backed by an `*os.File`
|
||||
// (the production call sites in `storage/filesystem`) satisfy it
|
||||
// directly; arbitrary [io.Reader]s do not, and decode for them
|
||||
// retains the pre-existing behaviour of erroring out at the
|
||||
// truncated-payload boundary instead.
|
||||
//
|
||||
// The interface is intentionally unexported so the public
|
||||
// [NewDecoder] signature stays compatible with v5.
|
||||
type statInput interface {
|
||||
Stat() (fs.FileInfo, error)
|
||||
}
|
||||
|
||||
// Decoder reads and decodes idx files from an input stream.
|
||||
type Decoder struct {
|
||||
io.Reader
|
||||
h hash.Hash
|
||||
src io.Reader
|
||||
h hash.Hash
|
||||
}
|
||||
|
||||
// NewDecoder builds a new idx stream decoder, that reads from r.
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
h := hash.New(crypto.SHA1)
|
||||
tr := io.TeeReader(r, h)
|
||||
return &Decoder{tr, h}
|
||||
return &Decoder{tr, r, h}
|
||||
}
|
||||
|
||||
// Decode reads from the stream and decode the content into the MemoryIndex struct.
|
||||
func (d *Decoder) Decode(idx *MemoryIndex) error {
|
||||
idxSize := int64(-1)
|
||||
if in, ok := d.src.(statInput); ok {
|
||||
fi, err := in.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: stat input: %w", ErrMalformedIdxFile, err)
|
||||
}
|
||||
idxSize = fi.Size()
|
||||
}
|
||||
|
||||
if err := validateHeader(d); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
flow := []func(*MemoryIndex, io.Reader) error{
|
||||
headerFlow := []func(*MemoryIndex, io.Reader) error{
|
||||
readVersion,
|
||||
readFanout,
|
||||
}
|
||||
for _, f := range headerFlow {
|
||||
if err := f(idx, d); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if idxSize >= 0 {
|
||||
if err := validateIdxV2Size(idx, idxSize); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
bodyFlow := []func(*MemoryIndex, io.Reader) error{
|
||||
readObjectNames,
|
||||
readCRC32,
|
||||
readOffsets,
|
||||
readPackChecksum,
|
||||
}
|
||||
|
||||
for _, f := range flow {
|
||||
for _, f := range bodyFlow {
|
||||
if err := f(idx, d); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -199,3 +253,103 @@ func readIdxChecksum(idx *MemoryIndex, r io.Reader) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateIdxV2Size enforces the size formula used by canonical Git
|
||||
// load_idx for idx v2 files: the on-disk length must lie within
|
||||
// [minSize, maxSize] where
|
||||
//
|
||||
// perObject = hashsz + crc32Len + offset32Len
|
||||
// minSize = headerLen + fanoutLen + trailerHashes*hashsz + nr*perObject
|
||||
// maxSize = minSize + (nr-1)*offset64Len when nr > 0
|
||||
//
|
||||
// with nr taken from the last fanout entry and hashsz fixed at
|
||||
// [objectIDLength] (SHA-1 in v5). Multiplications use a self-checking
|
||||
// overflow guard so inputs whose claimed object count overflows the
|
||||
// formula are rejected rather than wrapping into a smaller value.
|
||||
func validateIdxV2Size(idx *MemoryIndex, idxSize int64) error {
|
||||
nr := int64(idx.Fanout[fanout-1])
|
||||
hashsz := int64(objectIDLength)
|
||||
|
||||
minSize := minIdxV2Size(nr, hashsz)
|
||||
maxSize := maxIdxV2Size(nr, hashsz)
|
||||
if minSize < 0 || maxSize < 0 {
|
||||
return fmt.Errorf("%w: object count %d is inconsistent with file size", ErrMalformedIdxFile, nr)
|
||||
}
|
||||
|
||||
if idxSize < minSize || idxSize > maxSize {
|
||||
return fmt.Errorf("%w: file size %d is inconsistent with object count %d", ErrMalformedIdxFile, idxSize, nr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// minIdxV2Size returns the minimum on-disk size of an idx v2 file
|
||||
// holding nr objects with the given hash size, mirroring the
|
||||
// computation in canonical Git load_idx. Returns -1 when any
|
||||
// intermediate multiplication or addition would overflow int64.
|
||||
func minIdxV2Size(nr, hashsz int64) int64 {
|
||||
perObject := hashsz + crc32Len + offset32Len
|
||||
fixed := int64(headerLen+fanoutLen) + trailerHashes*hashsz
|
||||
|
||||
objects, ok := mulInt64(nr, perObject)
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
sum, ok := addInt64(fixed, objects)
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// maxIdxV2Size returns the maximum on-disk size of an idx v2 file
|
||||
// holding nr objects with the given hash size, mirroring the
|
||||
// computation in canonical Git load_idx. Returns -1 on overflow.
|
||||
func maxIdxV2Size(nr, hashsz int64) int64 {
|
||||
minSize := minIdxV2Size(nr, hashsz)
|
||||
if minSize < 0 {
|
||||
return -1
|
||||
}
|
||||
if nr == 0 {
|
||||
return minSize
|
||||
}
|
||||
overflow, ok := mulInt64(nr-1, offset64Len)
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
sum, ok := addInt64(minSize, overflow)
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// mulInt64 returns a*b and whether the result fits in an int64 without
|
||||
// overflow. Negative operands or overflow yield ok=false. The overflow
|
||||
// check uses the standard self-inverse identity: a*b/b == a only when
|
||||
// the multiplication did not wrap.
|
||||
func mulInt64(a, b int64) (int64, bool) {
|
||||
if a < 0 || b < 0 {
|
||||
return 0, false
|
||||
}
|
||||
if a == 0 || b == 0 {
|
||||
return 0, true
|
||||
}
|
||||
c := a * b
|
||||
if c/b != a {
|
||||
return 0, false
|
||||
}
|
||||
return c, true
|
||||
}
|
||||
|
||||
// addInt64 returns a+b and whether the result fits in an int64 without
|
||||
// overflow. Negative operands or overflow yield ok=false.
|
||||
func addInt64(a, b int64) (int64, bool) {
|
||||
if a < 0 || b < 0 {
|
||||
return 0, false
|
||||
}
|
||||
c := a + b
|
||||
if c < a {
|
||||
return 0, false
|
||||
}
|
||||
return c, true
|
||||
}
|
||||
|
||||
29
vendor/github.com/go-git/go-git/v5/plumbing/format/idxfile/idxfile.go
generated
vendored
29
vendor/github.com/go-git/go-git/v5/plumbing/format/idxfile/idxfile.go
generated
vendored
@ -2,6 +2,7 @@ package idxfile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"sync"
|
||||
@ -126,7 +127,10 @@ func (idx *MemoryIndex) FindOffset(h plumbing.Hash) (int64, error) {
|
||||
return 0, plumbing.ErrObjectNotFound
|
||||
}
|
||||
|
||||
offset := idx.getOffset(k, i)
|
||||
offset, err := idx.getOffset(k, i)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Save the offset for reverse lookup
|
||||
idx.mu.Lock()
|
||||
@ -141,17 +145,19 @@ func (idx *MemoryIndex) FindOffset(h plumbing.Hash) (int64, error) {
|
||||
|
||||
const isO64Mask = uint64(1) << 31
|
||||
|
||||
func (idx *MemoryIndex) getOffset(firstLevel, secondLevel int) uint64 {
|
||||
func (idx *MemoryIndex) getOffset(firstLevel, secondLevel int) (uint64, error) {
|
||||
offset := secondLevel << 2
|
||||
ofs := encbin.BigEndian.Uint32(idx.Offset32[firstLevel][offset : offset+4])
|
||||
|
||||
if (uint64(ofs) & isO64Mask) != 0 {
|
||||
offset := 8 * (uint64(ofs) & ^isO64Mask)
|
||||
n := encbin.BigEndian.Uint64(idx.Offset64[offset : offset+8])
|
||||
return n
|
||||
if l := uint64(len(idx.Offset64)); l < 8 || offset > l-8 {
|
||||
return 0, fmt.Errorf("%w: offset64 index out of range", ErrMalformedIdxFile)
|
||||
}
|
||||
return encbin.BigEndian.Uint64(idx.Offset64[offset : offset+8]), nil
|
||||
}
|
||||
|
||||
return uint64(ofs)
|
||||
return uint64(ofs), nil
|
||||
}
|
||||
|
||||
// FindCRC32 implements the Index interface.
|
||||
@ -209,8 +215,11 @@ func (idx *MemoryIndex) genOffsetHash() error {
|
||||
mappedFirstLevel := idx.FanoutMapping[firstLevel]
|
||||
for secondLevel := uint32(0); i < fanoutValue; i++ {
|
||||
copy(hash[:], idx.Names[mappedFirstLevel][secondLevel*objectIDLength:])
|
||||
offset := int64(idx.getOffset(mappedFirstLevel, int(secondLevel)))
|
||||
offsetHash[offset] = hash
|
||||
off, err := idx.getOffset(mappedFirstLevel, int(secondLevel))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
offsetHash[int64(off)] = hash
|
||||
secondLevel++
|
||||
}
|
||||
}
|
||||
@ -291,7 +300,11 @@ func (i *idxfileEntryIter) Next() (*Entry, error) {
|
||||
mappedFirstLevel := i.idx.FanoutMapping[i.firstLevel]
|
||||
entry := new(Entry)
|
||||
copy(entry.Hash[:], i.idx.Names[mappedFirstLevel][i.secondLevel*objectIDLength:])
|
||||
entry.Offset = i.idx.getOffset(mappedFirstLevel, i.secondLevel)
|
||||
var err error
|
||||
entry.Offset, err = i.idx.getOffset(mappedFirstLevel, i.secondLevel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entry.CRC32 = i.idx.getCRC32(mappedFirstLevel, i.secondLevel)
|
||||
|
||||
i.secondLevel++
|
||||
|
||||
18
vendor/github.com/go-git/go-git/v5/plumbing/format/objfile/reader.go
generated
vendored
18
vendor/github.com/go-git/go-git/v5/plumbing/format/objfile/reader.go
generated
vendored
@ -11,9 +11,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrClosed = errors.New("objfile: already closed")
|
||||
ErrHeader = errors.New("objfile: invalid header")
|
||||
ErrNegativeSize = errors.New("objfile: negative object size")
|
||||
ErrClosed = errors.New("objfile: already closed")
|
||||
ErrHeader = errors.New("objfile: invalid header")
|
||||
ErrHeaderNotRead = errors.New("objfile: Header must be called before Read")
|
||||
ErrNegativeSize = errors.New("objfile: negative object size")
|
||||
)
|
||||
|
||||
// Reader reads and decodes compressed objfile data from a provided io.Reader.
|
||||
@ -100,12 +101,23 @@ func (r *Reader) prepareForRead(t plumbing.ObjectType, size int64) {
|
||||
//
|
||||
// If Read encounters the end of the data stream it will return err == io.EOF,
|
||||
// either in the current call if n > 0 or in a subsequent call.
|
||||
//
|
||||
// Read returns ErrHeaderNotRead if Header has not been called successfully.
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
if r.multi == nil {
|
||||
return 0, ErrHeaderNotRead
|
||||
}
|
||||
return r.multi.Read(p)
|
||||
}
|
||||
|
||||
// Hash returns the hash of the object data stream that has been read so far.
|
||||
// It returns the zero plumbing.Hash if Header has not been called
|
||||
// successfully — guarding against the nil hasher that prepareForRead has
|
||||
// not yet allocated.
|
||||
func (r *Reader) Hash() plumbing.Hash {
|
||||
if r.multi == nil {
|
||||
return plumbing.ZeroHash
|
||||
}
|
||||
return r.hasher.Sum()
|
||||
}
|
||||
|
||||
|
||||
3
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/diff_delta.go
generated
vendored
3
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/diff_delta.go
generated
vendored
@ -19,9 +19,6 @@ const (
|
||||
// https://github.com/git/git/blob/f7466e94375b3be27f229c78873f0acf8301c0a5/diff-delta.c#L428
|
||||
// Max size of a copy operation (64KB).
|
||||
maxCopySize = 64 * 1024
|
||||
|
||||
// Min size of a copy operation.
|
||||
minCopySize = 4
|
||||
)
|
||||
|
||||
// GetDelta returns an EncodedObject of type OFSDeltaObject. Base and Target object,
|
||||
|
||||
8
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/fsobject.go
generated
vendored
8
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/fsobject.go
generated
vendored
@ -78,7 +78,13 @@ func (o *FSObject) Reader() (io.ReadCloser, error) {
|
||||
_ = f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.NewReadCloserWithCloser(r, f.Close), nil
|
||||
// Cap the lazy stream at the resolved object size: well-formed
|
||||
// content reaches EOF inside the bound, an inflated stream that
|
||||
// runs past surfaces ErrInflatedSizeMismatch on the byte just
|
||||
// past the limit. For delta-resolved objects o.size is the
|
||||
// expanded size, which is what the caller is reading here.
|
||||
bounded := newBoundedReadCloser(r, o.size)
|
||||
return ioutil.NewReadCloserWithCloser(bounded, f.Close), nil
|
||||
}
|
||||
r, err := p.getObjectContent(o.offset)
|
||||
if err != nil {
|
||||
|
||||
21
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/packfile.go
generated
vendored
21
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/packfile.go
generated
vendored
@ -126,11 +126,17 @@ func (p *Packfile) nextObjectHeader() (*ObjectHeader, error) {
|
||||
return h, err
|
||||
}
|
||||
|
||||
func (p *Packfile) getDeltaObjectSize(buf *bytes.Buffer) int64 {
|
||||
func (p *Packfile) getDeltaObjectSize(buf *bytes.Buffer) (int64, error) {
|
||||
delta := buf.Bytes()
|
||||
_, delta = decodeLEB128(delta) // skip src size
|
||||
sz, _ := decodeLEB128(delta)
|
||||
return int64(sz)
|
||||
_, delta, err := decodeLEB128(delta) // skip src size
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
sz, _, err := decodeLEB128(delta)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int64(sz), nil
|
||||
}
|
||||
|
||||
func (p *Packfile) getObjectSize(h *ObjectHeader) (int64, error) {
|
||||
@ -145,7 +151,7 @@ func (p *Packfile) getObjectSize(h *ObjectHeader) (int64, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return p.getDeltaObjectSize(buf), nil
|
||||
return p.getDeltaObjectSize(buf)
|
||||
default:
|
||||
return 0, ErrInvalidObject.AddDetails("type %q", h.Type)
|
||||
}
|
||||
@ -233,7 +239,10 @@ func (p *Packfile) getNextObject(h *ObjectHeader, hash plumbing.Hash) (plumbing.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
size = p.getDeltaObjectSize(buf)
|
||||
size, err = p.getDeltaObjectSize(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size <= smallObjectThreshold {
|
||||
var obj = new(plumbing.MemoryObject)
|
||||
obj.SetSize(size)
|
||||
|
||||
72
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/parser.go
generated
vendored
72
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/parser.go
generated
vendored
@ -26,6 +26,45 @@ var (
|
||||
ErrDeltaNotCached = errors.New("delta could not be found in cache")
|
||||
)
|
||||
|
||||
// maxObjectPreallocBytes caps the up-front size hint passed to
|
||||
// bytes.Buffer.Grow when staging an object's contents, so a malformed length
|
||||
// cannot trigger a huge or out-of-range allocation. The buffer still grows
|
||||
// dynamically as data is written; this is purely a hint cap.
|
||||
const maxObjectPreallocBytes = 1 << 30 // 1 GiB
|
||||
|
||||
// maxObjectsPrealloc caps the up-front capacity reserved from the pack's
|
||||
// declared object count, so a header advertising an absurd quantity cannot
|
||||
// trigger a multi-gigabyte allocation. The slice and maps still grow
|
||||
// organically beyond this hint.
|
||||
const maxObjectsPrealloc = 1 << 16 // 64 Ki entries
|
||||
|
||||
// Match upstream Git's pack depth ceiling: pack-objects.h OE_DEPTH_BITS,
|
||||
// enforced in builtin/pack-objects.c as (1 << OE_DEPTH_BITS) - 1.
|
||||
const maxDeltaChainDepth = 4095
|
||||
|
||||
// growHint returns a non-negative int64 size, clamped to a sane upper bound,
|
||||
// suitable for passing to bytes.Buffer.Grow.
|
||||
func growHint(n int64) int {
|
||||
switch {
|
||||
case n <= 0:
|
||||
return 0
|
||||
case n > maxObjectPreallocBytes:
|
||||
return maxObjectPreallocBytes
|
||||
default:
|
||||
return int(n)
|
||||
}
|
||||
}
|
||||
|
||||
// objectsHint returns a non-negative count, clamped to maxObjectsPrealloc,
|
||||
// suitable for passing to make() as the capacity hint for slices or maps
|
||||
// sized from a pack's declared object count.
|
||||
func objectsHint(n uint32) int {
|
||||
if n > maxObjectsPrealloc {
|
||||
return maxObjectsPrealloc
|
||||
}
|
||||
return int(n)
|
||||
}
|
||||
|
||||
// Observer interface is implemented by index encoders.
|
||||
type Observer interface {
|
||||
// OnHeader is called when a new packfile is opened.
|
||||
@ -166,9 +205,10 @@ func (p *Parser) init() error {
|
||||
}
|
||||
|
||||
p.count = c
|
||||
p.oiByHash = make(map[plumbing.Hash]*objectInfo, p.count)
|
||||
p.oiByOffset = make(map[int64]*objectInfo, p.count)
|
||||
p.oi = make([]*objectInfo, p.count)
|
||||
hint := objectsHint(p.count)
|
||||
p.oiByHash = make(map[plumbing.Hash]*objectInfo, hint)
|
||||
p.oiByOffset = make(map[int64]*objectInfo, hint)
|
||||
p.oi = make([]*objectInfo, 0, hint)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -261,7 +301,7 @@ func (p *Parser) indexObjects() error {
|
||||
}
|
||||
if delta && !p.scanner.IsSeekable {
|
||||
buf.Reset()
|
||||
buf.Grow(int(oh.Length))
|
||||
buf.Grow(growHint(oh.Length))
|
||||
writers = append(writers, buf)
|
||||
}
|
||||
|
||||
@ -306,7 +346,7 @@ func (p *Parser) indexObjects() error {
|
||||
}
|
||||
|
||||
p.oiByOffset[oh.Offset] = ota
|
||||
p.oi[i] = ota
|
||||
p.oi = append(p.oi, ota)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -317,8 +357,12 @@ func (p *Parser) resolveDeltas() error {
|
||||
defer sync.PutBytesBuffer(buf)
|
||||
|
||||
for _, obj := range p.oi {
|
||||
if err := checkDeltaChainDepth(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
buf.Grow(int(obj.Length))
|
||||
buf.Grow(growHint(obj.Length))
|
||||
err := p.get(obj, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -337,6 +381,9 @@ func (p *Parser) resolveDeltas() error {
|
||||
// create it once and reuse across all children.
|
||||
r := bytes.NewReader(buf.Bytes())
|
||||
for _, child := range obj.Children {
|
||||
if err := checkDeltaChainDepth(child); err != nil {
|
||||
return err
|
||||
}
|
||||
// Even though we are discarding the output, we still need to read it to
|
||||
// so that the scanner can advance to the next object, and the SHA1 can be
|
||||
// calculated.
|
||||
@ -356,6 +403,17 @@ func (p *Parser) resolveDeltas() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkDeltaChainDepth(o *objectInfo) error {
|
||||
var depth int
|
||||
for current := o; current != nil && current.DiskType.IsDelta(); current = current.Parent {
|
||||
depth++
|
||||
if depth > maxDeltaChainDepth {
|
||||
return fmt.Errorf("%w: delta chain depth exceeds %d", ErrMalformedPackFile, maxDeltaChainDepth)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) resolveExternalRef(o *objectInfo) {
|
||||
if ref, ok := p.oiByHash[o.SHA1]; ok && ref.ExternalRef {
|
||||
p.oiByHash[o.SHA1] = o
|
||||
@ -405,7 +463,7 @@ func (p *Parser) get(o *objectInfo, buf *bytes.Buffer) (err error) {
|
||||
if o.DiskType.IsDelta() {
|
||||
b := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(b)
|
||||
buf.Grow(int(o.Length))
|
||||
buf.Grow(growHint(o.Length))
|
||||
err := p.get(o.Parent, b)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
113
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/patch_delta.go
generated
vendored
113
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/patch_delta.go
generated
vendored
@ -31,10 +31,15 @@ const (
|
||||
// premptively made available for a patch operation.
|
||||
maxPatchPreemptionSize uint = 65536
|
||||
|
||||
// minDeltaSize defines the smallest size for a delta.
|
||||
minDeltaSize = 4
|
||||
// minDeltaSize is the smallest valid delta: a 1-byte srcSz LEB128
|
||||
// header followed by a 1-byte targetSz LEB128 header (the
|
||||
// shortest case being targetSz=0 with no operations).
|
||||
minDeltaSize = 2
|
||||
)
|
||||
|
||||
// uintBits is the bit width of uint on the current platform (32 or 64).
|
||||
const uintBits = 32 << (^uint(0) >> 63)
|
||||
|
||||
type offset struct {
|
||||
mask byte
|
||||
shift uint
|
||||
@ -142,7 +147,7 @@ func ReaderFromDelta(base plumbing.EncodedObject, deltaRC io.Reader) (io.ReadClo
|
||||
baseBuf := bufio.NewReader(baseRd)
|
||||
basePos := uint(0)
|
||||
|
||||
for {
|
||||
for remainingTargetSz > 0 {
|
||||
cmd, err := deltaBuf.ReadByte()
|
||||
if err == io.EOF {
|
||||
_ = dstWr.CloseWithError(ErrInvalidDelta)
|
||||
@ -166,9 +171,9 @@ func ReaderFromDelta(base plumbing.EncodedObject, deltaRC io.Reader) (io.ReadClo
|
||||
return
|
||||
}
|
||||
|
||||
if invalidSize(sz, targetSz) ||
|
||||
if invalidSize(sz, remainingTargetSz) ||
|
||||
invalidOffsetSize(offset, sz, srcSz) {
|
||||
_ = dstWr.Close()
|
||||
_ = dstWr.CloseWithError(ErrInvalidDelta)
|
||||
return
|
||||
}
|
||||
|
||||
@ -210,7 +215,7 @@ func ReaderFromDelta(base plumbing.EncodedObject, deltaRC io.Reader) (io.ReadClo
|
||||
|
||||
case isCopyFromDelta(cmd):
|
||||
sz := uint(cmd) // cmd is the size itself
|
||||
if invalidSize(sz, targetSz) {
|
||||
if invalidSize(sz, remainingTargetSz) {
|
||||
_ = dstWr.CloseWithError(ErrInvalidDelta)
|
||||
return
|
||||
}
|
||||
@ -225,40 +230,48 @@ func ReaderFromDelta(base plumbing.EncodedObject, deltaRC io.Reader) (io.ReadClo
|
||||
_ = dstWr.CloseWithError(ErrDeltaCmd)
|
||||
return
|
||||
}
|
||||
|
||||
if remainingTargetSz <= 0 {
|
||||
_ = dstWr.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Mirror upstream's `data != top` post-loop check: every byte
|
||||
// of the delta payload must be consumed.
|
||||
if _, err := deltaBuf.ReadByte(); err == nil {
|
||||
_ = dstWr.CloseWithError(ErrInvalidDelta)
|
||||
return
|
||||
} else if err != io.EOF {
|
||||
_ = dstWr.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
_ = dstWr.Close()
|
||||
}()
|
||||
|
||||
return dstRd, nil
|
||||
}
|
||||
|
||||
func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
if len(delta) < minCopySize {
|
||||
return ErrInvalidDelta
|
||||
srcSz, delta, err := decodeLEB128(delta)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %w", ErrInvalidDelta, err)
|
||||
}
|
||||
|
||||
srcSz, delta := decodeLEB128(delta)
|
||||
if srcSz != uint(len(src)) {
|
||||
return ErrInvalidDelta
|
||||
}
|
||||
|
||||
targetSz, delta := decodeLEB128(delta)
|
||||
targetSz, delta, err := decodeLEB128(delta)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %w", ErrInvalidDelta, err)
|
||||
}
|
||||
remainingTargetSz := targetSz
|
||||
|
||||
var cmd byte
|
||||
|
||||
growSz := min(targetSz, maxPatchPreemptionSize)
|
||||
dst.Grow(int(growSz))
|
||||
for {
|
||||
|
||||
for remainingTargetSz > 0 {
|
||||
if len(delta) == 0 {
|
||||
return ErrInvalidDelta
|
||||
}
|
||||
|
||||
cmd = delta[0]
|
||||
cmd := delta[0]
|
||||
delta = delta[1:]
|
||||
|
||||
switch {
|
||||
@ -275,16 +288,16 @@ func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if invalidSize(sz, targetSz) ||
|
||||
if invalidSize(sz, remainingTargetSz) ||
|
||||
invalidOffsetSize(offset, sz, srcSz) {
|
||||
break
|
||||
return ErrInvalidDelta
|
||||
}
|
||||
dst.Write(src[offset : offset+sz])
|
||||
remainingTargetSz -= sz
|
||||
|
||||
case isCopyFromDelta(cmd):
|
||||
sz := uint(cmd) // cmd is the size itself
|
||||
if invalidSize(sz, targetSz) {
|
||||
if invalidSize(sz, remainingTargetSz) {
|
||||
return ErrInvalidDelta
|
||||
}
|
||||
|
||||
@ -299,10 +312,12 @@ func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
default:
|
||||
return ErrDeltaCmd
|
||||
}
|
||||
}
|
||||
|
||||
if remainingTargetSz <= 0 {
|
||||
break
|
||||
}
|
||||
// Mirror upstream's `data != top` post-loop check: every byte of
|
||||
// the delta payload must be consumed.
|
||||
if len(delta) != 0 {
|
||||
return ErrInvalidDelta
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -354,7 +369,7 @@ func patchDeltaWriter(dst io.Writer, base io.ReaderAt, delta io.Reader,
|
||||
baselr := io.LimitReader(sr, 0).(*io.LimitedReader)
|
||||
deltalr := io.LimitReader(deltaBuf, 0).(*io.LimitedReader)
|
||||
|
||||
for {
|
||||
for remainingTargetSz > 0 {
|
||||
buf := *bufp
|
||||
cmd, err := deltaBuf.ReadByte()
|
||||
if err == io.EOF {
|
||||
@ -374,9 +389,9 @@ func patchDeltaWriter(dst io.Writer, base io.ReaderAt, delta io.Reader,
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
|
||||
if invalidSize(sz, targetSz) ||
|
||||
if invalidSize(sz, remainingTargetSz) ||
|
||||
invalidOffsetSize(offset, sz, srcSz) {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
return 0, plumbing.ZeroHash, ErrInvalidDelta
|
||||
}
|
||||
|
||||
if _, err := sr.Seek(int64(offset), io.SeekStart); err != nil {
|
||||
@ -389,7 +404,7 @@ func patchDeltaWriter(dst io.Writer, base io.ReaderAt, delta io.Reader,
|
||||
remainingTargetSz -= sz
|
||||
} else if isCopyFromDelta(cmd) {
|
||||
sz := uint(cmd) // cmd is the size itself
|
||||
if invalidSize(sz, targetSz) {
|
||||
if invalidSize(sz, remainingTargetSz) {
|
||||
return 0, plumbing.ZeroHash, ErrInvalidDelta
|
||||
}
|
||||
deltalr.N = int64(sz)
|
||||
@ -399,30 +414,41 @@ func patchDeltaWriter(dst io.Writer, base io.ReaderAt, delta io.Reader,
|
||||
|
||||
remainingTargetSz -= sz
|
||||
} else {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
if remainingTargetSz <= 0 {
|
||||
break
|
||||
return 0, plumbing.ZeroHash, ErrDeltaCmd
|
||||
}
|
||||
}
|
||||
|
||||
// Mirror upstream's `data != top` post-loop check: every byte of
|
||||
// the delta payload must be consumed.
|
||||
if _, err := deltaBuf.ReadByte(); err == nil {
|
||||
return 0, plumbing.ZeroHash, ErrInvalidDelta
|
||||
} else if err != io.EOF {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
|
||||
return targetSz, hasher.Sum(), nil
|
||||
}
|
||||
|
||||
// Decodes a number encoded as an unsigned LEB128 at the start of some
|
||||
// binary data and returns the decoded number and the rest of the
|
||||
// stream.
|
||||
// binary data and returns the decoded number, the rest of the stream,
|
||||
// and an error if the encoded value does not fit in a uint.
|
||||
//
|
||||
// This must be called twice on the delta data buffer, first to get the
|
||||
// expected source buffer size, and again to get the target buffer size.
|
||||
func decodeLEB128(input []byte) (uint, []byte) {
|
||||
func decodeLEB128(input []byte) (uint, []byte, error) {
|
||||
if len(input) == 0 {
|
||||
return 0, input
|
||||
return 0, input, nil
|
||||
}
|
||||
|
||||
var num, sz uint
|
||||
var b byte
|
||||
for {
|
||||
// A continuation byte at shift > uintBits-7 cannot contribute
|
||||
// without overflowing the accumulator.
|
||||
if sz*7 > uintBits-7 {
|
||||
return 0, input, ErrLengthOverflow
|
||||
}
|
||||
|
||||
b = input[sz]
|
||||
num |= (uint(b) & payload) << (sz * 7) // concats 7 bits chunks
|
||||
sz++
|
||||
@ -432,12 +458,16 @@ func decodeLEB128(input []byte) (uint, []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
return num, input[sz:]
|
||||
return num, input[sz:], nil
|
||||
}
|
||||
|
||||
func decodeLEB128ByteReader(input io.ByteReader) (uint, error) {
|
||||
var num, sz uint
|
||||
for {
|
||||
if sz*7 > uintBits-7 {
|
||||
return 0, ErrLengthOverflow
|
||||
}
|
||||
|
||||
b, err := input.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@ -529,8 +559,9 @@ func decodeSize(cmd byte, delta []byte) (uint, []byte, error) {
|
||||
return sz, delta, nil
|
||||
}
|
||||
|
||||
func invalidSize(sz, targetSz uint) bool {
|
||||
return sz > targetSz
|
||||
// invalidSize reports whether sz exceeds the remaining target size.
|
||||
func invalidSize(sz, remaining uint) bool {
|
||||
return sz > remaining
|
||||
}
|
||||
|
||||
func invalidOffsetSize(offset, sz, srcSz uint) bool {
|
||||
|
||||
154
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/scanner.go
generated
vendored
154
vendor/github.com/go-git/go-git/v5/plumbing/format/packfile/scanner.go
generated
vendored
@ -29,8 +29,100 @@ var (
|
||||
ErrSeekNotSupported = NewError("not seek support")
|
||||
// ErrMalformedPackFile is returned by the parser when the pack file is corrupted.
|
||||
ErrMalformedPackFile = errors.New("malformed PACK file")
|
||||
// ErrLengthOverflow is returned when a variable-length integer would not
|
||||
// fit into its accumulator because the input declares more continuation
|
||||
// bytes than the type can hold.
|
||||
ErrLengthOverflow = errors.New("variable-length integer overflow")
|
||||
// ErrInflatedSizeMismatch is returned when a packfile object inflates to
|
||||
// more bytes than the size declared in its object header. A well-formed
|
||||
// packfile never produces more data than the declared size; exceeding it
|
||||
// indicates a structurally invalid entry.
|
||||
ErrInflatedSizeMismatch = errors.New("packfile: inflated object exceeds declared size")
|
||||
)
|
||||
|
||||
// boundedWriter passes writes through to w up to limit bytes total, then
|
||||
// returns ErrInflatedSizeMismatch. It is used to enforce that a packfile
|
||||
// object's inflated length does not exceed the size declared in its header.
|
||||
type boundedWriter struct {
|
||||
w io.Writer
|
||||
limit int64
|
||||
n int64
|
||||
}
|
||||
|
||||
// Write forwards p to the underlying writer while keeping the running total
|
||||
// at or below limit. On overrun it forwards the legal prefix and reports
|
||||
// the number of bytes actually consumed alongside ErrInflatedSizeMismatch,
|
||||
// matching the contract in io.Writer. A write error from the underlying
|
||||
// writer during overrun-handling is joined with ErrInflatedSizeMismatch so
|
||||
// it is not silently dropped.
|
||||
func (b *boundedWriter) Write(p []byte) (int, error) {
|
||||
if b.n+int64(len(p)) > b.limit {
|
||||
remain := int(b.limit - b.n)
|
||||
err := error(ErrInflatedSizeMismatch)
|
||||
if remain > 0 {
|
||||
n, werr := b.w.Write(p[:remain])
|
||||
b.n += int64(n)
|
||||
if werr != nil {
|
||||
err = errors.Join(ErrInflatedSizeMismatch, werr)
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
n, err := b.w.Write(p)
|
||||
b.n += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// boundedReadCloser wraps a ReadCloser and reports ErrInflatedSizeMismatch
|
||||
// once more than limit bytes have been read. It is used by the on-demand
|
||||
// object reader returned from FSObject.Reader so that a lazy Read of a
|
||||
// packfile object cannot stream past its declared inflated size.
|
||||
//
|
||||
// The implementation builds on io.LimitedReader with the standard
|
||||
// overrun-detection trick: request limit+1 bytes from the underlying so
|
||||
// that the moment the sentinel byte materializes (LimitedReader.N drops
|
||||
// to zero) we know the source produced more than limit bytes.
|
||||
type boundedReadCloser struct {
|
||||
lr io.LimitedReader
|
||||
closer io.Closer
|
||||
overrun bool
|
||||
}
|
||||
|
||||
// newBoundedReadCloser wraps rc so that the cumulative bytes returned from
|
||||
// Read never exceed limit. The first call that would have returned a byte
|
||||
// past limit instead returns ErrInflatedSizeMismatch; subsequent calls
|
||||
// keep returning the same error. A negative limit is treated as zero, so
|
||||
// the first byte produced by rc surfaces ErrInflatedSizeMismatch.
|
||||
func newBoundedReadCloser(rc io.ReadCloser, limit int64) *boundedReadCloser {
|
||||
if limit < 0 {
|
||||
limit = 0
|
||||
}
|
||||
return &boundedReadCloser{
|
||||
lr: io.LimitedReader{R: rc, N: limit + 1},
|
||||
closer: rc,
|
||||
}
|
||||
}
|
||||
|
||||
// Read forwards Read up to the configured byte limit. When the underlying
|
||||
// stream produces the limit+1 sentinel byte, the legal prefix is returned
|
||||
// alongside ErrInflatedSizeMismatch; on subsequent calls only the error
|
||||
// is returned.
|
||||
func (b *boundedReadCloser) Read(p []byte) (int, error) {
|
||||
if b.overrun {
|
||||
return 0, ErrInflatedSizeMismatch
|
||||
}
|
||||
n, err := b.lr.Read(p)
|
||||
if b.lr.N == 0 {
|
||||
b.overrun = true
|
||||
return n - 1, ErrInflatedSizeMismatch
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Close closes the underlying ReadCloser.
|
||||
func (b *boundedReadCloser) Close() error { return b.closer.Close() }
|
||||
|
||||
// ObjectHeader contains the information related to the object, this information
|
||||
// is collected from the previous bytes to the content of the object.
|
||||
type ObjectHeader struct {
|
||||
@ -220,6 +312,13 @@ func (s *Scanner) nextObjectHeader() (*ObjectHeader, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// An OFS-delta references a base object that appears earlier
|
||||
// in the pack; the negative offset must be strictly positive
|
||||
// and not larger than the current object's offset.
|
||||
if no <= 0 || no > h.Offset {
|
||||
return nil, fmt.Errorf("%w: invalid OFS delta offset", ErrMalformedPackFile)
|
||||
}
|
||||
|
||||
h.OffsetReference = h.Offset - no
|
||||
case plumbing.REFDeltaObject:
|
||||
var err error
|
||||
@ -303,6 +402,13 @@ func (s *Scanner) readLength(first byte) (int64, error) {
|
||||
shift := firstLengthBits
|
||||
var err error
|
||||
for c&maskContinue > 0 {
|
||||
// Mirrors unpack_object_header_buffer in canonical Git's
|
||||
// packfile.c: a continuation byte at shift > 64-7 cannot
|
||||
// contribute without overflowing an int64.
|
||||
if shift > 64-lengthBits {
|
||||
return 0, fmt.Errorf("%w: %w", ErrMalformedPackFile, ErrLengthOverflow)
|
||||
}
|
||||
|
||||
if c, err = s.r.ReadByte(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -315,10 +421,18 @@ func (s *Scanner) readLength(first byte) (int64, error) {
|
||||
}
|
||||
|
||||
// NextObject writes the content of the next object into the reader, returns
|
||||
// the number of bytes written, the CRC32 of the content and an error, if any
|
||||
// the number of bytes written, the CRC32 of the content and an error, if any.
|
||||
//
|
||||
// When a prior NextObjectHeader has stashed the object header in
|
||||
// pendingObject, the inflated stream is bounded by the header's declared
|
||||
// length and surfaces ErrInflatedSizeMismatch on overrun.
|
||||
func (s *Scanner) NextObject(w io.Writer) (written int64, crc32 uint32, err error) {
|
||||
declaredSize := int64(-1)
|
||||
if s.pendingObject != nil {
|
||||
declaredSize = s.pendingObject.Length
|
||||
}
|
||||
s.pendingObject = nil
|
||||
written, err = s.copyObject(w)
|
||||
written, err = s.copyObject(w, declaredSize)
|
||||
|
||||
s.r.Flush()
|
||||
crc32 = s.crc.Sum32()
|
||||
@ -327,23 +441,39 @@ func (s *Scanner) NextObject(w io.Writer) (written int64, crc32 uint32, err erro
|
||||
return
|
||||
}
|
||||
|
||||
// ReadObject returns a reader for the object content and an error
|
||||
// ReadObject returns a reader for the object content and an error.
|
||||
//
|
||||
// When a prior NextObjectHeader has stashed the object header in
|
||||
// pendingObject, the returned reader is bounded by the header's declared
|
||||
// length so callers cannot stream past the declared inflated size; an
|
||||
// overrun surfaces ErrInflatedSizeMismatch on the byte just past the
|
||||
// limit.
|
||||
func (s *Scanner) ReadObject() (io.ReadCloser, error) {
|
||||
declaredSize := int64(-1)
|
||||
if s.pendingObject != nil {
|
||||
declaredSize = s.pendingObject.Length
|
||||
}
|
||||
s.pendingObject = nil
|
||||
zr, err := sync.GetZlibReader(s.r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("zlib reset error: %s", err)
|
||||
}
|
||||
|
||||
return ioutil.NewReadCloserWithCloser(zr.Reader, func() error {
|
||||
rc := ioutil.NewReadCloserWithCloser(zr.Reader, func() error {
|
||||
sync.PutZlibReader(zr)
|
||||
return nil
|
||||
}), nil
|
||||
})
|
||||
if declaredSize >= 0 {
|
||||
return newBoundedReadCloser(rc, declaredSize), nil
|
||||
}
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
// ReadRegularObject reads and write a non-deltified object
|
||||
// from it zlib stream in an object entry in the packfile.
|
||||
func (s *Scanner) copyObject(w io.Writer) (n int64, err error) {
|
||||
// copyObject inflates a non-deltified object's zlib stream into w. When
|
||||
// declaredSize is non-negative, the write sink is wrapped in a
|
||||
// boundedWriter so an overrun surfaces ErrInflatedSizeMismatch instead
|
||||
// of being silently appended.
|
||||
func (s *Scanner) copyObject(w io.Writer, declaredSize int64) (n int64, err error) {
|
||||
zr, err := sync.GetZlibReader(s.r)
|
||||
defer sync.PutZlibReader(zr)
|
||||
|
||||
@ -352,8 +482,14 @@ func (s *Scanner) copyObject(w io.Writer) (n int64, err error) {
|
||||
}
|
||||
|
||||
defer ioutil.CheckClose(zr.Reader, &err)
|
||||
|
||||
sink := w
|
||||
if declaredSize >= 0 {
|
||||
sink = &boundedWriter{w: w, limit: declaredSize}
|
||||
}
|
||||
|
||||
buf := sync.GetByteSlice()
|
||||
n, err = io.CopyBuffer(w, zr.Reader, *buf)
|
||||
n, err = io.CopyBuffer(sink, zr.Reader, *buf)
|
||||
sync.PutByteSlice(buf)
|
||||
return
|
||||
}
|
||||
|
||||
207
vendor/github.com/go-git/go-git/v5/plumbing/object/commit.go
generated
vendored
207
vendor/github.com/go-git/go-git/v5/plumbing/object/commit.go
generated
vendored
@ -5,7 +5,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
@ -20,6 +20,7 @@ const (
|
||||
beginpgp string = "-----BEGIN PGP SIGNATURE-----"
|
||||
endpgp string = "-----END PGP SIGNATURE-----"
|
||||
headerpgp string = "gpgsig"
|
||||
headerpgp256 string = "gpgsig-sha256"
|
||||
headerencoding string = "encoding"
|
||||
|
||||
// https://github.com/git/git/blob/bcb6cae2966cc407ca1afc77413b3ef11103c175/Documentation/gitformat-signature.txt#L153
|
||||
@ -41,6 +42,11 @@ type MessageEncoding string
|
||||
// in time, such as a timestamp, the author of the changes since the last
|
||||
// commit, a pointer to the previous commit(s), etc.
|
||||
// http://shafiulazam.com/gitbook/1_the_git_object_model.html
|
||||
//
|
||||
// When a Commit is populated by Decode it retains a reference to the source
|
||||
// plumbing.EncodedObject so that EncodeWithoutSignature can reproduce the
|
||||
// exact bytes the signature was computed over. Refer to EncodeWithoutSignature
|
||||
// for more information.
|
||||
type Commit struct {
|
||||
// Hash of the commit object.
|
||||
Hash plumbing.Hash
|
||||
@ -66,6 +72,9 @@ type Commit struct {
|
||||
ExtraHeaders []ExtraHeader
|
||||
|
||||
s storer.EncodedObjectStorer
|
||||
// src holds the encoded object this Commit was decoded from, used by
|
||||
// EncodeWithoutSignature to recover the canonical signed bytes.
|
||||
src plumbing.EncodedObject
|
||||
}
|
||||
|
||||
// ExtraHeader holds any non-standard header
|
||||
@ -98,8 +107,8 @@ func (h ExtraHeader) Format(f fmt.State, verb rune) {
|
||||
func parseExtraHeader(line []byte) (ExtraHeader, bool) {
|
||||
split := bytes.SplitN(line, []byte{' '}, 2)
|
||||
|
||||
out := ExtraHeader {
|
||||
Key: string(bytes.TrimRight(split[0], "\n")),
|
||||
out := ExtraHeader{
|
||||
Key: string(bytes.TrimRight(split[0], "\n")),
|
||||
Value: "",
|
||||
}
|
||||
|
||||
@ -181,6 +190,11 @@ func (c *Commit) NumParents() int {
|
||||
|
||||
var ErrParentNotFound = errors.New("commit parent not found")
|
||||
|
||||
// ErrMalformedCommit is returned when a commit object cannot be decoded
|
||||
// because its standard headers (tree, parent, author, committer) are missing,
|
||||
// duplicated, or out of order.
|
||||
var ErrMalformedCommit = errors.New("malformed commit")
|
||||
|
||||
// Parent returns the ith parent of a commit.
|
||||
func (c *Commit) Parent(i int) (*Commit, error) {
|
||||
if len(c.ParentHashes) == 0 || i > len(c.ParentHashes)-1 {
|
||||
@ -227,14 +241,23 @@ func (c *Commit) Type() plumbing.ObjectType {
|
||||
return plumbing.CommitObject
|
||||
}
|
||||
|
||||
func (c *Commit) reset() {
|
||||
storer := c.s
|
||||
*c = Commit{
|
||||
Encoding: defaultUtf8CommitMessageEncoding,
|
||||
s: storer,
|
||||
}
|
||||
}
|
||||
|
||||
// Decode transforms a plumbing.EncodedObject into a Commit struct.
|
||||
func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
|
||||
if o.Type() != plumbing.CommitObject {
|
||||
return ErrUnsupportedObject
|
||||
}
|
||||
|
||||
c.reset()
|
||||
c.Hash = o.Hash()
|
||||
c.Encoding = defaultUtf8CommitMessageEncoding
|
||||
c.src = o
|
||||
|
||||
reader, err := o.Reader()
|
||||
if err != nil {
|
||||
@ -245,97 +268,17 @@ func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
|
||||
r := sync.GetBufioReader(reader)
|
||||
defer sync.PutBufioReader(r)
|
||||
|
||||
var message bool
|
||||
var mergetag bool
|
||||
var pgpsig bool
|
||||
var msgbuf bytes.Buffer
|
||||
var extraheader *ExtraHeader = nil
|
||||
for {
|
||||
line, err := r.ReadBytes('\n')
|
||||
if err != nil && err != io.EOF {
|
||||
s := &commitScanner{r: r, c: c}
|
||||
for state := scanTree; state != nil; {
|
||||
state, err = state(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mergetag {
|
||||
if len(line) > 0 && line[0] == ' ' {
|
||||
line = bytes.TrimLeft(line, " ")
|
||||
c.MergeTag += string(line)
|
||||
continue
|
||||
} else {
|
||||
mergetag = false
|
||||
}
|
||||
}
|
||||
|
||||
if pgpsig {
|
||||
if len(line) > 0 && line[0] == ' ' {
|
||||
line = bytes.TrimLeft(line, " ")
|
||||
c.PGPSignature += string(line)
|
||||
continue
|
||||
} else {
|
||||
pgpsig = false
|
||||
}
|
||||
}
|
||||
|
||||
if extraheader != nil {
|
||||
if len(line) > 0 && line[0] == ' ' {
|
||||
extraheader.Value += string(line[1:])
|
||||
continue
|
||||
} else {
|
||||
extraheader.Value = strings.TrimRight(extraheader.Value, "\n")
|
||||
c.ExtraHeaders = append(c.ExtraHeaders, *extraheader)
|
||||
extraheader = nil
|
||||
}
|
||||
}
|
||||
|
||||
if !message {
|
||||
original_line := line
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
message = true
|
||||
continue
|
||||
}
|
||||
|
||||
split := bytes.SplitN(line, []byte{' '}, 2)
|
||||
|
||||
var data []byte
|
||||
if len(split) == 2 {
|
||||
data = split[1]
|
||||
}
|
||||
|
||||
switch string(split[0]) {
|
||||
case "tree":
|
||||
c.TreeHash = plumbing.NewHash(string(data))
|
||||
case "parent":
|
||||
c.ParentHashes = append(c.ParentHashes, plumbing.NewHash(string(data)))
|
||||
case "author":
|
||||
c.Author.Decode(data)
|
||||
case "committer":
|
||||
c.Committer.Decode(data)
|
||||
case headermergetag:
|
||||
c.MergeTag += string(data) + "\n"
|
||||
mergetag = true
|
||||
case headerencoding:
|
||||
c.Encoding = MessageEncoding(data)
|
||||
case headerpgp:
|
||||
c.PGPSignature += string(data) + "\n"
|
||||
pgpsig = true
|
||||
default:
|
||||
h, maybecontinued := parseExtraHeader(original_line)
|
||||
if maybecontinued {
|
||||
extraheader = &h
|
||||
} else {
|
||||
c.ExtraHeaders = append(c.ExtraHeaders, h)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
msgbuf.Write(line)
|
||||
}
|
||||
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
c.Message = msgbuf.String()
|
||||
if !s.sawTree {
|
||||
return fmt.Errorf("%w: missing tree header", ErrMalformedCommit)
|
||||
}
|
||||
c.Message = s.msgbuf.String()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -344,11 +287,73 @@ func (c *Commit) Encode(o plumbing.EncodedObject) error {
|
||||
return c.encode(o, true)
|
||||
}
|
||||
|
||||
// EncodeWithoutSignature export a Commit into a plumbing.EncodedObject without the signature (correspond to the payload of the PGP signature).
|
||||
// EncodeWithoutSignature exports a Commit into a plumbing.EncodedObject
|
||||
// without any signature headers, producing the payload that PGP/GPG
|
||||
// signatures are computed over.
|
||||
//
|
||||
// Behaviour depends on how the Commit was created:
|
||||
//
|
||||
// - For Commits populated by Decode whose exported fields still match the
|
||||
// source object, the payload is streamed from the raw source bytes with
|
||||
// gpgsig and gpgsig-sha256 headers (and their continuation lines)
|
||||
// stripped verbatim. This preserves the exact bytes the signature was
|
||||
// computed over, regardless of any normalization performed by Decode.
|
||||
//
|
||||
// - For Commits constructed in memory, or for decoded Commits whose
|
||||
// exported fields have been mutated, the payload is derived from the
|
||||
// current struct fields. Mutation is detected by re-decoding the source
|
||||
// object and comparing exported fields; if any differ, the in-memory
|
||||
// representation prevails.
|
||||
func (c *Commit) EncodeWithoutSignature(o plumbing.EncodedObject) error {
|
||||
if c.matchesSource() {
|
||||
return stripObjectSignatures(o, c.src, plumbing.CommitObject)
|
||||
}
|
||||
return c.encode(o, false)
|
||||
}
|
||||
|
||||
// matchesSource reports whether c.src is set and re-decoding it produces a
|
||||
// Commit whose payload-affecting exported fields are identical to those of
|
||||
// c. It is the auto-detection used by EncodeWithoutSignature to decide
|
||||
// between the raw bytes and the struct-encoded payload.
|
||||
//
|
||||
// PGPSignature is intentionally excluded from the comparison: neither path
|
||||
// emits it, so mutating it must not trigger a switch to struct-encode (which
|
||||
// would change the byte layout the caller is trying to verify against).
|
||||
func (c *Commit) matchesSource() bool {
|
||||
if c.src == nil {
|
||||
return false
|
||||
}
|
||||
fresh := &Commit{}
|
||||
if err := fresh.Decode(c.src); err != nil {
|
||||
return false
|
||||
}
|
||||
return c.Hash == fresh.Hash &&
|
||||
signatureEqual(c.Author, fresh.Author) &&
|
||||
signatureEqual(c.Committer, fresh.Committer) &&
|
||||
c.MergeTag == fresh.MergeTag &&
|
||||
c.Message == fresh.Message &&
|
||||
c.TreeHash == fresh.TreeHash &&
|
||||
c.Encoding == fresh.Encoding &&
|
||||
slices.Equal(c.ParentHashes, fresh.ParentHashes) &&
|
||||
slices.Equal(c.ExtraHeaders, fresh.ExtraHeaders)
|
||||
}
|
||||
|
||||
func signatureEqual(a, b Signature) bool {
|
||||
return a.Name == b.Name &&
|
||||
a.Email == b.Email &&
|
||||
a.When.Unix() == b.When.Unix() &&
|
||||
a.When.Format("-0700") == b.When.Format("-0700")
|
||||
}
|
||||
|
||||
func isStandardHeader(key string) bool {
|
||||
switch key {
|
||||
case "tree", "parent", "author", "committer",
|
||||
headerencoding, headermergetag, headerpgp, headerpgp256:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
|
||||
o.SetType(plumbing.CommitObject)
|
||||
w, err := o.Writer()
|
||||
@ -407,7 +412,9 @@ func (c *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
|
||||
}
|
||||
|
||||
for _, header := range c.ExtraHeaders {
|
||||
|
||||
if isStandardHeader(header.Key) {
|
||||
continue
|
||||
}
|
||||
if _, err = fmt.Fprintf(w, "\n%s", header); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -478,9 +485,21 @@ func (c *Commit) String() string {
|
||||
)
|
||||
}
|
||||
|
||||
// ErrMultipleSignatures is returned by Verify when the commit carries more
|
||||
// than one armored signature block. Mirrors upstream's parse_gpg_output
|
||||
// rejection of GOODSIG/BADSIG status lines after the first
|
||||
// (gpg-interface.c:257-269): multi-signature commits are intentionally
|
||||
// unsupported because their provenance cannot be reduced to a single
|
||||
// authoritative signer.
|
||||
var ErrMultipleSignatures = errors.New("commit has multiple signatures")
|
||||
|
||||
// Verify performs PGP verification of the commit with a provided armored
|
||||
// keyring and returns openpgp.Entity associated with verifying key on success.
|
||||
func (c *Commit) Verify(armoredKeyRing string) (*openpgp.Entity, error) {
|
||||
if countSignatureBlocks([]byte(c.PGPSignature)) > 1 {
|
||||
return nil, ErrMultipleSignatures
|
||||
}
|
||||
|
||||
keyRingReader := strings.NewReader(armoredKeyRing)
|
||||
keyring, err := openpgp.ReadArmoredKeyRing(keyRingReader)
|
||||
if err != nil {
|
||||
|
||||
377
vendor/github.com/go-git/go-git/v5/plumbing/object/commit_scanner.go
generated
vendored
Normal file
377
vendor/github.com/go-git/go-git/v5/plumbing/object/commit_scanner.go
generated
vendored
Normal file
@ -0,0 +1,377 @@
|
||||
package object
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
// commitScanner holds the working state of the commit decoder driven by the
|
||||
// stateFn loop in (*Commit).Decode. Each commitState reads one or more lines
|
||||
// from r, updates the in-progress *Commit and the scanner's bookkeeping, and
|
||||
// returns the state that should run next (or nil to stop).
|
||||
type commitScanner struct {
|
||||
r *bufio.Reader
|
||||
c *Commit
|
||||
msgbuf bytes.Buffer
|
||||
|
||||
// pending holds a line that was read but the current state decided to
|
||||
// hand back to the next state, paired with the io.EOF flag that was
|
||||
// returned when the line was originally read.
|
||||
pending []byte
|
||||
pendingErr error
|
||||
|
||||
// First-occurrence tracking: once the corresponding field has been
|
||||
// decoded, subsequent occurrences are silently dropped (matches
|
||||
// upstream's find_commit_header / first-wins semantics).
|
||||
//
|
||||
// gpgsig is not tracked here: upstream's parse_buffer_signed_by_header
|
||||
// (commit.c:1186) accumulates every occurrence into one signature buffer,
|
||||
// so we do the same on the scanner side to keep verification payloads
|
||||
// byte-aligned. gpgsig-sha256 is recognized and skipped without exposing a
|
||||
// new field in v5.
|
||||
sawTree, sawAuthor, sawCommitter bool
|
||||
sawEncoding, sawMergetag bool
|
||||
|
||||
// extra is the multi-line ExtraHeader currently being assembled.
|
||||
extra *ExtraHeader
|
||||
}
|
||||
|
||||
// commitState is one step of the decoder state machine. Each function reads
|
||||
// the lines it needs, mutates *Commit via s.c, and returns the next state to
|
||||
// run (or nil to terminate the loop).
|
||||
type commitState func(*commitScanner) (commitState, error)
|
||||
|
||||
// readLine returns the next line from the buffer, transparently consuming any
|
||||
// line that was previously pushed back by a state that decided not to handle
|
||||
// it.
|
||||
func (s *commitScanner) readLine() ([]byte, error) {
|
||||
if s.pending != nil {
|
||||
line, err := s.pending, s.pendingErr
|
||||
s.pending, s.pendingErr = nil, nil
|
||||
return line, err
|
||||
}
|
||||
line, err := s.r.ReadBytes('\n')
|
||||
if err != nil && err != io.EOF {
|
||||
return line, err
|
||||
}
|
||||
return line, err
|
||||
}
|
||||
|
||||
// pushBack stashes an unconsumed line so the next state's readLine call sees
|
||||
// it. Only one line can be pushed back at a time.
|
||||
func (s *commitScanner) pushBack(line []byte, err error) {
|
||||
s.pending = line
|
||||
s.pendingErr = err
|
||||
}
|
||||
|
||||
// scanTree expects the first non-empty header to be `tree HASH`. Anything
|
||||
// else (or an empty buffer) is rejected with ErrMalformedCommit, matching
|
||||
// upstream's `bogus commit object` check.
|
||||
func scanTree(s *commitScanner) (commitState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 || isBlankLine(line) {
|
||||
return nil, fmt.Errorf("%w: missing tree header", ErrMalformedCommit)
|
||||
}
|
||||
|
||||
key, data := splitHeader(line)
|
||||
if key != "tree" {
|
||||
return nil, fmt.Errorf("%w: tree header must be first", ErrMalformedCommit)
|
||||
}
|
||||
h, herr := parseObjectIDHex(data, ErrMalformedCommit, "tree")
|
||||
if herr != nil {
|
||||
return nil, herr
|
||||
}
|
||||
s.c.TreeHash = h
|
||||
s.sawTree = true
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return scanParents, nil
|
||||
}
|
||||
|
||||
// scanParents consumes contiguous `parent HASH` lines. The first non-parent
|
||||
// line ends the parent block and is handed off to scanAuthor; any later
|
||||
// `parent` line is silently dropped (matches upstream's parse_commit_buffer
|
||||
// exiting its parent loop at the first non-parent line and
|
||||
// read_commit_extra_header_lines filtering `parent` out of extras).
|
||||
func scanParents(s *commitScanner) (commitState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if isBlankLine(line) {
|
||||
return scanMessage, nil
|
||||
}
|
||||
|
||||
key, data := splitHeader(line)
|
||||
if key == "parent" {
|
||||
h, herr := parseObjectIDHex(data, ErrMalformedCommit, "parent")
|
||||
if herr != nil {
|
||||
return nil, herr
|
||||
}
|
||||
s.c.ParentHashes = append(s.c.ParentHashes, h)
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return scanParents, nil
|
||||
}
|
||||
s.pushBack(line, err)
|
||||
return scanAuthor, nil
|
||||
}
|
||||
|
||||
// scanAuthor accepts an `author` line at its canonical position immediately
|
||||
// after the parent block. Any other header here is pushed back for
|
||||
// scanCommitter; an out-of-place author is therefore silently dropped.
|
||||
// Mirrors upstream's parse_commit_date func.
|
||||
func scanAuthor(s *commitScanner) (commitState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if isBlankLine(line) {
|
||||
return scanMessage, nil
|
||||
}
|
||||
|
||||
key, data := splitHeader(line)
|
||||
if key == "author" {
|
||||
s.c.Author.Decode(data)
|
||||
s.sawAuthor = true
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return scanCommitter, nil
|
||||
}
|
||||
s.pushBack(line, err)
|
||||
return scanCommitter, nil
|
||||
}
|
||||
|
||||
// scanCommitter accepts a `committer` line at its canonical position
|
||||
// immediately after the author. Any other header is pushed back for
|
||||
// scanHeaders. Same upstream rationale as scanAuthor.
|
||||
func scanCommitter(s *commitScanner) (commitState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if isBlankLine(line) {
|
||||
return scanMessage, nil
|
||||
}
|
||||
|
||||
key, data := splitHeader(line)
|
||||
if key == "committer" {
|
||||
s.c.Committer.Decode(data)
|
||||
s.sawCommitter = true
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return scanHeaders, nil
|
||||
}
|
||||
s.pushBack(line, err)
|
||||
return scanHeaders, nil
|
||||
}
|
||||
|
||||
// scanHeaders dispatches one header line. Continuation-bearing headers
|
||||
// (mergetag, gpgsig, gpgsig-sha256, and unknown extras whose value is
|
||||
// continued on subsequent lines) hand off to a dedicated continuation state
|
||||
// that handles the `<space>...` lines and then returns here.
|
||||
func scanHeaders(s *commitScanner) (commitState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if isBlankLine(line) {
|
||||
return scanMessage, nil
|
||||
}
|
||||
|
||||
originalLine := line
|
||||
key, data := splitHeader(line)
|
||||
|
||||
var next commitState = scanHeaders
|
||||
switch key {
|
||||
case "tree", "parent", "author", "committer":
|
||||
// Anything reaching scanHeaders with one of these keys is out of
|
||||
// canonical position: duplicate tree, parent past the contiguous
|
||||
// block, or author/committer not at their expected slot. Drop them
|
||||
// the same way upstream's standard_header_field filter excludes
|
||||
// them from the extras list (read_commit_extra_header_lines,
|
||||
// commit.c:1520-1522).
|
||||
case headerencoding:
|
||||
if !s.sawEncoding {
|
||||
s.c.Encoding = MessageEncoding(data)
|
||||
s.sawEncoding = true
|
||||
}
|
||||
case headermergetag:
|
||||
if s.sawMergetag {
|
||||
next = scanSkipCont
|
||||
} else {
|
||||
s.c.MergeTag += string(data) + "\n"
|
||||
s.sawMergetag = true
|
||||
next = scanMergetagCont
|
||||
}
|
||||
case headerpgp:
|
||||
s.c.PGPSignature += string(data) + "\n"
|
||||
next = scanPgpCont
|
||||
case headerpgp256:
|
||||
next = scanSkipCont
|
||||
default:
|
||||
h, multiline := parseExtraHeader(originalLine)
|
||||
if multiline {
|
||||
s.extra = &h
|
||||
next = scanExtraCont
|
||||
} else {
|
||||
s.c.ExtraHeaders = append(s.c.ExtraHeaders, h)
|
||||
}
|
||||
}
|
||||
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return next, nil
|
||||
}
|
||||
|
||||
// scanMergetagCont accumulates continuation lines for the first mergetag
|
||||
// header. Continuations strip exactly one leading space, mirroring upstream's
|
||||
// `line + 1` (commit.c:1509). The first non-continuation line is pushed back
|
||||
// so scanHeaders can dispatch it.
|
||||
func scanMergetagCont(s *commitScanner) (commitState, error) {
|
||||
return continuationCont(s, &s.c.MergeTag, scanMergetagCont)
|
||||
}
|
||||
|
||||
// scanPgpCont accumulates continuation lines for a signature header.
|
||||
// Continuations strip exactly one leading space, mirroring upstream's
|
||||
// `line + 1` (commit.c:1509). The first non-continuation line is pushed back
|
||||
// so scanHeaders can dispatch it. Repeat occurrences of the same signature
|
||||
// header land back here and concatenate, matching upstream's
|
||||
// parse_buffer_signed_by_header (commit.c:1186).
|
||||
func scanPgpCont(s *commitScanner) (commitState, error) {
|
||||
return continuationCont(s, &s.c.PGPSignature, scanPgpCont)
|
||||
}
|
||||
|
||||
func continuationCont(s *commitScanner, dst *string, self commitState) (commitState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) > 0 && line[0] == ' ' {
|
||||
*dst += string(line[1:])
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return self, nil
|
||||
}
|
||||
if len(line) > 0 {
|
||||
s.pushBack(line, err)
|
||||
}
|
||||
return scanHeaders, nil
|
||||
}
|
||||
|
||||
// scanSkipCont discards continuation lines that belong to a header scanHeaders
|
||||
// chose to drop.
|
||||
func scanSkipCont(s *commitScanner) (commitState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) > 0 && line[0] == ' ' {
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return scanSkipCont, nil
|
||||
}
|
||||
if len(line) > 0 {
|
||||
s.pushBack(line, err)
|
||||
}
|
||||
return scanHeaders, nil
|
||||
}
|
||||
|
||||
// scanExtraCont accumulates continuation lines for an unknown ExtraHeader
|
||||
// whose value spans multiple lines, then finalises the entry once the
|
||||
// continuation block ends.
|
||||
func scanExtraCont(s *commitScanner) (commitState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) > 0 && line[0] == ' ' {
|
||||
s.extra.Value += string(line[1:])
|
||||
if err == io.EOF {
|
||||
s.finaliseExtra()
|
||||
return nil, nil
|
||||
}
|
||||
return scanExtraCont, nil
|
||||
}
|
||||
s.finaliseExtra()
|
||||
if len(line) > 0 {
|
||||
s.pushBack(line, err)
|
||||
}
|
||||
return scanHeaders, nil
|
||||
}
|
||||
|
||||
func (s *commitScanner) finaliseExtra() {
|
||||
s.extra.Value = strings.TrimRight(s.extra.Value, "\n")
|
||||
s.c.ExtraHeaders = append(s.c.ExtraHeaders, *s.extra)
|
||||
s.extra = nil
|
||||
}
|
||||
|
||||
// scanMessage drains the remaining bytes into the message buffer.
|
||||
func scanMessage(s *commitScanner) (commitState, error) {
|
||||
for {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) > 0 {
|
||||
s.msgbuf.Write(line)
|
||||
}
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isBlankLine reports whether line is the canonical header/body separator:
|
||||
// a single newline. Mirrors upstream's `*line == '\n'` test in
|
||||
// read_commit_extra_header_lines (commit.c:1502).
|
||||
func isBlankLine(line []byte) bool {
|
||||
return len(line) == 1 && line[0] == '\n'
|
||||
}
|
||||
|
||||
// splitHeader returns the header keyword (everything before the first space)
|
||||
// and the value (everything after, with the trailing newline stripped). If
|
||||
// the header has no value the returned data is nil.
|
||||
func splitHeader(line []byte) (string, []byte) {
|
||||
trimmed := bytes.TrimRight(line, "\n")
|
||||
key, value, ok := bytes.Cut(trimmed, []byte{' '})
|
||||
if !ok {
|
||||
return string(trimmed), nil
|
||||
}
|
||||
return string(key), value
|
||||
}
|
||||
|
||||
func parseObjectIDHex(data []byte, malformedErr error, header string) (plumbing.Hash, error) {
|
||||
id := string(data)
|
||||
if !plumbing.IsHash(id) {
|
||||
return plumbing.ZeroHash, fmt.Errorf("%w: bad %s hash", malformedErr, header)
|
||||
}
|
||||
return plumbing.NewHash(id), nil
|
||||
}
|
||||
122
vendor/github.com/go-git/go-git/v5/plumbing/object/signature.go
generated
vendored
122
vendor/github.com/go-git/go-git/v5/plumbing/object/signature.go
generated
vendored
@ -1,6 +1,13 @@
|
||||
package object
|
||||
|
||||
import "bytes"
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/utils/ioutil"
|
||||
"github.com/go-git/go-git/v5/utils/sync"
|
||||
)
|
||||
|
||||
const (
|
||||
signatureTypeUnknown signatureType = iota
|
||||
@ -100,3 +107,116 @@ func parseSignedBytes(b []byte) (int, signatureType) {
|
||||
}
|
||||
return match, t
|
||||
}
|
||||
|
||||
// countSignatureBlocks reports how many distinct armored signature blocks
|
||||
// start at a line boundary in b. Used by verification paths to reject
|
||||
// multi-signature payloads, matching upstream's check in gpg-interface.c
|
||||
// where parse_gpg_output bails out the first time it sees a second
|
||||
// exclusive status line (a second GOODSIG/BADSIG/etc.).
|
||||
func countSignatureBlocks(b []byte) int {
|
||||
n, count := 0, 0
|
||||
for n < len(b) {
|
||||
i := b[n:]
|
||||
if typeForSignature(i) != signatureTypeUnknown {
|
||||
count++
|
||||
}
|
||||
if eol := bytes.IndexByte(i, '\n'); eol >= 0 {
|
||||
n += eol + 1
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// isSignatureHeader reports whether line is a canonical "gpgsig "/
|
||||
// "gpgsig-sha256 " header line. Other "gpgsig"-prefixed extra headers
|
||||
// are intentionally not matched.
|
||||
func isSignatureHeader(line []byte) bool {
|
||||
return bytes.HasPrefix(line, []byte(headerpgp+" ")) ||
|
||||
bytes.HasPrefix(line, []byte(headerpgp256+" "))
|
||||
}
|
||||
|
||||
// stripObjectSignatures streams src into dst, producing the byte sequence
|
||||
// over which a PGP/GPG signature is computed:
|
||||
//
|
||||
// - Canonical "gpgsig" and "gpgsig-sha256" headers (and their
|
||||
// continuation lines) are dropped, mirroring upstream's
|
||||
// remove_signature in commit.c.
|
||||
// - For tag objects, the inline trailing PGP signature is additionally
|
||||
// truncated, mirroring upstream's parse_signature in gpg-interface.c
|
||||
// used by gpg_verify_tag.
|
||||
//
|
||||
// The returned object's type is set to objType. Used by both
|
||||
// Commit.EncodeWithoutSignature and Tag.EncodeWithoutSignature to
|
||||
// reproduce the exact bytes the signature was computed over.
|
||||
func stripObjectSignatures(dst, src plumbing.EncodedObject, objType plumbing.ObjectType) (err error) {
|
||||
dst.SetType(objType)
|
||||
|
||||
r, err := src.Reader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ioutil.CheckClose(r, &err)
|
||||
|
||||
var input io.Reader = r
|
||||
if objType == plumbing.TagObject {
|
||||
raw, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sm, _ := parseSignedBytes(raw); sm >= 0 {
|
||||
raw = raw[:sm]
|
||||
}
|
||||
input = bytes.NewReader(raw)
|
||||
}
|
||||
|
||||
w, err := dst.Writer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ioutil.CheckClose(w, &err)
|
||||
|
||||
return stripHeaderSignatures(w, input)
|
||||
}
|
||||
|
||||
// stripHeaderSignatures copies r to w, dropping canonical signature header
|
||||
// lines (gpgsig and gpgsig-sha256) and their continuation lines. Lines
|
||||
// past the blank line that closes the header block are copied verbatim.
|
||||
func stripHeaderSignatures(w io.Writer, r io.Reader) error {
|
||||
br := sync.GetBufioReader(r)
|
||||
defer sync.PutBufioReader(br)
|
||||
|
||||
var inBody, skipping bool
|
||||
for {
|
||||
line, rerr := br.ReadBytes('\n')
|
||||
if rerr != nil && rerr != io.EOF {
|
||||
return rerr
|
||||
}
|
||||
|
||||
write := true
|
||||
if !inBody {
|
||||
switch {
|
||||
case skipping && len(line) > 0 && line[0] == ' ':
|
||||
write = false
|
||||
case isSignatureHeader(line):
|
||||
skipping = true
|
||||
write = false
|
||||
case len(line) == 1 && line[0] == '\n':
|
||||
skipping = false
|
||||
inBody = true
|
||||
default:
|
||||
skipping = false
|
||||
}
|
||||
}
|
||||
|
||||
if write && len(line) > 0 {
|
||||
if _, werr := w.Write(line); werr != nil {
|
||||
return werr
|
||||
}
|
||||
}
|
||||
if rerr == io.EOF {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
135
vendor/github.com/go-git/go-git/v5/plumbing/object/tag.go
generated
vendored
135
vendor/github.com/go-git/go-git/v5/plumbing/object/tag.go
generated
vendored
@ -1,9 +1,8 @@
|
||||
package object
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
@ -13,6 +12,10 @@ import (
|
||||
"github.com/go-git/go-git/v5/utils/sync"
|
||||
)
|
||||
|
||||
// ErrMalformedTag is returned when a tag object cannot be decoded because
|
||||
// its required headers (object, type, tag) are missing or out of order.
|
||||
var ErrMalformedTag = errors.New("malformed tag")
|
||||
|
||||
// Tag represents an annotated tag object. It points to a single git object of
|
||||
// any type, but tags typically are applied to commit or blob objects. It
|
||||
// provides a reference that associates the target with a tag name. It also
|
||||
@ -39,6 +42,9 @@ type Tag struct {
|
||||
Target plumbing.Hash
|
||||
|
||||
s storer.EncodedObjectStorer
|
||||
// src holds the encoded object this Tag was decoded from, used by
|
||||
// EncodeWithoutSignature to recover the canonical signed bytes.
|
||||
src plumbing.EncodedObject
|
||||
}
|
||||
|
||||
// GetTag gets a tag from an object storer and decodes it.
|
||||
@ -77,13 +83,20 @@ func (t *Tag) Type() plumbing.ObjectType {
|
||||
return plumbing.TagObject
|
||||
}
|
||||
|
||||
func (t *Tag) reset() {
|
||||
storer := t.s
|
||||
*t = Tag{s: storer}
|
||||
}
|
||||
|
||||
// Decode transforms a plumbing.EncodedObject into a Tag struct.
|
||||
func (t *Tag) Decode(o plumbing.EncodedObject) (err error) {
|
||||
if o.Type() != plumbing.TagObject {
|
||||
return ErrUnsupportedObject
|
||||
}
|
||||
|
||||
t.reset()
|
||||
t.Hash = o.Hash()
|
||||
t.src = o
|
||||
|
||||
reader, err := o.Reader()
|
||||
if err != nil {
|
||||
@ -94,42 +107,15 @@ func (t *Tag) Decode(o plumbing.EncodedObject) (err error) {
|
||||
r := sync.GetBufioReader(reader)
|
||||
defer sync.PutBufioReader(r)
|
||||
|
||||
for {
|
||||
var line []byte
|
||||
line, err = r.ReadBytes('\n')
|
||||
if err != nil && err != io.EOF {
|
||||
scanner := &tagScanner{r: r, t: t}
|
||||
for state := scanTagObject; state != nil; {
|
||||
state, err = state(scanner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
break // Start of message
|
||||
}
|
||||
|
||||
split := bytes.SplitN(line, []byte{' '}, 2)
|
||||
switch string(split[0]) {
|
||||
case "object":
|
||||
t.Target = plumbing.NewHash(string(split[1]))
|
||||
case "type":
|
||||
t.TargetType, err = plumbing.ParseObjectType(string(split[1]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "tag":
|
||||
t.Name = string(split[1])
|
||||
case "tagger":
|
||||
t.Tagger.Decode(split[1])
|
||||
}
|
||||
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data := scanner.msgbuf.Bytes()
|
||||
if sm, _ := parseSignedBytes(data); sm >= 0 {
|
||||
t.PGPSignature = string(data[sm:])
|
||||
data = data[:sm]
|
||||
@ -144,11 +130,54 @@ func (t *Tag) Encode(o plumbing.EncodedObject) error {
|
||||
return t.encode(o, true)
|
||||
}
|
||||
|
||||
// EncodeWithoutSignature export a Tag into a plumbing.EncodedObject without the signature (correspond to the payload of the PGP signature).
|
||||
// EncodeWithoutSignature exports a Tag into a plumbing.EncodedObject without
|
||||
// any signature data, producing the payload that PGP/GPG signatures are
|
||||
// computed over.
|
||||
//
|
||||
// Behaviour mirrors Commit.EncodeWithoutSignature:
|
||||
//
|
||||
// - For Tags populated by Decode whose exported fields still match the
|
||||
// source object, the payload is streamed from the raw source bytes with
|
||||
// the inline trailing signature truncated and gpgsig/gpgsig-sha256
|
||||
// headers (and their continuation lines) stripped verbatim. This
|
||||
// preserves the exact bytes the signature was computed over, regardless
|
||||
// of any normalization performed by Decode.
|
||||
//
|
||||
// - For Tags constructed in memory, or for decoded Tags whose exported
|
||||
// fields have been mutated, the payload is derived from the current
|
||||
// struct fields. Mutation is detected by re-decoding the source object
|
||||
// and comparing exported fields; if any differ, the in-memory
|
||||
// representation prevails.
|
||||
func (t *Tag) EncodeWithoutSignature(o plumbing.EncodedObject) error {
|
||||
if t.matchesSource() {
|
||||
return stripObjectSignatures(o, t.src, plumbing.TagObject)
|
||||
}
|
||||
return t.encode(o, false)
|
||||
}
|
||||
|
||||
// matchesSource reports whether t.src is set and re-decoding it produces a
|
||||
// Tag whose payload-affecting exported fields are identical to those of t.
|
||||
//
|
||||
// PGPSignature is intentionally excluded from the comparison: neither path
|
||||
// emits it as part of the verification payload, so mutating it must not
|
||||
// trigger a switch to struct-encode (which would change the byte layout the
|
||||
// caller is trying to verify against).
|
||||
func (t *Tag) matchesSource() bool {
|
||||
if t.src == nil {
|
||||
return false
|
||||
}
|
||||
fresh := &Tag{}
|
||||
if err := fresh.Decode(t.src); err != nil {
|
||||
return false
|
||||
}
|
||||
return t.Hash == fresh.Hash &&
|
||||
t.Name == fresh.Name &&
|
||||
signatureEqual(t.Tagger, fresh.Tagger) &&
|
||||
t.Message == fresh.Message &&
|
||||
t.TargetType == fresh.TargetType &&
|
||||
t.Target == fresh.Target
|
||||
}
|
||||
|
||||
func (t *Tag) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
|
||||
o.SetType(plumbing.TagObject)
|
||||
w, err := o.Writer()
|
||||
@ -158,16 +187,26 @@ func (t *Tag) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
|
||||
defer ioutil.CheckClose(w, &err)
|
||||
|
||||
if _, err = fmt.Fprintf(w,
|
||||
"object %s\ntype %s\ntag %s\ntagger ",
|
||||
"object %s\ntype %s\ntag %s\n",
|
||||
t.Target.String(), t.TargetType.Bytes(), t.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = t.Tagger.Encode(w); err != nil {
|
||||
return err
|
||||
if !isZeroSignature(t.Tagger) {
|
||||
if _, err = fmt.Fprint(w, "tagger "); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = t.Tagger.Encode(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = fmt.Fprint(w, "\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = fmt.Fprint(w, "\n\n"); err != nil {
|
||||
if _, err = fmt.Fprint(w, "\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -175,11 +214,12 @@ func (t *Tag) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Note that this is highly sensitive to what it sent along in the message.
|
||||
// Message *always* needs to end with a newline, or else the message and the
|
||||
// signature will be concatenated into a corrupt object. Since this is a
|
||||
// lower-level method, we assume you know what you are doing and have already
|
||||
// done the needful on the message in the caller.
|
||||
// Note that this is highly sensitive to what is sent along in the
|
||||
// message. Message *always* needs to end with a newline, or else the
|
||||
// message and the trailing signature will be concatenated into a
|
||||
// corrupt object. Since this is a lower-level method, we assume you
|
||||
// know what you are doing and have already done the needful on the
|
||||
// message in the caller.
|
||||
if includeSig {
|
||||
if _, err = fmt.Fprint(w, t.PGPSignature); err != nil {
|
||||
return err
|
||||
@ -189,6 +229,10 @@ func (t *Tag) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func isZeroSignature(s Signature) bool {
|
||||
return s.Name == "" && s.Email == "" && s.When.IsZero()
|
||||
}
|
||||
|
||||
// Commit returns the commit pointed to by the tag. If the tag points to a
|
||||
// different type of object ErrUnsupportedObject will be returned.
|
||||
func (t *Tag) Commit() (*Commit, error) {
|
||||
@ -256,7 +300,8 @@ func (t *Tag) String() string {
|
||||
}
|
||||
|
||||
// Verify performs PGP verification of the tag with a provided armored
|
||||
// keyring and returns openpgp.Entity associated with verifying key on success.
|
||||
// keyring and returns openpgp.Entity associated with verifying key on
|
||||
// success.
|
||||
func (t *Tag) Verify(armoredKeyRing string) (*openpgp.Entity, error) {
|
||||
keyRingReader := strings.NewReader(armoredKeyRing)
|
||||
keyring, err := openpgp.ReadArmoredKeyRing(keyRingReader)
|
||||
|
||||
237
vendor/github.com/go-git/go-git/v5/plumbing/object/tag_scanner.go
generated
vendored
Normal file
237
vendor/github.com/go-git/go-git/v5/plumbing/object/tag_scanner.go
generated
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
package object
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
// tagScanner holds the working state of the tag decoder driven by the
|
||||
// stateFn loop in (*Tag).Decode. Each tagState reads one or more lines
|
||||
// from r, updates the in-progress *Tag and the scanner's bookkeeping,
|
||||
// and returns the state that should run next (or nil to stop).
|
||||
type tagScanner struct {
|
||||
r *bufio.Reader
|
||||
t *Tag
|
||||
msgbuf bytes.Buffer
|
||||
|
||||
// pending holds a line that was read but the current state decided to
|
||||
// hand back to the next state, paired with the io.EOF flag returned
|
||||
// when the line was originally read.
|
||||
pending []byte
|
||||
pendingErr error
|
||||
|
||||
// First-occurrence tracking: once the corresponding canonical
|
||||
// header has been decoded at its expected position, subsequent
|
||||
// occurrences (or out-of-position lines) are silently dropped,
|
||||
// matching the strict layout enforced by upstream's
|
||||
// parse_tag_buffer (tag.c:130).
|
||||
//
|
||||
// gpgsig-sha256 is recognized and skipped without exposing a new field
|
||||
// in v5.
|
||||
sawObject, sawType, sawName, sawTagger bool
|
||||
}
|
||||
|
||||
// tagState is one step of the decoder state machine. Each function reads
|
||||
// the lines it needs, mutates *Tag via s.t, and returns the next state
|
||||
// to run (or nil to terminate the loop).
|
||||
type tagState func(*tagScanner) (tagState, error)
|
||||
|
||||
// readLine returns the next line from the buffer, transparently
|
||||
// consuming any line that was previously pushed back by a state that
|
||||
// decided not to handle it.
|
||||
func (s *tagScanner) readLine() ([]byte, error) {
|
||||
if s.pending != nil {
|
||||
line, err := s.pending, s.pendingErr
|
||||
s.pending, s.pendingErr = nil, nil
|
||||
return line, err
|
||||
}
|
||||
return s.r.ReadBytes('\n')
|
||||
}
|
||||
|
||||
// pushBack stashes an unconsumed line so the next state's readLine call
|
||||
// sees it. Only one line can be pushed back at a time.
|
||||
func (s *tagScanner) pushBack(line []byte, err error) {
|
||||
s.pending = line
|
||||
s.pendingErr = err
|
||||
}
|
||||
|
||||
// scanTagObject requires the first line to be `object HASH`, mirroring
|
||||
// upstream's strict parse_tag_buffer (tag.c:151-156). Anything else
|
||||
// returns ErrMalformedTag.
|
||||
func scanTagObject(s *tagScanner) (tagState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 || isBlankLine(line) {
|
||||
return nil, fmt.Errorf("%w: missing object header", ErrMalformedTag)
|
||||
}
|
||||
|
||||
key, data := splitHeader(line)
|
||||
if key != "object" {
|
||||
return nil, fmt.Errorf("%w: object header must be first", ErrMalformedTag)
|
||||
}
|
||||
h, herr := parseObjectIDHex(data, ErrMalformedTag, "object")
|
||||
if herr != nil {
|
||||
return nil, herr
|
||||
}
|
||||
s.t.Target = h
|
||||
s.sawObject = true
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return scanTagType, nil
|
||||
}
|
||||
|
||||
// scanTagType requires a `type` line immediately after the object header,
|
||||
// mirroring upstream's parse_tag_buffer (tag.c:158-166).
|
||||
func scanTagType(s *tagScanner) (tagState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 || isBlankLine(line) {
|
||||
return nil, fmt.Errorf("%w: missing type header", ErrMalformedTag)
|
||||
}
|
||||
|
||||
key, data := splitHeader(line)
|
||||
if key != "type" {
|
||||
return nil, fmt.Errorf("%w: type header must follow object", ErrMalformedTag)
|
||||
}
|
||||
ot, perr := plumbing.ParseObjectType(string(data))
|
||||
if perr != nil {
|
||||
return nil, perr
|
||||
}
|
||||
s.t.TargetType = ot
|
||||
s.sawType = true
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return scanTagName, nil
|
||||
}
|
||||
|
||||
// scanTagName requires a `tag` line immediately after the type header,
|
||||
// mirroring upstream's parse_tag_buffer (tag.c:186-194).
|
||||
func scanTagName(s *tagScanner) (tagState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 || isBlankLine(line) {
|
||||
return nil, fmt.Errorf("%w: missing tag header", ErrMalformedTag)
|
||||
}
|
||||
|
||||
key, data := splitHeader(line)
|
||||
if key != "tag" {
|
||||
return nil, fmt.Errorf("%w: tag header must follow type", ErrMalformedTag)
|
||||
}
|
||||
s.t.Name = string(data)
|
||||
s.sawName = true
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return scanTagTagger, nil
|
||||
}
|
||||
|
||||
// scanTagTagger accepts a `tagger` line at its canonical position. Any
|
||||
// other header is pushed back for scanTagHeaders.
|
||||
func scanTagTagger(s *tagScanner) (tagState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if isBlankLine(line) {
|
||||
return scanTagMessage, nil
|
||||
}
|
||||
|
||||
key, data := splitHeader(line)
|
||||
if key == "tagger" {
|
||||
s.t.Tagger.Decode(data)
|
||||
s.sawTagger = true
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return scanTagHeaders, nil
|
||||
}
|
||||
s.pushBack(line, err)
|
||||
return scanTagHeaders, nil
|
||||
}
|
||||
|
||||
// scanTagHeaders dispatches one header line. gpgsig-sha256 hands off to
|
||||
// scanTagSkipCont so the continuation block can be consumed; out-of-position
|
||||
// canonical fields and unknown headers are silently dropped.
|
||||
func scanTagHeaders(s *tagScanner) (tagState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if isBlankLine(line) {
|
||||
return scanTagMessage, nil
|
||||
}
|
||||
|
||||
key, _ := splitHeader(line)
|
||||
next := scanTagHeaders
|
||||
switch key {
|
||||
case "object", "type", "tag", "tagger":
|
||||
// Out-of-canonical-position duplicates are dropped, mirroring the
|
||||
// strict ordering of upstream's parse_tag_buffer.
|
||||
case headerpgp256:
|
||||
next = scanTagSkipCont
|
||||
default:
|
||||
// Unknown header: silently dropped (the Tag struct does not
|
||||
// expose ExtraHeaders).
|
||||
}
|
||||
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return next, nil
|
||||
}
|
||||
|
||||
// scanTagSkipCont discards continuation lines for a header scanTagHeaders chose
|
||||
// to drop. The first non-continuation line is pushed back so scanTagHeaders can
|
||||
// dispatch it.
|
||||
func scanTagSkipCont(s *tagScanner) (tagState, error) {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) > 0 && line[0] == ' ' {
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return scanTagSkipCont, nil
|
||||
}
|
||||
if len(line) > 0 {
|
||||
s.pushBack(line, err)
|
||||
}
|
||||
return scanTagHeaders, nil
|
||||
}
|
||||
|
||||
// scanTagMessage drains the remaining bytes into the message buffer.
|
||||
// (*Tag).Decode then runs parseSignedBytes over those bytes to peel off
|
||||
// the optional inline trailing PGP signature.
|
||||
func scanTagMessage(s *tagScanner) (tagState, error) {
|
||||
for {
|
||||
line, err := s.readLine()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) > 0 {
|
||||
s.msgbuf.Write(line)
|
||||
}
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
151
vendor/github.com/go-git/go-git/v5/plumbing/object/tree.go
generated
vendored
151
vendor/github.com/go-git/go-git/v5/plumbing/object/tree.go
generated
vendored
@ -10,6 +10,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5/internal/pathutil"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/filemode"
|
||||
"github.com/go-git/go-git/v5/plumbing/storer"
|
||||
@ -29,6 +30,7 @@ var (
|
||||
ErrDirectoryNotFound = errors.New("directory not found")
|
||||
ErrEntryNotFound = errors.New("entry not found")
|
||||
ErrEntriesNotSorted = errors.New("entries in tree are not sorted")
|
||||
ErrMalformedTree = errors.New("malformed tree")
|
||||
)
|
||||
|
||||
// Tree is basically like a directory - it references a bunch of other trees
|
||||
@ -37,9 +39,9 @@ type Tree struct {
|
||||
Entries []TreeEntry
|
||||
Hash plumbing.Hash
|
||||
|
||||
s storer.EncodedObjectStorer
|
||||
m map[string]*TreeEntry
|
||||
t map[string]*Tree // tree path cache
|
||||
s storer.EncodedObjectStorer
|
||||
t map[string]*Tree // tree path cache
|
||||
entriesSorted bool
|
||||
}
|
||||
|
||||
// GetTree gets a tree from an object storer and decodes it.
|
||||
@ -117,7 +119,16 @@ func (t *Tree) Tree(path string) (*Tree, error) {
|
||||
}
|
||||
|
||||
// TreeEntryFile returns the *File for a given *TreeEntry.
|
||||
//
|
||||
// The entry's name is validated against pathutil.ValidTreePath for
|
||||
// the same reason FindEntry validates: TreeEntryFile is a boundary
|
||||
// where attacker-controlled tree data leaves the trusted store as a
|
||||
// *File whose Name a caller can hand to filesystem ops.
|
||||
func (t *Tree) TreeEntryFile(e *TreeEntry) (*File, error) {
|
||||
if err := pathutil.ValidTreePath(e.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blob, err := GetBlob(t.s, e.Hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -127,7 +138,16 @@ func (t *Tree) TreeEntryFile(e *TreeEntry) (*File, error) {
|
||||
}
|
||||
|
||||
// FindEntry search a TreeEntry in this tree or any subtree.
|
||||
//
|
||||
// The lookup path is validated against pathutil.ValidTreePath to
|
||||
// prevent attacker-controlled tree contents from leaking past this
|
||||
// boundary as `.git`-shaped or path-traversal-shaped names. Callers
|
||||
// that legitimately need to look up unsafe paths should walk the
|
||||
// tree manually.
|
||||
func (t *Tree) FindEntry(path string) (*TreeEntry, error) {
|
||||
if err := pathutil.ValidTreePath(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if t.t == nil {
|
||||
t.t = make(map[string]*Tree)
|
||||
}
|
||||
@ -182,16 +202,43 @@ func (t *Tree) dir(baseName string) (*Tree, error) {
|
||||
}
|
||||
|
||||
func (t *Tree) entry(baseName string) (*TreeEntry, error) {
|
||||
if t.m == nil {
|
||||
t.buildMap()
|
||||
}
|
||||
|
||||
entry, ok := t.m[baseName]
|
||||
if !ok {
|
||||
if t.entriesSorted {
|
||||
if entry := t.searchEntry(baseName); entry != nil {
|
||||
return entry, nil
|
||||
}
|
||||
return nil, ErrEntryNotFound
|
||||
}
|
||||
|
||||
return entry, nil
|
||||
pastName := baseName + "/"
|
||||
for i := range t.Entries {
|
||||
entry := &t.Entries[i]
|
||||
if entry.Name == baseName {
|
||||
return entry, nil
|
||||
}
|
||||
if treeEntrySortName(entry) > pastName {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrEntryNotFound
|
||||
}
|
||||
|
||||
func (t *Tree) searchEntry(baseName string) *TreeEntry {
|
||||
if i := t.searchEntryIndex(baseName); i < len(t.Entries) && t.Entries[i].Name == baseName {
|
||||
return &t.Entries[i]
|
||||
}
|
||||
|
||||
if i := t.searchEntryIndex(baseName + "/"); i < len(t.Entries) && t.Entries[i].Name == baseName {
|
||||
return &t.Entries[i]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tree) searchEntryIndex(name string) int {
|
||||
return sort.Search(len(t.Entries), func(i int) bool {
|
||||
return treeEntrySortName(&t.Entries[i]) >= name
|
||||
})
|
||||
}
|
||||
|
||||
// Files returns a FileIter allowing to iterate over the Tree
|
||||
@ -212,20 +259,25 @@ func (t *Tree) Type() plumbing.ObjectType {
|
||||
return plumbing.TreeObject
|
||||
}
|
||||
|
||||
func (t *Tree) reset() {
|
||||
storer := t.s
|
||||
*t = Tree{s: storer}
|
||||
}
|
||||
|
||||
// Decode transform an plumbing.EncodedObject into a Tree struct
|
||||
func (t *Tree) Decode(o plumbing.EncodedObject) (err error) {
|
||||
if o.Type() != plumbing.TreeObject {
|
||||
return ErrUnsupportedObject
|
||||
}
|
||||
|
||||
t.reset()
|
||||
t.Hash = o.Hash()
|
||||
// assume tree is sorted as a valid tree should always be sorted.
|
||||
t.entriesSorted = true
|
||||
if o.Size() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
t.Entries = nil
|
||||
t.m = nil
|
||||
|
||||
reader, err := o.Reader()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -235,10 +287,14 @@ func (t *Tree) Decode(o plumbing.EncodedObject) (err error) {
|
||||
r := sync.GetBufioReader(reader)
|
||||
defer sync.PutBufioReader(r)
|
||||
|
||||
var prevSortName string
|
||||
for {
|
||||
str, err := r.ReadString(' ')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
if len(str) != 0 {
|
||||
return fmt.Errorf("%w: missing mode terminator", ErrMalformedTree)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@ -248,25 +304,41 @@ func (t *Tree) Decode(o plumbing.EncodedObject) (err error) {
|
||||
|
||||
mode, err := filemode.New(str)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("%w: malformed mode", ErrMalformedTree)
|
||||
}
|
||||
mode = canonicalTreeMode(mode)
|
||||
|
||||
name, err := r.ReadString(0)
|
||||
if err != nil && err != io.EOF {
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return fmt.Errorf("%w: missing filename terminator", ErrMalformedTree)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if len(name) == 1 {
|
||||
return fmt.Errorf("%w: empty filename", ErrMalformedTree)
|
||||
}
|
||||
|
||||
var hash plumbing.Hash
|
||||
if _, err = io.ReadFull(r, hash[:]); err != nil {
|
||||
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
return fmt.Errorf("%w: truncated object id", ErrMalformedTree)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
baseName := name[:len(name)-1]
|
||||
t.Entries = append(t.Entries, TreeEntry{
|
||||
entry := TreeEntry{
|
||||
Hash: hash,
|
||||
Mode: mode,
|
||||
Name: baseName,
|
||||
})
|
||||
}
|
||||
sortName := treeEntrySortName(&entry)
|
||||
if len(t.Entries) != 0 && prevSortName > sortName {
|
||||
t.entriesSorted = false
|
||||
}
|
||||
prevSortName = sortName
|
||||
t.Entries = append(t.Entries, entry)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -279,21 +351,37 @@ func (s TreeEntrySorter) Len() int {
|
||||
}
|
||||
|
||||
func (s TreeEntrySorter) Less(i, j int) bool {
|
||||
name1 := s[i].Name
|
||||
name2 := s[j].Name
|
||||
if s[i].Mode == filemode.Dir {
|
||||
name1 += "/"
|
||||
}
|
||||
if s[j].Mode == filemode.Dir {
|
||||
name2 += "/"
|
||||
}
|
||||
return name1 < name2
|
||||
return treeEntrySortName(&s[i]) < treeEntrySortName(&s[j])
|
||||
}
|
||||
|
||||
func (s TreeEntrySorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
// Git compares tree entries as if directory names had a trailing slash.
|
||||
func treeEntrySortName(e *TreeEntry) string {
|
||||
if e.Mode == filemode.Dir {
|
||||
return e.Name + "/"
|
||||
}
|
||||
return e.Name
|
||||
}
|
||||
|
||||
func canonicalTreeMode(mode filemode.FileMode) filemode.FileMode {
|
||||
switch mode & 0o170000 {
|
||||
case 0o040000:
|
||||
return filemode.Dir
|
||||
case 0o100000:
|
||||
if mode&0o111 != 0 {
|
||||
return filemode.Executable
|
||||
}
|
||||
return filemode.Regular
|
||||
case 0o120000:
|
||||
return filemode.Symlink
|
||||
default:
|
||||
return filemode.Submodule
|
||||
}
|
||||
}
|
||||
|
||||
// Encode transforms a Tree into a plumbing.EncodedObject.
|
||||
// The tree entries must be sorted by name.
|
||||
func (t *Tree) Encode(o plumbing.EncodedObject) (err error) {
|
||||
@ -329,13 +417,6 @@ func (t *Tree) Encode(o plumbing.EncodedObject) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *Tree) buildMap() {
|
||||
t.m = make(map[string]*TreeEntry)
|
||||
for i := 0; i < len(t.Entries); i++ {
|
||||
t.m[t.Entries[i].Name] = &t.Entries[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Diff returns a list of changes between this tree and the provided one
|
||||
func (t *Tree) Diff(to *Tree) (Changes, error) {
|
||||
return t.DiffContext(context.Background(), to)
|
||||
@ -455,6 +536,10 @@ func (w *TreeWalker) Next() (name string, entry TreeEntry, err error) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := pathutil.ValidTreePath(entry.Name); err != nil {
|
||||
return name, entry, err
|
||||
}
|
||||
|
||||
if entry.Mode == filemode.Dir {
|
||||
obj, err = GetTree(w.s, entry.Hash)
|
||||
}
|
||||
|
||||
168
vendor/github.com/go-git/go-git/v5/plumbing/transport/http/common.go
generated
vendored
168
vendor/github.com/go-git/go-git/v5/plumbing/transport/http/common.go
generated
vendored
@ -7,7 +7,6 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
@ -24,6 +23,33 @@ import (
|
||||
"github.com/go-git/go-git/v5/utils/ioutil"
|
||||
)
|
||||
|
||||
type contextKey int
|
||||
|
||||
const initialRequestKey contextKey = iota
|
||||
|
||||
// RedirectPolicy controls how the HTTP transport follows redirects.
|
||||
//
|
||||
// The values mirror Git's http.followRedirects config:
|
||||
// "true" follows redirects for all requests, "false" treats redirects as
|
||||
// errors, and "initial" follows redirects only for the initial
|
||||
// /info/refs discovery request. The zero value defaults to "initial".
|
||||
type RedirectPolicy string
|
||||
|
||||
const (
|
||||
FollowInitialRedirects RedirectPolicy = "initial"
|
||||
FollowRedirects RedirectPolicy = "true"
|
||||
NoFollowRedirects RedirectPolicy = "false"
|
||||
)
|
||||
|
||||
func withInitialRequest(ctx context.Context) context.Context {
|
||||
return context.WithValue(ctx, initialRequestKey, true)
|
||||
}
|
||||
|
||||
func isInitialRequest(req *http.Request) bool {
|
||||
v, _ := req.Context().Value(initialRequestKey).(bool)
|
||||
return v
|
||||
}
|
||||
|
||||
// it requires a bytes.Buffer, because we need to know the length
|
||||
func applyHeadersToRequest(req *http.Request, content *bytes.Buffer, host string, requestType string) {
|
||||
req.Header.Add("User-Agent", capability.DefaultAgent())
|
||||
@ -54,12 +80,15 @@ func advertisedReferences(ctx context.Context, s *session, serviceName string) (
|
||||
|
||||
s.ApplyAuthToRequest(req)
|
||||
applyHeadersToRequest(req, nil, s.endpoint.Host, serviceName)
|
||||
res, err := s.client.Do(req.WithContext(ctx))
|
||||
res, err := s.client.Do(req.WithContext(withInitialRequest(ctx)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.ModifyEndpointIfRedirect(res)
|
||||
if err := s.ModifyEndpointIfRedirect(res); err != nil {
|
||||
_ = res.Body.Close()
|
||||
return nil, err
|
||||
}
|
||||
defer ioutil.CheckClose(res.Body, &err)
|
||||
|
||||
if err = NewErr(res); err != nil {
|
||||
@ -96,6 +125,7 @@ type client struct {
|
||||
client *http.Client
|
||||
transports *lru.Cache
|
||||
mutex sync.RWMutex
|
||||
follow RedirectPolicy
|
||||
}
|
||||
|
||||
// ClientOptions holds user configurable options for the client.
|
||||
@ -106,6 +136,11 @@ type ClientOptions struct {
|
||||
// size, will result in the least recently used transport getting deleted
|
||||
// before the provided transport is added to the cache.
|
||||
CacheMaxEntries int
|
||||
|
||||
// RedirectPolicy controls redirect handling. Supported values are
|
||||
// "true", "false", and "initial". The zero value defaults to
|
||||
// "initial", matching Git's http.followRedirects default.
|
||||
RedirectPolicy RedirectPolicy
|
||||
}
|
||||
|
||||
var (
|
||||
@ -150,12 +185,16 @@ func NewClientWithOptions(c *http.Client, opts *ClientOptions) transport.Transpo
|
||||
}
|
||||
cl := &client{
|
||||
client: c,
|
||||
follow: FollowInitialRedirects,
|
||||
}
|
||||
|
||||
if opts != nil {
|
||||
if opts.CacheMaxEntries > 0 {
|
||||
cl.transports = lru.New(opts.CacheMaxEntries)
|
||||
}
|
||||
if opts.RedirectPolicy != "" {
|
||||
cl.follow = opts.RedirectPolicy
|
||||
}
|
||||
}
|
||||
return cl
|
||||
}
|
||||
@ -289,14 +328,9 @@ func newSession(c *client, ep *transport.Endpoint, auth transport.AuthMethod) (*
|
||||
}
|
||||
}
|
||||
|
||||
httpClient = &http.Client{
|
||||
Transport: transport,
|
||||
CheckRedirect: c.client.CheckRedirect,
|
||||
Jar: c.client.Jar,
|
||||
Timeout: c.client.Timeout,
|
||||
}
|
||||
httpClient = c.cloneHTTPClient(transport)
|
||||
} else {
|
||||
httpClient = c.client
|
||||
httpClient = c.cloneHTTPClient(c.client.Transport)
|
||||
}
|
||||
|
||||
s := &session{
|
||||
@ -324,30 +358,122 @@ func (s *session) ApplyAuthToRequest(req *http.Request) {
|
||||
s.auth.SetAuth(req)
|
||||
}
|
||||
|
||||
func (s *session) ModifyEndpointIfRedirect(res *http.Response) {
|
||||
func (s *session) ModifyEndpointIfRedirect(res *http.Response) error {
|
||||
if res.Request == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if s.endpoint == nil {
|
||||
return fmt.Errorf("http redirect: nil endpoint")
|
||||
}
|
||||
|
||||
r := res.Request
|
||||
if !strings.HasSuffix(r.URL.Path, infoRefsPath) {
|
||||
return
|
||||
return fmt.Errorf("http redirect: target %q does not end with %s", r.URL.Path, infoRefsPath)
|
||||
}
|
||||
if r.URL.Scheme != "http" && r.URL.Scheme != "https" {
|
||||
return fmt.Errorf("http redirect: unsupported scheme %q", r.URL.Scheme)
|
||||
}
|
||||
if r.URL.Scheme != s.endpoint.Protocol &&
|
||||
!(s.endpoint.Protocol == "http" && r.URL.Scheme == "https") {
|
||||
return fmt.Errorf("http redirect: changes scheme from %q to %q", s.endpoint.Protocol, r.URL.Scheme)
|
||||
}
|
||||
|
||||
h, p, err := net.SplitHostPort(r.URL.Host)
|
||||
host := endpointHost(r.URL.Hostname())
|
||||
port, err := endpointPort(r.URL.Port())
|
||||
if err != nil {
|
||||
h = r.URL.Host
|
||||
return err
|
||||
}
|
||||
if p != "" {
|
||||
port, err := strconv.Atoi(p)
|
||||
if err == nil {
|
||||
s.endpoint.Port = port
|
||||
}
|
||||
|
||||
if host != s.endpoint.Host || effectivePort(r.URL.Scheme, port) != effectivePort(s.endpoint.Protocol, s.endpoint.Port) {
|
||||
s.endpoint.User = ""
|
||||
s.endpoint.Password = ""
|
||||
s.auth = nil
|
||||
}
|
||||
s.endpoint.Host = h
|
||||
|
||||
s.endpoint.Host = host
|
||||
s.endpoint.Port = port
|
||||
|
||||
s.endpoint.Protocol = r.URL.Scheme
|
||||
s.endpoint.Path = r.URL.Path[:len(r.URL.Path)-len(infoRefsPath)]
|
||||
return nil
|
||||
}
|
||||
|
||||
func endpointHost(host string) string {
|
||||
if strings.Contains(host, ":") {
|
||||
return "[" + host + "]"
|
||||
}
|
||||
|
||||
return host
|
||||
}
|
||||
|
||||
func endpointPort(port string) (int, error) {
|
||||
if port == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
parsed, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("http redirect: invalid port %q", port)
|
||||
}
|
||||
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func effectivePort(scheme string, port int) int {
|
||||
if port != 0 {
|
||||
return port
|
||||
}
|
||||
|
||||
switch strings.ToLower(scheme) {
|
||||
case "http":
|
||||
return 80
|
||||
case "https":
|
||||
return 443
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (c *client) cloneHTTPClient(transport http.RoundTripper) *http.Client {
|
||||
return &http.Client{
|
||||
Transport: transport,
|
||||
CheckRedirect: wrapCheckRedirect(c.follow, c.client.CheckRedirect),
|
||||
Jar: c.client.Jar,
|
||||
Timeout: c.client.Timeout,
|
||||
}
|
||||
}
|
||||
|
||||
func wrapCheckRedirect(policy RedirectPolicy, next func(*http.Request, []*http.Request) error) func(*http.Request, []*http.Request) error {
|
||||
return func(req *http.Request, via []*http.Request) error {
|
||||
if err := checkRedirect(req, via, policy); err != nil {
|
||||
return err
|
||||
}
|
||||
if next != nil {
|
||||
return next(req, via)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func checkRedirect(req *http.Request, via []*http.Request, policy RedirectPolicy) error {
|
||||
switch policy {
|
||||
case FollowRedirects:
|
||||
case NoFollowRedirects:
|
||||
return fmt.Errorf("http redirect: redirects disabled to %s", req.URL)
|
||||
case "", FollowInitialRedirects:
|
||||
if !isInitialRequest(req) {
|
||||
return fmt.Errorf("http redirect: redirect on non-initial request to %s", req.URL)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("http redirect: invalid redirect policy %q", policy)
|
||||
}
|
||||
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
|
||||
return fmt.Errorf("http redirect: unsupported scheme %q", req.URL.Scheme)
|
||||
}
|
||||
if len(via) >= 10 {
|
||||
return fmt.Errorf("http redirect: too many redirects")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*session) Close() error {
|
||||
|
||||
34
vendor/github.com/go-git/go-git/v5/plumbing/transport/ssh/common.go
generated
vendored
34
vendor/github.com/go-git/go-git/v5/plumbing/transport/ssh/common.go
generated
vendored
@ -252,7 +252,39 @@ func (c *command) setAuthFromEndpoint() error {
|
||||
}
|
||||
|
||||
func endpointToCommand(cmd string, ep *transport.Endpoint) string {
|
||||
return fmt.Sprintf("%s '%s'", cmd, ep.Path)
|
||||
var b strings.Builder
|
||||
b.WriteString(cmd)
|
||||
b.WriteByte(' ')
|
||||
writeShellQuote(&b, ep.Path)
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// writeShellQuote writes s to b, wrapped in single quotes with
|
||||
// embedded single quotes and exclamation marks escaped using the
|
||||
// POSIX close-escape-reopen idiom:
|
||||
//
|
||||
// ' becomes '\''
|
||||
// ! becomes '\!'
|
||||
//
|
||||
// It is a direct port of canonical Git's sq_quote_buf (quote.c).
|
||||
// The bang escape keeps the result safe when re-evaluated under
|
||||
// csh-derived shells that perform history expansion. The output is
|
||||
// safe to pass as a single argument through any POSIX shell and
|
||||
// round-trips through git-shell's sq_dequote_to_argv.
|
||||
func writeShellQuote(b *strings.Builder, s string) {
|
||||
b.Grow(len(s) + 2)
|
||||
b.WriteByte('\'')
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c == '\'' || c == '!' {
|
||||
b.WriteString(`'\`)
|
||||
b.WriteByte(c)
|
||||
b.WriteByte('\'')
|
||||
continue
|
||||
}
|
||||
b.WriteByte(c)
|
||||
}
|
||||
b.WriteByte('\'')
|
||||
}
|
||||
|
||||
func overrideConfig(overrides *ssh.ClientConfig, c *ssh.ClientConfig) {
|
||||
|
||||
13
vendor/github.com/go-git/go-git/v5/repository.go
generated
vendored
13
vendor/github.com/go-git/go-git/v5/repository.go
generated
vendored
@ -1530,7 +1530,18 @@ func (r *Repository) Worktree() (*Worktree, error) {
|
||||
return nil, ErrIsBareRepository
|
||||
}
|
||||
|
||||
return &Worktree{r: r, Filesystem: r.wt}, nil
|
||||
protectNTFS := defaultProtectNTFS()
|
||||
protectHFS := defaultProtectHFS()
|
||||
if cfg, err := r.Config(); err == nil {
|
||||
if cfg.Core.ProtectNTFS.IsSet() {
|
||||
protectNTFS = cfg.Core.ProtectNTFS.IsTrue()
|
||||
}
|
||||
if cfg.Core.ProtectHFS.IsSet() {
|
||||
protectHFS = cfg.Core.ProtectHFS.IsTrue()
|
||||
}
|
||||
}
|
||||
|
||||
return &Worktree{r: r, Filesystem: newWorktreeFilesystem(r.wt, protectNTFS, protectHFS)}, nil
|
||||
}
|
||||
|
||||
func expand_ref(s storer.ReferenceStorer, ref plumbing.ReferenceName) (*plumbing.Reference, error) {
|
||||
|
||||
19
vendor/github.com/go-git/go-git/v5/storage/filesystem/dotgit/dotgit.go
generated
vendored
19
vendor/github.com/go-git/go-git/v5/storage/filesystem/dotgit/dotgit.go
generated
vendored
@ -75,6 +75,10 @@ var (
|
||||
// ErrEmptyRefFile is returned when a reference file is attempted to be read,
|
||||
// but the file is empty
|
||||
ErrEmptyRefFile = errors.New("ref file is empty")
|
||||
// ErrModuleNameEscape is returned when a submodule name would
|
||||
// resolve outside the modules/ subtree, mirroring canonical Git's
|
||||
// "ignoring suspicious submodule name" defence.
|
||||
ErrModuleNameEscape = errors.New("submodule name escapes modules/ directory")
|
||||
)
|
||||
|
||||
// Options holds configuration for the storage.
|
||||
@ -1127,9 +1131,20 @@ func (d *DotGit) PackRefs() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Module return a billy.Filesystem pointing to the module folder
|
||||
// Module returns a billy.Filesystem pointing to the module folder.
|
||||
//
|
||||
// As a defence in depth against submodule name path traversal,
|
||||
// refuse names whose joined path leaves the modules/ subtree once
|
||||
// cleaned. The config-layer parser also validates submodule names,
|
||||
// but Module may be reached from any caller that constructs a
|
||||
// Submodule struct programmatically and so bypasses the parser.
|
||||
func (d *DotGit) Module(name string) (billy.Filesystem, error) {
|
||||
return d.fs.Chroot(d.fs.Join(modulePath, name))
|
||||
p := d.fs.Join(modulePath, name)
|
||||
cleaned := path.Clean(filepath.ToSlash(p))
|
||||
if cleaned != modulePath && !strings.HasPrefix(cleaned, modulePath+"/") {
|
||||
return nil, ErrModuleNameEscape
|
||||
}
|
||||
return d.fs.Chroot(p)
|
||||
}
|
||||
|
||||
func (d *DotGit) AddAlternate(remote string) error {
|
||||
|
||||
82
vendor/github.com/go-git/go-git/v5/submodule.go
generated
vendored
82
vendor/github.com/go-git/go-git/v5/submodule.go
generated
vendored
@ -6,9 +6,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-git/go-billy/v5"
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
"github.com/go-git/go-git/v5/internal/pathutil"
|
||||
giturl "github.com/go-git/go-git/v5/internal/url"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/format/index"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||
@ -119,6 +122,16 @@ func (s *Submodule) Repository() (*Repository, error) {
|
||||
exists = true
|
||||
}
|
||||
|
||||
// s.c.Path is sourced from the worktree's .gitmodules and is
|
||||
// therefore tree-controlled. Apply the strict tree-path validator
|
||||
// before chroot — the wrapper's tolerant validPath would let a
|
||||
// final-position .git component through (e.g. "submodule/.git"),
|
||||
// which a malicious .gitmodules could use to chroot the submodule
|
||||
// worktree into the repository's actual .git directory.
|
||||
if err := pathutil.ValidTreePath(s.c.Path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var worktree billy.Filesystem
|
||||
if worktree, err = s.w.Filesystem.Chroot(s.c.Path); err != nil {
|
||||
return nil, err
|
||||
@ -138,18 +151,25 @@ func (s *Submodule) Repository() (*Repository, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !path.IsAbs(moduleEndpoint.Path) && moduleEndpoint.Protocol == "file" {
|
||||
remotes, err := s.w.r.Remotes()
|
||||
// A relative submodule URL such as "../X.git" must resolve against
|
||||
// the parent repository's remote URL, not against the process CWD.
|
||||
// Detect relativity from the raw configured URL because
|
||||
// transport.NewEndpoint normalizes local paths to absolute form via
|
||||
// filepath.Abs, which would otherwise mask the relative form here.
|
||||
if giturl.IsLocalEndpoint(s.c.URL) &&
|
||||
!path.IsAbs(s.c.URL) && !filepath.IsAbs(s.c.URL) {
|
||||
|
||||
base, err := defaultRemote(s.w.r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolving relative submodule URL: %w", err)
|
||||
}
|
||||
|
||||
rootEndpoint, err := transport.NewEndpoint(base.URLs[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rootEndpoint, err := transport.NewEndpoint(remotes[0].c.URLs[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rootEndpoint.Path = path.Join(rootEndpoint.Path, moduleEndpoint.Path)
|
||||
rootEndpoint.Path = path.Join(rootEndpoint.Path, s.c.URL)
|
||||
*moduleEndpoint = *rootEndpoint
|
||||
}
|
||||
|
||||
@ -161,6 +181,52 @@ func (s *Submodule) Repository() (*Repository, error) {
|
||||
return r, err
|
||||
}
|
||||
|
||||
// defaultRemote returns the remote that relative submodule URLs are
|
||||
// resolved against, mirroring canonical Git's repo_default_remote
|
||||
// (remote.c) and resolve_relative_url (builtin/submodule--helper.c):
|
||||
//
|
||||
// 1. if HEAD is on a branch with branch.<name>.remote configured,
|
||||
// use that remote;
|
||||
// 2. else if exactly one remote is configured, use it;
|
||||
// 3. otherwise fall back to DefaultRemoteName ("origin").
|
||||
//
|
||||
// Each rule falls through unconditionally: a branch lookup that
|
||||
// finds the branch but with an empty Remote does not short-circuit
|
||||
// rule (2). Returns an error when the chosen remote is not configured.
|
||||
func defaultRemote(r *Repository) (*config.RemoteConfig, error) {
|
||||
cfg, err := r.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ref, err := r.Reference(plumbing.HEAD, false); err == nil &&
|
||||
ref.Type() == plumbing.SymbolicReference &&
|
||||
ref.Target().IsBranch() {
|
||||
if b, ok := cfg.Branches[ref.Target().Short()]; ok && b.Remote != "" {
|
||||
return lookupRemote(cfg, b.Remote)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cfg.Remotes) == 1 {
|
||||
for name := range cfg.Remotes {
|
||||
return lookupRemote(cfg, name)
|
||||
}
|
||||
}
|
||||
|
||||
return lookupRemote(cfg, DefaultRemoteName)
|
||||
}
|
||||
|
||||
func lookupRemote(cfg *config.Config, name string) (*config.RemoteConfig, error) {
|
||||
rc, ok := cfg.Remotes[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("remote %q not found", name)
|
||||
}
|
||||
if len(rc.URLs) == 0 {
|
||||
return nil, fmt.Errorf("remote %q has no configured URL", name)
|
||||
}
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
// Update the registered submodule to match what the superproject expects, the
|
||||
// submodule should be initialized first calling the Init method or setting in
|
||||
// the options SubmoduleUpdateOptions.Init equals true
|
||||
|
||||
15
vendor/github.com/go-git/go-git/v5/utils/binary/read.go
generated
vendored
15
vendor/github.com/go-git/go-git/v5/utils/binary/read.go
generated
vendored
@ -5,11 +5,18 @@ package binary
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
// ErrIntegerOverflow is returned when a Git-format variable-width integer
|
||||
// would not fit into an int64 because the input declares more continuation
|
||||
// bytes than the type can hold.
|
||||
var ErrIntegerOverflow = errors.New("variable-width integer overflow")
|
||||
|
||||
// Read reads structured binary data from r into data. Bytes are read and
|
||||
// decoded in BigEndian order
|
||||
// https://golang.org/pkg/encoding/binary/#Read
|
||||
@ -92,6 +99,14 @@ func ReadVariableWidthInt(r io.Reader) (int64, error) {
|
||||
|
||||
var v = int64(c & maskLength)
|
||||
for c&maskContinue > 0 {
|
||||
// Reject input that, after the v++ and shift below, would
|
||||
// not fit in an int64. With v < (MaxInt64-127)>>7, the
|
||||
// post-increment v is at most (MaxInt64-127)>>7 and the
|
||||
// final (v << 7) + (c & 0x7F) stays within int64.
|
||||
if v >= (math.MaxInt64-int64(maskLength))>>lengthBits {
|
||||
return 0, ErrIntegerOverflow
|
||||
}
|
||||
|
||||
v++
|
||||
if err := Read(r, &c); err != nil {
|
||||
return 0, err
|
||||
|
||||
115
vendor/github.com/go-git/go-git/v5/worktree.go
generated
vendored
115
vendor/github.com/go-git/go-git/v5/worktree.go
generated
vendored
@ -7,7 +7,6 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-billy/v5"
|
||||
@ -458,10 +457,6 @@ func (w *Worktree) resetWorktree(t *object.Tree, files []string) error {
|
||||
|
||||
filesMap := buildFilePathMap(files)
|
||||
for _, ch := range changes {
|
||||
if err := w.validChange(ch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(files) > 0 {
|
||||
file := ""
|
||||
if ch.From != nil {
|
||||
@ -489,108 +484,6 @@ func (w *Worktree) resetWorktree(t *object.Tree, files []string) error {
|
||||
return w.r.Storer.SetIndex(idx)
|
||||
}
|
||||
|
||||
// worktreeDeny is a list of paths that are not allowed
|
||||
// to be used when resetting the worktree.
|
||||
var worktreeDeny = map[string]struct{}{
|
||||
// .git
|
||||
GitDirName: {},
|
||||
|
||||
// For other historical reasons, file names that do not conform to the 8.3
|
||||
// format (up to eight characters for the basename, three for the file
|
||||
// extension, certain characters not allowed such as `+`, etc) are associated
|
||||
// with a so-called "short name", at least on the `C:` drive by default.
|
||||
// Which means that `git~1/` is a valid way to refer to `.git/`.
|
||||
"git~1": {},
|
||||
}
|
||||
|
||||
// validPath checks whether paths are valid.
|
||||
// The rules around invalid paths could differ from upstream based on how
|
||||
// filesystems are managed within go-git, but they are largely the same.
|
||||
//
|
||||
// For upstream rules:
|
||||
// https://github.com/git/git/blob/564d0252ca632e0264ed670534a51d18a689ef5d/read-cache.c#L946
|
||||
// https://github.com/git/git/blob/564d0252ca632e0264ed670534a51d18a689ef5d/path.c#L1383
|
||||
func validPath(paths ...string) error {
|
||||
for _, p := range paths {
|
||||
parts := strings.FieldsFunc(p, func(r rune) bool { return (r == '\\' || r == '/') })
|
||||
if len(parts) == 0 {
|
||||
return fmt.Errorf("invalid path: %q", p)
|
||||
}
|
||||
|
||||
if _, denied := worktreeDeny[strings.ToLower(parts[0])]; denied {
|
||||
return fmt.Errorf("invalid path prefix: %q", p)
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
// Volume names are not supported, in both formats: \\ and <DRIVE_LETTER>:.
|
||||
if vol := filepath.VolumeName(p); vol != "" {
|
||||
return fmt.Errorf("invalid path: %q", p)
|
||||
}
|
||||
|
||||
if !windowsValidPath(parts[0]) {
|
||||
return fmt.Errorf("invalid path: %q", p)
|
||||
}
|
||||
}
|
||||
|
||||
for _, part := range parts {
|
||||
if part == ".." {
|
||||
return fmt.Errorf("invalid path %q: cannot use '..'", p)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// windowsPathReplacer defines the chars that need to be replaced
|
||||
// as part of windowsValidPath.
|
||||
var windowsPathReplacer *strings.Replacer
|
||||
|
||||
func init() {
|
||||
windowsPathReplacer = strings.NewReplacer(" ", "", ".", "")
|
||||
}
|
||||
|
||||
func windowsValidPath(part string) bool {
|
||||
if len(part) > 3 && strings.EqualFold(part[:4], GitDirName) {
|
||||
// For historical reasons, file names that end in spaces or periods are
|
||||
// automatically trimmed. Therefore, `.git . . ./` is a valid way to refer
|
||||
// to `.git/`.
|
||||
if windowsPathReplacer.Replace(part[4:]) == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// For yet other historical reasons, NTFS supports so-called "Alternate Data
|
||||
// Streams", i.e. metadata associated with a given file, referred to via
|
||||
// `<filename>:<stream-name>:<stream-type>`. There exists a default stream
|
||||
// type for directories, allowing `.git/` to be accessed via
|
||||
// `.git::$INDEX_ALLOCATION/`.
|
||||
//
|
||||
// For performance reasons, _all_ Alternate Data Streams of `.git/` are
|
||||
// forbidden, not just `::$INDEX_ALLOCATION`.
|
||||
if len(part) > 4 && part[4:5] == ":" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *Worktree) validChange(ch merkletrie.Change) error {
|
||||
action, err := ch.Action()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch action {
|
||||
case merkletrie.Delete:
|
||||
return validPath(ch.From.String())
|
||||
case merkletrie.Insert:
|
||||
return validPath(ch.To.String())
|
||||
case merkletrie.Modify:
|
||||
return validPath(ch.From.String(), ch.To.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Worktree) checkoutChange(ch merkletrie.Change, t *object.Tree, idx *indexBuilder) error {
|
||||
a, err := ch.Action()
|
||||
if err != nil {
|
||||
@ -763,10 +656,10 @@ func (w *Worktree) checkoutFile(f *object.File) (err error) {
|
||||
}
|
||||
|
||||
func (w *Worktree) checkoutFileSymlink(f *object.File) (err error) {
|
||||
// https://github.com/git/git/commit/10ecfa76491e4923988337b2e2243b05376b40de
|
||||
if strings.EqualFold(f.Name, gitmodulesFile) {
|
||||
return ErrGitModulesSymlink
|
||||
}
|
||||
// .gitmodules symlink rejection (and its NTFS / HFS variants) is
|
||||
// enforced by the worktreeFilesystem wrapper's Symlink method via
|
||||
// validSymlinkName. See https://github.com/git/git/commit/10ecfa7
|
||||
// for the upstream rationale.
|
||||
|
||||
from, err := f.Reader()
|
||||
if err != nil {
|
||||
|
||||
264
vendor/github.com/go-git/go-git/v5/worktree_fs.go
generated
vendored
Normal file
264
vendor/github.com/go-git/go-git/v5/worktree_fs.go
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-billy/v5"
|
||||
|
||||
"github.com/go-git/go-git/v5/internal/pathutil"
|
||||
)
|
||||
|
||||
// defaultProtectHFS returns the default value for core.protectHFS
|
||||
// when not explicitly configured. Matches upstream Git's
|
||||
// PROTECT_HFS_DEFAULT[1], which the Makefile sets to 1 on Darwin
|
||||
// and leaves at 0 on every other platform.
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/config.mak.uname#L146
|
||||
func defaultProtectHFS() bool {
|
||||
return runtime.GOOS == "darwin"
|
||||
}
|
||||
|
||||
// defaultProtectNTFS returns the default value for core.protectNTFS
|
||||
// when not explicitly configured. Matches upstream Git's
|
||||
// PROTECT_NTFS_DEFAULT, which has been 1 on every platform since
|
||||
// 9102f958ee5 (CVE-2019-1353)[1]: WSL allows Linux processes to
|
||||
// reach NTFS-mounted worktrees on Windows hosts, so the
|
||||
// is_ntfs_dotgit guard cannot safely be gated on the runtime OS.
|
||||
//
|
||||
// [1]: https://github.com/git/git/commit/9102f958ee5
|
||||
func defaultProtectNTFS() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// worktreeFilesystem wraps a billy.Filesystem and validates every path passed
|
||||
// to a mutating operation. This prevents writing to, or deleting from,
|
||||
// dangerous locations (e.g. .git/*, ../) regardless of which worktree
|
||||
// code path triggers the operation.
|
||||
type worktreeFilesystem struct {
|
||||
billy.Filesystem
|
||||
protectNTFS bool
|
||||
protectHFS bool
|
||||
}
|
||||
|
||||
func newWorktreeFilesystem(fs billy.Filesystem, protectNTFS, protectHFS bool) *worktreeFilesystem {
|
||||
return &worktreeFilesystem{Filesystem: fs, protectNTFS: protectNTFS, protectHFS: protectHFS}
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) Create(filename string) (billy.File, error) {
|
||||
if err := sfs.validPath(filename); err != nil {
|
||||
return nil, fmt.Errorf("create: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.Create(filename)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) Open(filename string) (billy.File, error) {
|
||||
if err := sfs.validReadPath(filename); err != nil {
|
||||
return nil, fmt.Errorf("open: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.Open(filename)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) {
|
||||
if err := sfs.validPath(filename); err != nil {
|
||||
return nil, fmt.Errorf("openfile: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.OpenFile(filename, flag, perm)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) Stat(filename string) (os.FileInfo, error) {
|
||||
if err := sfs.validReadPath(filename); err != nil {
|
||||
return nil, fmt.Errorf("stat: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.Stat(filename)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) Remove(filename string) error {
|
||||
if err := sfs.validPath(filename); err != nil {
|
||||
return fmt.Errorf("remove: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.Remove(filename)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) Rename(from, to string) error {
|
||||
if err := sfs.validPath(from, to); err != nil {
|
||||
return fmt.Errorf("rename: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.Rename(from, to)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) ReadDir(path string) ([]os.FileInfo, error) {
|
||||
if err := sfs.validReadPath(path); err != nil {
|
||||
return nil, fmt.Errorf("readdir: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.ReadDir(path)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) Lstat(filename string) (os.FileInfo, error) {
|
||||
if err := sfs.validReadPath(filename); err != nil {
|
||||
return nil, fmt.Errorf("lstat: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.Lstat(filename)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) Symlink(target, link string) error {
|
||||
if err := sfs.validPath(link); err != nil {
|
||||
return fmt.Errorf("symlink: %w", err)
|
||||
}
|
||||
if err := sfs.validSymlinkName(link); err != nil {
|
||||
return fmt.Errorf("symlink: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.Symlink(target, link)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) Readlink(link string) (string, error) {
|
||||
if err := sfs.validReadPath(link); err != nil {
|
||||
return "", fmt.Errorf("readlink: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.Readlink(link)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) MkdirAll(path string, perm os.FileMode) error {
|
||||
// MkdirAll on the worktree root is a no-op: the root always exists,
|
||||
// so there is nothing to materialise. Mirroring the tolerance that
|
||||
// validReadPath gives to read-side operations avoids breaking callers
|
||||
// that walk a directory tree and pass the relative-to-root prefix
|
||||
// ("") through to the worktree FS.
|
||||
if path == "" || path == "." || path == "/" {
|
||||
return nil
|
||||
}
|
||||
if err := sfs.validPath(path); err != nil {
|
||||
return fmt.Errorf("mkdirall: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.MkdirAll(path, perm)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) TempFile(_, _ string) (billy.File, error) {
|
||||
return nil, fmt.Errorf("tempfile: %w", errUnsupportedOperation)
|
||||
}
|
||||
|
||||
func (sfs *worktreeFilesystem) Chroot(path string) (billy.Filesystem, error) {
|
||||
if err := sfs.validReadPath(path); err != nil {
|
||||
return nil, fmt.Errorf("chroot: %w", err)
|
||||
}
|
||||
return sfs.Filesystem.Chroot(path)
|
||||
}
|
||||
|
||||
// validReadPath is like validPath but treats the empty string and "." as
|
||||
// valid references to the worktree root. Read-side operations on the root
|
||||
// (e.g. ReadDir(""), Lstat(".")) are legitimate; mutating the root itself
|
||||
// is not, so write-side operations continue to use validPath directly.
|
||||
func (sfs *worktreeFilesystem) validReadPath(p string) error {
|
||||
if p == "" || p == "." || p == "/" {
|
||||
return nil
|
||||
}
|
||||
return sfs.validPath(p)
|
||||
}
|
||||
|
||||
var errUnsupportedOperation = errors.New("unsupported operation")
|
||||
|
||||
// isDotGitVariant reports whether part is .git, git~1, or an HFS+
|
||||
// equivalent of .git (when protectHFS is true). NTFS variants of .git
|
||||
// (e.g. ".git " with trailing space, ".git::$INDEX_ALLOCATION") are
|
||||
// detected separately by pathutil.WindowsValidPath, which applies
|
||||
// regardless of position in the path. Both validators reuse this
|
||||
// helper.
|
||||
func isDotGitVariant(part string, protectHFS bool) bool {
|
||||
if pathutil.IsDotGitName(part) {
|
||||
return true
|
||||
}
|
||||
if protectHFS && pathutil.IsHFSDotGit(part) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// validPath checks whether paths are valid for the worktree
|
||||
// filesystem abstraction. It is intentionally tolerant of .git as
|
||||
// the final path component of a multi-component path
|
||||
// (e.g. "submodule/.git"), so that legitimate gitlink pointer files
|
||||
// can still be Stat'd, Read, and Removed via the wrapper during
|
||||
// submodule cleanup. Attacker-controlled tree-entry paths are
|
||||
// validated separately by pathutil.ValidTreePath at the boundaries
|
||||
// where data leaves the trusted store (Tree.FindEntry, the explicit
|
||||
// callers in CherryPick and Submodule.Repository).
|
||||
//
|
||||
// For upstream rules:
|
||||
// https://github.com/git/git/blob/v2.54.0/read-cache.c#L987
|
||||
// https://github.com/git/git/blob/v2.54.0/path.c#L1419
|
||||
func (sfs *worktreeFilesystem) validPath(paths ...string) error {
|
||||
for _, p := range paths {
|
||||
for i := 0; i < len(p); i++ {
|
||||
if p[i] < 0x20 || p[i] == 0x7f {
|
||||
return fmt.Errorf("invalid path %q: contains control character", p)
|
||||
}
|
||||
}
|
||||
|
||||
parts := strings.FieldsFunc(p, func(r rune) bool { return (r == '\\' || r == '/') })
|
||||
if len(parts) == 0 {
|
||||
return fmt.Errorf("invalid path: %q", p)
|
||||
}
|
||||
|
||||
if sfs.protectNTFS {
|
||||
// Volume names are not supported, in both formats: \\ and <DRIVE_LETTER>:.
|
||||
if vol := filepath.VolumeName(p); vol != "" {
|
||||
return fmt.Errorf("invalid path: %q", p)
|
||||
}
|
||||
}
|
||||
|
||||
for i, part := range parts {
|
||||
if part == "." || part == ".." {
|
||||
return fmt.Errorf("invalid path %q: cannot use %q", p, part)
|
||||
}
|
||||
|
||||
// Reject .git (and equivalents) as a path component when it is
|
||||
// either the first component (root-level .git) or a non-final
|
||||
// component (traversal into a .git directory, e.g. "a/.git/config").
|
||||
// A final non-first .git component (e.g. "submodule/.git") is
|
||||
// allowed because submodule worktrees contain a .git pointer file.
|
||||
if isDotGitVariant(part, sfs.protectHFS) && (i == 0 || i < len(parts)-1) {
|
||||
return fmt.Errorf("invalid path component: %q", p)
|
||||
}
|
||||
|
||||
if sfs.protectNTFS && !pathutil.WindowsValidPath(part) {
|
||||
return fmt.Errorf("invalid path: %q", p)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validSymlinkName checks the per-component name of a symlink for
|
||||
// dotfile names that attackers can use to trick a checkout into
|
||||
// writing a dangerous symlink. Each path component is compared
|
||||
// against .gitmodules case-insensitively, against its NTFS variants
|
||||
// (e.g. ".gitmodules .", ".gitmodules::$INDEX_ALLOCATION", or 8.3
|
||||
// short-name forms) when protectNTFS is on, and against its HFS+
|
||||
// variants (Unicode ignored code points folded into ".gitmodules")
|
||||
// when protectHFS is on.
|
||||
//
|
||||
// Reference: upstream Git verify_path_internal at read-cache.c#L1004-L1024
|
||||
// in tag v2.54.0[1].
|
||||
//
|
||||
// [1]: https://github.com/git/git/blob/v2.54.0/read-cache.c#L1004-L1024
|
||||
func (sfs *worktreeFilesystem) validSymlinkName(name string) error {
|
||||
parts := strings.FieldsFunc(name, func(r rune) bool {
|
||||
return r == '/' || r == '\\'
|
||||
})
|
||||
for _, part := range parts {
|
||||
if strings.EqualFold(part, gitmodulesFile) {
|
||||
return ErrGitModulesSymlink
|
||||
}
|
||||
if sfs.protectNTFS && pathutil.IsNTFSDotGitmodules(part) {
|
||||
return ErrGitModulesSymlink
|
||||
}
|
||||
if sfs.protectHFS && pathutil.IsHFSDotGitmodules(part) {
|
||||
return ErrGitModulesSymlink
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
9
vendor/github.com/go-git/go-git/v5/worktree_status.go
generated
vendored
9
vendor/github.com/go-git/go-git/v5/worktree_status.go
generated
vendored
@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-billy/v5/util"
|
||||
"github.com/go-git/go-git/v5/internal/pathutil"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/filemode"
|
||||
"github.com/go-git/go-git/v5/plumbing/format/gitignore"
|
||||
@ -545,6 +546,14 @@ func (w *Worktree) addOrUpdateFileToIndex(idx *index.Index, filename string, h p
|
||||
}
|
||||
|
||||
func (w *Worktree) doAddFileToIndex(idx *index.Index, filename string, h plumbing.Hash) error {
|
||||
// Mirror upstream's Index.Add gate at the v5 caller boundary: the
|
||||
// index feeds future trees, so a name that the tree-side
|
||||
// pathutil.ValidTreePath gate would reject must not enter the
|
||||
// index in the first place. v5 keeps Index.Add's existing signature
|
||||
// for API compatibility, so the validation happens here.
|
||||
if err := pathutil.ValidTreePath(filename); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.doUpdateFileToIndex(idx.Add(filename), filename, h)
|
||||
}
|
||||
|
||||
|
||||
2
vendor/github.com/pjbgf/sha1cd/Dockerfile.arm
generated
vendored
2
vendor/github.com/pjbgf/sha1cd/Dockerfile.arm
generated
vendored
@ -1,4 +1,4 @@
|
||||
FROM golang:1.24@sha256:14fd8a55e59a560704e5fc44970b301d00d344e45d6b914dda228e09f359a088
|
||||
FROM golang:1.26@sha256:6df14f4a4bc9d979a3721f488981e0d1b318006377e473ed23d026796f5f4c0a
|
||||
|
||||
ENV GOOS=linux
|
||||
ENV GOARCH=arm
|
||||
|
||||
2
vendor/github.com/pjbgf/sha1cd/Dockerfile.arm64
generated
vendored
2
vendor/github.com/pjbgf/sha1cd/Dockerfile.arm64
generated
vendored
@ -1,4 +1,4 @@
|
||||
FROM golang:1.24@sha256:14fd8a55e59a560704e5fc44970b301d00d344e45d6b914dda228e09f359a088
|
||||
FROM golang:1.26@sha256:6df14f4a4bc9d979a3721f488981e0d1b318006377e473ed23d026796f5f4c0a
|
||||
|
||||
ENV GOOS=linux
|
||||
ENV GOARCH=arm64
|
||||
|
||||
5
vendor/github.com/pjbgf/sha1cd/sha1cd.go
generated
vendored
5
vendor/github.com/pjbgf/sha1cd/sha1cd.go
generated
vendored
@ -12,7 +12,6 @@ package sha1cd
|
||||
// Original: https://github.com/golang/go/blob/master/src/crypto/sha1/sha1.go
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash"
|
||||
@ -20,10 +19,6 @@ import (
|
||||
shared "github.com/pjbgf/sha1cd/internal"
|
||||
)
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.SHA1, New)
|
||||
}
|
||||
|
||||
// The size of a SHA-1 checksum in bytes.
|
||||
const Size = shared.Size
|
||||
|
||||
|
||||
4
vendor/github.com/pjbgf/sha1cd/sha1cdblock_amd64.go
generated
vendored
4
vendor/github.com/pjbgf/sha1cd/sha1cdblock_amd64.go
generated
vendored
@ -37,9 +37,9 @@ func block(dig *digest, p []byte) {
|
||||
chunk := p[:shared.Chunk]
|
||||
|
||||
blockAMD64(dig.h[:], chunk, m1[:], cs[:])
|
||||
rectifyCompressionState(m1, &cs)
|
||||
rectifyCompressionState(&m1, &cs)
|
||||
|
||||
col := checkCollision(m1, cs, dig.h)
|
||||
col := checkCollision(&m1, &cs, &dig.h)
|
||||
if col {
|
||||
dig.col = true
|
||||
|
||||
|
||||
8
vendor/github.com/pjbgf/sha1cd/sha1cdblock_amd64.s
generated
vendored
8
vendor/github.com/pjbgf/sha1cd/sha1cdblock_amd64.s
generated
vendored
@ -11,11 +11,11 @@
|
||||
// Reference implementations:
|
||||
// - https://github.com/golang/go/blob/master/src/crypto/sha1/sha1block_amd64.s
|
||||
|
||||
// Reverse the dword order in abcd via PSHUFD then store the 16 bytes in one
|
||||
// move, instead of issuing four VPEXTRD's that each go through the store port.
|
||||
#define LOADCS(abcd, e, index, target) \
|
||||
VPEXTRD $3, abcd, ((index*20)+0)(target); \
|
||||
VPEXTRD $2, abcd, ((index*20)+4)(target); \
|
||||
VPEXTRD $1, abcd, ((index*20)+8)(target); \
|
||||
VPEXTRD $0, abcd, ((index*20)+12)(target); \
|
||||
VPSHUFD $0x1B, abcd, X8; \
|
||||
VMOVDQU X8, ((index*20)+0)(target); \
|
||||
MOVL e, ((index*20)+16)(target);
|
||||
|
||||
#define LOADM1(m1, index, target) \
|
||||
|
||||
4
vendor/github.com/pjbgf/sha1cd/sha1cdblock_arm64.go
generated
vendored
4
vendor/github.com/pjbgf/sha1cd/sha1cdblock_arm64.go
generated
vendored
@ -34,8 +34,8 @@ func block(dig *digest, p []byte) {
|
||||
|
||||
blockARM64(dig.h[:], chunk, m1[:], cs[:])
|
||||
|
||||
rectifyCompressionState(m1, &cs)
|
||||
col := checkCollision(m1, cs, dig.h)
|
||||
rectifyCompressionState(&m1, &cs)
|
||||
col := checkCollision(&m1, &cs, &dig.h)
|
||||
if col {
|
||||
dig.col = true
|
||||
|
||||
|
||||
25
vendor/github.com/pjbgf/sha1cd/sha1cdblock_generic.go
generated
vendored
25
vendor/github.com/pjbgf/sha1cd/sha1cdblock_generic.go
generated
vendored
@ -127,7 +127,8 @@ func blockGeneric(dig *digest, p []byte) {
|
||||
}
|
||||
|
||||
if hi == 1 {
|
||||
col := checkCollision(m1, cs, [shared.WordBuffers]uint32{h0, h1, h2, h3, h4})
|
||||
h := [shared.WordBuffers]uint32{h0, h1, h2, h3, h4}
|
||||
col := checkCollision(&m1, &cs, &h)
|
||||
if col {
|
||||
dig.col = true
|
||||
hi++
|
||||
@ -143,23 +144,23 @@ func blockGeneric(dig *digest, p []byte) {
|
||||
|
||||
//go:noinline
|
||||
func checkCollision(
|
||||
m1 [shared.Rounds]uint32,
|
||||
cs [shared.PreStepState][shared.WordBuffers]uint32,
|
||||
h [shared.WordBuffers]uint32,
|
||||
m1 *[shared.Rounds]uint32,
|
||||
cs *[shared.PreStepState][shared.WordBuffers]uint32,
|
||||
h *[shared.WordBuffers]uint32,
|
||||
) bool {
|
||||
if mask := ubc.CalculateDvMask(m1); mask != 0 {
|
||||
dvs := ubc.SHA1_dvs()
|
||||
|
||||
for i := 0; dvs[i].DvType != 0; i++ {
|
||||
if (mask & ((uint32)(1) << uint32(dvs[i].MaskB))) != 0 {
|
||||
var csState [shared.WordBuffers]uint32
|
||||
var csState *[shared.WordBuffers]uint32
|
||||
switch dvs[i].TestT {
|
||||
case 58:
|
||||
csState = cs[1]
|
||||
csState = &cs[1]
|
||||
case 65:
|
||||
csState = cs[2]
|
||||
csState = &cs[2]
|
||||
case 0:
|
||||
csState = cs[0]
|
||||
csState = &cs[0]
|
||||
default:
|
||||
panic(fmt.Sprintf("dvs data is trying to use a testT that isn't available: %d", dvs[i].TestT))
|
||||
}
|
||||
@ -168,7 +169,7 @@ func checkCollision(
|
||||
dvs[i].TestT, // testT is the step number
|
||||
// m2 is a secondary message created XORing with
|
||||
// ubc's DM prior to the SHA recompression step.
|
||||
m1, dvs[i].Dm,
|
||||
m1, &dvs[i].Dm,
|
||||
csState,
|
||||
h)
|
||||
|
||||
@ -182,8 +183,8 @@ func checkCollision(
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func hasCollided(step uint32, m1, dm [shared.Rounds]uint32,
|
||||
state [shared.WordBuffers]uint32, h [shared.WordBuffers]uint32) bool {
|
||||
func hasCollided(step uint32, m1, dm *[shared.Rounds]uint32,
|
||||
state *[shared.WordBuffers]uint32, h *[shared.WordBuffers]uint32) bool {
|
||||
// Intermediary Hash Value.
|
||||
ihv := [shared.WordBuffers]uint32{}
|
||||
|
||||
@ -282,7 +283,7 @@ func hasCollided(step uint32, m1, dm [shared.Rounds]uint32,
|
||||
//
|
||||
//go:nosplit
|
||||
func rectifyCompressionState(
|
||||
m1 [shared.Rounds]uint32,
|
||||
m1 *[shared.Rounds]uint32,
|
||||
cs *[shared.PreStepState][shared.WordBuffers]uint32,
|
||||
) {
|
||||
if cs == nil {
|
||||
|
||||
5
vendor/github.com/pjbgf/sha1cd/ubc/ubc.go
generated
vendored
5
vendor/github.com/pjbgf/sha1cd/ubc/ubc.go
generated
vendored
@ -29,7 +29,10 @@ type DvInfo struct {
|
||||
// bitconditions for that DV have been met.
|
||||
//
|
||||
//go:nosplit
|
||||
func CalculateDvMask(W [80]uint32) uint32 {
|
||||
func CalculateDvMask(W *[80]uint32) uint32 {
|
||||
if W == nil {
|
||||
return 0
|
||||
}
|
||||
mask := uint32(0xFFFFFFFF)
|
||||
mask &= (((((W[44] ^ W[45]) >> 29) & 1) - 1) | ^(DV_I_48_0_bit | DV_I_51_0_bit | DV_I_52_0_bit | DV_II_45_0_bit | DV_II_46_0_bit | DV_II_50_0_bit | DV_II_51_0_bit))
|
||||
mask &= (((((W[49] ^ W[50]) >> 29) & 1) - 1) | ^(DV_I_46_0_bit | DV_II_45_0_bit | DV_II_50_0_bit | DV_II_51_0_bit | DV_II_55_0_bit | DV_II_56_0_bit))
|
||||
|
||||
16
vendor/github.com/spf13/cobra/command.go
generated
vendored
16
vendor/github.com/spf13/cobra/command.go
generated
vendored
@ -925,15 +925,10 @@ func (c *Command) execute(a []string) (err error) {
|
||||
// Also say we need help if the command isn't runnable.
|
||||
helpVal, err := c.Flags().GetBool(helpFlagName)
|
||||
if err != nil {
|
||||
// NOTE(d1): temporarily hardcoding "ayuda" as a replacement for "help"
|
||||
// source of the pain: https://github.com/spf13/cobra/issues/2359
|
||||
helpVal, err = c.Flags().GetBool("ayuda")
|
||||
if err != nil {
|
||||
// should be impossible to get here as we always declare a help
|
||||
// flag in InitDefaultHelpFlag()
|
||||
c.Println("\"help\" flag declared as non-bool. Please correct your code")
|
||||
return err
|
||||
}
|
||||
// should be impossible to get here as we always declare a help
|
||||
// flag in InitDefaultHelpFlag()
|
||||
c.Println("\"help\" flag declared as non-bool. Please correct your code")
|
||||
return err
|
||||
}
|
||||
|
||||
if helpVal {
|
||||
@ -1231,8 +1226,7 @@ func (c *Command) InitDefaultHelpFlag() {
|
||||
} else {
|
||||
usage += name
|
||||
}
|
||||
// NOTE(d1): do not assume "help" exists in the context of translation
|
||||
// c.Flags().BoolP(helpFlagName, "h", false, usage)
|
||||
c.Flags().BoolP(helpFlagName, "h", false, usage)
|
||||
_ = c.Flags().SetAnnotation(helpFlagName, FlagSetByCobraAnnotation, []string{"true"})
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/golang.org/x/crypto/ssh/cipher.go
generated
vendored
2
vendor/golang.org/x/crypto/ssh/cipher.go
generated
vendored
@ -586,7 +586,7 @@ func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader
|
||||
|
||||
// Length of encrypted portion of the packet (header, payload, padding).
|
||||
// Enforce minimum padding and packet size.
|
||||
encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize)
|
||||
encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPacketSize)
|
||||
// Enforce block size.
|
||||
encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize
|
||||
|
||||
|
||||
10
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
10
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
@ -274,10 +274,14 @@ func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiA
|
||||
}
|
||||
|
||||
// Filter algorithms based on those supported by MultiAlgorithmSigner.
|
||||
// Iterate over the signer's algorithms first to preserve its preference order.
|
||||
supportedKeyAlgos := algorithmsForKeyFormat(keyFormat)
|
||||
var keyAlgos []string
|
||||
for _, algo := range algorithmsForKeyFormat(keyFormat) {
|
||||
if slices.Contains(as.Algorithms(), underlyingAlgo(algo)) {
|
||||
keyAlgos = append(keyAlgos, algo)
|
||||
for _, signerAlgo := range as.Algorithms() {
|
||||
if idx := slices.IndexFunc(supportedKeyAlgos, func(algo string) bool {
|
||||
return underlyingAlgo(algo) == signerAlgo
|
||||
}); idx >= 0 {
|
||||
keyAlgos = append(keyAlgos, supportedKeyAlgos[idx])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
13
vendor/golang.org/x/net/http2/hpack/tables.go
generated
vendored
13
vendor/golang.org/x/net/http2/hpack/tables.go
generated
vendored
@ -6,6 +6,7 @@ package hpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// headerFieldTable implements a list of HeaderFields.
|
||||
@ -54,10 +55,16 @@ func (t *headerFieldTable) len() int {
|
||||
|
||||
// addEntry adds a new entry.
|
||||
func (t *headerFieldTable) addEntry(f HeaderField) {
|
||||
// Prevent f from escaping to the heap.
|
||||
f2 := HeaderField{
|
||||
Name: strings.Clone(f.Name),
|
||||
Value: strings.Clone(f.Value),
|
||||
Sensitive: f.Sensitive,
|
||||
}
|
||||
id := uint64(t.len()) + t.evictCount + 1
|
||||
t.byName[f.Name] = id
|
||||
t.byNameValue[pairNameValue{f.Name, f.Value}] = id
|
||||
t.ents = append(t.ents, f)
|
||||
t.byName[f2.Name] = id
|
||||
t.byNameValue[pairNameValue{f2.Name, f2.Value}] = id
|
||||
t.ents = append(t.ents, f2)
|
||||
}
|
||||
|
||||
// evictOldest evicts the n oldest entries in the table.
|
||||
|
||||
9
vendor/golang.org/x/net/http2/transport.go
generated
vendored
9
vendor/golang.org/x/net/http2/transport.go
generated
vendored
@ -718,9 +718,6 @@ func canRetryError(err error) bool {
|
||||
}
|
||||
|
||||
func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) {
|
||||
if t.transportTestHooks != nil {
|
||||
return t.newClientConn(nil, singleUse, nil)
|
||||
}
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -2861,6 +2858,9 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
|
||||
|
||||
var seenMaxConcurrentStreams bool
|
||||
err := f.ForeachSetting(func(s Setting) error {
|
||||
if err := s.Valid(); err != nil {
|
||||
return err
|
||||
}
|
||||
switch s.ID {
|
||||
case SettingMaxFrameSize:
|
||||
cc.maxFrameSize = s.Val
|
||||
@ -2892,9 +2892,6 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
|
||||
cc.henc.SetMaxDynamicTableSize(s.Val)
|
||||
cc.peerMaxHeaderTableSize = s.Val
|
||||
case SettingEnableConnectProtocol:
|
||||
if err := s.Valid(); err != nil {
|
||||
return err
|
||||
}
|
||||
// If the peer wants to send us SETTINGS_ENABLE_CONNECT_PROTOCOL,
|
||||
// we require that it do so in the first SETTINGS frame.
|
||||
//
|
||||
|
||||
19
vendor/golang.org/x/sys/cpu/cpu.go
generated
vendored
19
vendor/golang.org/x/sys/cpu/cpu.go
generated
vendored
@ -152,13 +152,17 @@ var ARM struct {
|
||||
// The booleans in Loong64 contain the correspondingly named cpu feature bit.
|
||||
// The struct is padded to avoid false sharing.
|
||||
var Loong64 struct {
|
||||
_ CacheLinePad
|
||||
HasLSX bool // support 128-bit vector extension
|
||||
HasLASX bool // support 256-bit vector extension
|
||||
HasCRC32 bool // support CRC instruction
|
||||
HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction
|
||||
HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} instruction
|
||||
_ CacheLinePad
|
||||
_ CacheLinePad
|
||||
HasLSX bool // support 128-bit vector extension
|
||||
HasLASX bool // support 256-bit vector extension
|
||||
HasCRC32 bool // support CRC instruction
|
||||
HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D}
|
||||
HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction
|
||||
HasLLACQ_SCREL bool // support LLACQ.{W/D}, SCREL.{W/D} instruction
|
||||
HasSCQ bool // support SC.Q instruction
|
||||
HasDBAR_HINTS bool // supports finer-grained DBAR hints
|
||||
|
||||
_ CacheLinePad
|
||||
}
|
||||
|
||||
// MIPS64X contains the supported CPU features of the current mips64/mips64le
|
||||
@ -232,6 +236,7 @@ var RISCV64 struct {
|
||||
HasZba bool // Address generation instructions extension
|
||||
HasZbb bool // Basic bit-manipulation extension
|
||||
HasZbs bool // Single-bit instructions extension
|
||||
HasZbc bool // Carryless multiplication extension
|
||||
HasZvbb bool // Vector Basic Bit-manipulation
|
||||
HasZvbc bool // Vector Carryless Multiplication
|
||||
HasZvkb bool // Vector Cryptography Bit-manipulation
|
||||
|
||||
2
vendor/golang.org/x/sys/cpu/cpu_darwin_arm64_other.go
generated
vendored
2
vendor/golang.org/x/sys/cpu/cpu_darwin_arm64_other.go
generated
vendored
@ -6,6 +6,8 @@
|
||||
|
||||
package cpu
|
||||
|
||||
import "runtime"
|
||||
|
||||
func doinit() {
|
||||
setMinimalFeatures()
|
||||
|
||||
|
||||
2
vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go
generated
vendored
2
vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go
generated
vendored
@ -58,6 +58,7 @@ const (
|
||||
riscv_HWPROBE_EXT_ZBA = 0x8
|
||||
riscv_HWPROBE_EXT_ZBB = 0x10
|
||||
riscv_HWPROBE_EXT_ZBS = 0x20
|
||||
riscv_HWPROBE_EXT_ZBC = 0x80
|
||||
riscv_HWPROBE_EXT_ZVBB = 0x20000
|
||||
riscv_HWPROBE_EXT_ZVBC = 0x40000
|
||||
riscv_HWPROBE_EXT_ZVKB = 0x80000
|
||||
@ -108,6 +109,7 @@ func doinit() {
|
||||
RISCV64.HasZba = isSet(v, riscv_HWPROBE_EXT_ZBA)
|
||||
RISCV64.HasZbb = isSet(v, riscv_HWPROBE_EXT_ZBB)
|
||||
RISCV64.HasZbs = isSet(v, riscv_HWPROBE_EXT_ZBS)
|
||||
RISCV64.HasZbc = isSet(v, riscv_HWPROBE_EXT_ZBC)
|
||||
RISCV64.HasZvbb = isSet(v, riscv_HWPROBE_EXT_ZVBB)
|
||||
RISCV64.HasZvbc = isSet(v, riscv_HWPROBE_EXT_ZVBC)
|
||||
RISCV64.HasZvkb = isSet(v, riscv_HWPROBE_EXT_ZVKB)
|
||||
|
||||
16
vendor/golang.org/x/sys/cpu/cpu_loong64.go
generated
vendored
16
vendor/golang.org/x/sys/cpu/cpu_loong64.go
generated
vendored
@ -15,8 +15,13 @@ const (
|
||||
cpucfg1_CRC32 = 1 << 25
|
||||
|
||||
// CPUCFG2 bits
|
||||
cpucfg2_LAM_BH = 1 << 27
|
||||
cpucfg2_LAMCAS = 1 << 28
|
||||
cpucfg2_LAM_BH = 1 << 27
|
||||
cpucfg2_LAMCAS = 1 << 28
|
||||
cpucfg2_LLACQ_SCREL = 1 << 29
|
||||
cpucfg2_SCQ = 1 << 30
|
||||
|
||||
// CPUCFG3 bits
|
||||
cpucfg3_DBAR_HINTS = 1 << 17
|
||||
)
|
||||
|
||||
func initOptions() {
|
||||
@ -26,6 +31,9 @@ func initOptions() {
|
||||
{Name: "crc32", Feature: &Loong64.HasCRC32},
|
||||
{Name: "lam_bh", Feature: &Loong64.HasLAM_BH},
|
||||
{Name: "lamcas", Feature: &Loong64.HasLAMCAS},
|
||||
{Name: "llacq_screl", Feature: &Loong64.HasLLACQ_SCREL},
|
||||
{Name: "scq", Feature: &Loong64.HasSCQ},
|
||||
{Name: "dbar_hints", Feature: &Loong64.HasDBAR_HINTS},
|
||||
}
|
||||
|
||||
// The CPUCFG data on Loong64 only reflects the hardware capabilities,
|
||||
@ -37,10 +45,14 @@ func initOptions() {
|
||||
// through CPUCFG
|
||||
cfg1 := get_cpucfg(1)
|
||||
cfg2 := get_cpucfg(2)
|
||||
cfg3 := get_cpucfg(3)
|
||||
|
||||
Loong64.HasCRC32 = cfgIsSet(cfg1, cpucfg1_CRC32)
|
||||
Loong64.HasLAMCAS = cfgIsSet(cfg2, cpucfg2_LAMCAS)
|
||||
Loong64.HasLAM_BH = cfgIsSet(cfg2, cpucfg2_LAM_BH)
|
||||
Loong64.HasLLACQ_SCREL = cfgIsSet(cfg2, cpucfg2_LLACQ_SCREL)
|
||||
Loong64.HasSCQ = cfgIsSet(cfg2, cpucfg2_SCQ)
|
||||
Loong64.HasDBAR_HINTS = cfgIsSet(cfg3, cpucfg3_DBAR_HINTS)
|
||||
}
|
||||
|
||||
func get_cpucfg(reg uint32) uint32
|
||||
|
||||
1
vendor/golang.org/x/sys/cpu/cpu_riscv64.go
generated
vendored
1
vendor/golang.org/x/sys/cpu/cpu_riscv64.go
generated
vendored
@ -16,6 +16,7 @@ func initOptions() {
|
||||
{Name: "zba", Feature: &RISCV64.HasZba},
|
||||
{Name: "zbb", Feature: &RISCV64.HasZbb},
|
||||
{Name: "zbs", Feature: &RISCV64.HasZbs},
|
||||
{Name: "zbc", Feature: &RISCV64.HasZbc},
|
||||
// RISC-V Cryptography Extensions
|
||||
{Name: "zvbb", Feature: &RISCV64.HasZvbb},
|
||||
{Name: "zvbc", Feature: &RISCV64.HasZvbc},
|
||||
|
||||
26
vendor/golang.org/x/sys/cpu/cpu_windows.go
generated
vendored
Normal file
26
vendor/golang.org/x/sys/cpu/cpu_windows.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cpu
|
||||
|
||||
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -systemdll=false -output zcpu_windows.go cpu_windows.go
|
||||
|
||||
//sys isProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) = kernel32.IsProcessorFeaturePresent
|
||||
|
||||
// The processor features to be tested for IsProcessorFeaturePresent, see
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
|
||||
const (
|
||||
_PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30
|
||||
_PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31
|
||||
_PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE = 34
|
||||
_PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE = 43
|
||||
|
||||
_PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE = 44
|
||||
_PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE = 45
|
||||
_PF_ARM_SVE_INSTRUCTIONS_AVAILABLE = 46
|
||||
_PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE = 47
|
||||
|
||||
_PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE = 64
|
||||
_PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE = 65
|
||||
)
|
||||
24
vendor/golang.org/x/sys/cpu/cpu_windows_arm64.go
generated
vendored
24
vendor/golang.org/x/sys/cpu/cpu_windows_arm64.go
generated
vendored
@ -4,10 +4,6 @@
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func doinit() {
|
||||
// set HasASIMD and HasFP to true as per
|
||||
// https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#base-requirements
|
||||
@ -18,25 +14,25 @@ func doinit() {
|
||||
ARM64.HasASIMD = true
|
||||
ARM64.HasFP = true
|
||||
|
||||
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) {
|
||||
if isProcessorFeaturePresent(_PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasAES = true
|
||||
ARM64.HasPMULL = true
|
||||
ARM64.HasSHA1 = true
|
||||
ARM64.HasSHA2 = true
|
||||
}
|
||||
ARM64.HasSHA3 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasCRC32 = windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSHA512 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasATOMICS = windows.IsProcessorFeaturePresent(windows.PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
|
||||
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasSHA3 = isProcessorFeaturePresent(_PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasCRC32 = isProcessorFeaturePresent(_PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSHA512 = isProcessorFeaturePresent(_PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasATOMICS = isProcessorFeaturePresent(_PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
|
||||
if isProcessorFeaturePresent(_PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasASIMDDP = true
|
||||
ARM64.HasASIMDRDM = true
|
||||
}
|
||||
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) {
|
||||
if isProcessorFeaturePresent(_PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasLRCPC = true
|
||||
ARM64.HasSM3 = true
|
||||
}
|
||||
ARM64.HasSVE = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSVE2 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasJSCVT = windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSVE = isProcessorFeaturePresent(_PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSVE2 = isProcessorFeaturePresent(_PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasJSCVT = isProcessorFeaturePresent(_PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
|
||||
}
|
||||
|
||||
48
vendor/golang.org/x/sys/cpu/zcpu_windows.go
generated
vendored
Normal file
48
vendor/golang.org/x/sys/cpu/zcpu_windows.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
// Code generated by 'go generate'; DO NOT EDIT.
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
errERROR_EINVAL error = syscall.EINVAL
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return errERROR_EINVAL
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
procIsProcessorFeaturePresent = modkernel32.NewProc("IsProcessorFeaturePresent")
|
||||
)
|
||||
|
||||
func isProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) {
|
||||
r0, _, _ := syscall.SyscallN(procIsProcessorFeaturePresent.Addr(), uintptr(ProcessorFeature))
|
||||
ret = r0 != 0
|
||||
return
|
||||
}
|
||||
128
vendor/golang.org/x/sys/unix/affinity_linux.go
generated
vendored
128
vendor/golang.org/x/sys/unix/affinity_linux.go
generated
vendored
@ -13,11 +13,19 @@ import (
|
||||
|
||||
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
|
||||
|
||||
// CPUSet represents a CPU affinity mask.
|
||||
// CPUSet represents a bit mask of CPUs, to be used with [SchedGetaffinity], [SchedSetaffinity],
|
||||
// and [SetMemPolicy].
|
||||
//
|
||||
// Note this type can only represent CPU IDs 0 through 1023.
|
||||
// Use [CPUSetDynamic]/[NewCPUSet] instead to avoid this limit.
|
||||
type CPUSet [cpuSetSize]cpuMask
|
||||
|
||||
func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
|
||||
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
|
||||
// CPUSetDynamic represents a bit mask of CPUs, to be used with [SchedGetaffinityDynamic],
|
||||
// [SchedSetaffinityDynamic], and [SetMemPolicyDynamic]. Use [NewCPUSet] to allocate.
|
||||
type CPUSetDynamic []cpuMask
|
||||
|
||||
func schedAffinity(trap uintptr, pid int, size uintptr, ptr unsafe.Pointer) error {
|
||||
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(size), uintptr(ptr))
|
||||
if e != 0 {
|
||||
return errnoErr(e)
|
||||
}
|
||||
@ -27,13 +35,13 @@ func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
|
||||
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
|
||||
// If pid is 0 the calling thread is used.
|
||||
func SchedGetaffinity(pid int, set *CPUSet) error {
|
||||
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
|
||||
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, unsafe.Sizeof(*set), unsafe.Pointer(set))
|
||||
}
|
||||
|
||||
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
|
||||
// If pid is 0 the calling thread is used.
|
||||
func SchedSetaffinity(pid int, set *CPUSet) error {
|
||||
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
|
||||
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, unsafe.Sizeof(*set), unsafe.Pointer(set))
|
||||
}
|
||||
|
||||
// Zero clears the set s, so that it contains no CPUs.
|
||||
@ -45,9 +53,7 @@ func (s *CPUSet) Zero() {
|
||||
// will silently ignore any invalid CPU bits in [CPUSet] so this is an
|
||||
// efficient way of resetting the CPU affinity of a process.
|
||||
func (s *CPUSet) Fill() {
|
||||
for i := range s {
|
||||
s[i] = ^cpuMask(0)
|
||||
}
|
||||
cpuMaskFill(s[:])
|
||||
}
|
||||
|
||||
func cpuBitsIndex(cpu int) int {
|
||||
@ -58,24 +64,27 @@ func cpuBitsMask(cpu int) cpuMask {
|
||||
return cpuMask(1 << (uint(cpu) % _NCPUBITS))
|
||||
}
|
||||
|
||||
// Set adds cpu to the set s.
|
||||
func (s *CPUSet) Set(cpu int) {
|
||||
func cpuMaskFill(s []cpuMask) {
|
||||
for i := range s {
|
||||
s[i] = ^cpuMask(0)
|
||||
}
|
||||
}
|
||||
|
||||
func cpuMaskSet(s []cpuMask, cpu int) {
|
||||
i := cpuBitsIndex(cpu)
|
||||
if i < len(s) {
|
||||
s[i] |= cpuBitsMask(cpu)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear removes cpu from the set s.
|
||||
func (s *CPUSet) Clear(cpu int) {
|
||||
func cpuMaskClear(s []cpuMask, cpu int) {
|
||||
i := cpuBitsIndex(cpu)
|
||||
if i < len(s) {
|
||||
s[i] &^= cpuBitsMask(cpu)
|
||||
}
|
||||
}
|
||||
|
||||
// IsSet reports whether cpu is in the set s.
|
||||
func (s *CPUSet) IsSet(cpu int) bool {
|
||||
func cpuMaskIsSet(s []cpuMask, cpu int) bool {
|
||||
i := cpuBitsIndex(cpu)
|
||||
if i < len(s) {
|
||||
return s[i]&cpuBitsMask(cpu) != 0
|
||||
@ -83,11 +92,98 @@ func (s *CPUSet) IsSet(cpu int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Count returns the number of CPUs in the set s.
|
||||
func (s *CPUSet) Count() int {
|
||||
func cpuMaskCount(s []cpuMask) int {
|
||||
c := 0
|
||||
for _, b := range s {
|
||||
c += bits.OnesCount64(uint64(b))
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Set adds cpu to the set s. If cpu is out of bounds for s, no action is taken.
|
||||
func (s *CPUSet) Set(cpu int) {
|
||||
cpuMaskSet(s[:], cpu)
|
||||
}
|
||||
|
||||
// Clear removes cpu from the set s. If cpu is out of bounds for s, no action is taken.
|
||||
func (s *CPUSet) Clear(cpu int) {
|
||||
cpuMaskClear(s[:], cpu)
|
||||
}
|
||||
|
||||
// IsSet reports whether cpu is in the set s.
|
||||
func (s *CPUSet) IsSet(cpu int) bool {
|
||||
return cpuMaskIsSet(s[:], cpu)
|
||||
}
|
||||
|
||||
// Count returns the number of CPUs in the set s.
|
||||
func (s *CPUSet) Count() int {
|
||||
return cpuMaskCount(s[:])
|
||||
}
|
||||
|
||||
// NewCPUSet creates a CPU affinity mask capable of representing CPU IDs
|
||||
// up to maxCPU (exclusive).
|
||||
func NewCPUSet(maxCPU int) CPUSetDynamic {
|
||||
numMasks := (maxCPU + _NCPUBITS - 1) / _NCPUBITS
|
||||
if numMasks == 0 {
|
||||
numMasks = 1
|
||||
}
|
||||
return make(CPUSetDynamic, numMasks)
|
||||
}
|
||||
|
||||
// Zero clears the set s, so that it contains no CPUs.
|
||||
func (s CPUSetDynamic) Zero() {
|
||||
clear(s)
|
||||
}
|
||||
|
||||
// Fill adds all possible CPU bits to the set s. On Linux, [SchedSetaffinityDynamic]
|
||||
// will silently ignore any invalid CPU bits in [CPUSetDynamic] so this is an
|
||||
// efficient way of resetting the CPU affinity of a process.
|
||||
func (s CPUSetDynamic) Fill() {
|
||||
cpuMaskFill(s)
|
||||
}
|
||||
|
||||
// Set adds cpu to the set s. If cpu is out of bounds for s, no action is taken.
|
||||
func (s CPUSetDynamic) Set(cpu int) {
|
||||
cpuMaskSet(s, cpu)
|
||||
}
|
||||
|
||||
// Clear removes cpu from the set s. If cpu is out of bounds for s, no action is taken.
|
||||
func (s CPUSetDynamic) Clear(cpu int) {
|
||||
cpuMaskClear(s, cpu)
|
||||
}
|
||||
|
||||
// IsSet reports whether cpu is in the set s.
|
||||
func (s CPUSetDynamic) IsSet(cpu int) bool {
|
||||
return cpuMaskIsSet(s, cpu)
|
||||
}
|
||||
|
||||
// Count returns the number of CPUs in the set s.
|
||||
func (s CPUSetDynamic) Count() int {
|
||||
return cpuMaskCount(s)
|
||||
}
|
||||
|
||||
func (s CPUSetDynamic) size() uintptr {
|
||||
return uintptr(len(s)) * unsafe.Sizeof(cpuMask(0))
|
||||
}
|
||||
|
||||
func (s CPUSetDynamic) pointer() unsafe.Pointer {
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
return unsafe.Pointer(&s[0])
|
||||
}
|
||||
|
||||
// SchedGetaffinityDynamic gets the CPU affinity mask of the thread specified by pid.
|
||||
// If pid is 0 the calling thread is used.
|
||||
//
|
||||
// If the set is smaller than the size of the affinity mask used by the kernel,
|
||||
// [EINVAL] is returned.
|
||||
func SchedGetaffinityDynamic(pid int, set CPUSetDynamic) error {
|
||||
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set.size(), set.pointer())
|
||||
}
|
||||
|
||||
// SchedSetaffinityDynamic sets the CPU affinity mask of the thread specified by pid.
|
||||
// If pid is 0 the calling thread is used.
|
||||
func SchedSetaffinityDynamic(pid int, set CPUSetDynamic) error {
|
||||
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set.size(), set.pointer())
|
||||
}
|
||||
|
||||
2
vendor/golang.org/x/sys/unix/mkall.sh
generated
vendored
2
vendor/golang.org/x/sys/unix/mkall.sh
generated
vendored
@ -51,7 +51,7 @@ if [[ "$GOOS" = "linux" ]]; then
|
||||
# Files generated through docker (use $cmd so you can Ctl-C the build or run)
|
||||
set -e
|
||||
$cmd docker build --tag generate:$GOOS $GOOS
|
||||
$cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS
|
||||
$cmd docker run --rm --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS
|
||||
exit
|
||||
fi
|
||||
|
||||
|
||||
3
vendor/golang.org/x/sys/unix/mkerrors.sh
generated
vendored
3
vendor/golang.org/x/sys/unix/mkerrors.sh
generated
vendored
@ -354,6 +354,9 @@ struct ltchars {
|
||||
// Renamed in v6.16, commit c6d732c38f93 ("net: ethtool: remove duplicate defines for family info")
|
||||
#define ETHTOOL_FAMILY_NAME ETHTOOL_GENL_NAME
|
||||
#define ETHTOOL_FAMILY_VERSION ETHTOOL_GENL_VERSION
|
||||
|
||||
// Removed in v6.17, commit 760e6f7befba ("futex: Remove support for IMMUTABLE")
|
||||
#define PR_FUTEX_HASH_GET_IMMUTABLE 3
|
||||
'
|
||||
|
||||
includes_NetBSD='
|
||||
|
||||
103
vendor/golang.org/x/sys/unix/readv_unix.go
generated
vendored
Normal file
103
vendor/golang.org/x/sys/unix/readv_unix.go
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin || linux || openbsd
|
||||
|
||||
package unix
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// minIovec is the size of the small initial allocation used by
|
||||
// Readv, Writev, etc.
|
||||
//
|
||||
// This small allocation gets stack allocated, which lets the
|
||||
// common use case of len(iovs) <= minIovec avoid more expensive
|
||||
// heap allocations.
|
||||
const minIovec = 8
|
||||
|
||||
// appendBytes converts bs to Iovecs and appends them to vecs.
|
||||
func appendBytes(vecs []Iovec, bs [][]byte) []Iovec {
|
||||
for _, b := range bs {
|
||||
var v Iovec
|
||||
v.SetLen(len(b))
|
||||
if len(b) > 0 {
|
||||
v.Base = &b[0]
|
||||
} else {
|
||||
v.Base = (*byte)(unsafe.Pointer(&_zero))
|
||||
}
|
||||
vecs = append(vecs, v)
|
||||
}
|
||||
return vecs
|
||||
}
|
||||
|
||||
// writevRaceDetect tells the race detector that the program
|
||||
// has read the first n bytes stored in iovecs.
|
||||
func writevRaceDetect(iovecs []Iovec, n int) {
|
||||
if !raceenabled {
|
||||
return
|
||||
}
|
||||
for i := 0; n > 0 && i < len(iovecs); i++ {
|
||||
m := min(int(iovecs[i].Len), n)
|
||||
n -= m
|
||||
if m > 0 {
|
||||
raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// readvRaceDetect tells the race detector that the program
|
||||
// has written to the first n bytes stored in iovecs.
|
||||
func readvRaceDetect(iovecs []Iovec, n int, err error) {
|
||||
if !raceenabled {
|
||||
return
|
||||
}
|
||||
for i := 0; n > 0 && i < len(iovecs); i++ {
|
||||
m := min(int(iovecs[i].Len), n)
|
||||
n -= m
|
||||
if m > 0 {
|
||||
raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
raceAcquire(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
}
|
||||
|
||||
func Readv(fd int, iovs [][]byte) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
n, err = readv(fd, iovecs)
|
||||
readvRaceDetect(iovecs, n, err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
n, err = preadv(fd, iovecs, offset)
|
||||
readvRaceDetect(iovecs, n, err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func Writev(fd int, iovs [][]byte) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
if raceenabled {
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
n, err = writev(fd, iovecs)
|
||||
writevRaceDetect(iovecs, n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
if raceenabled {
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
n, err = pwritev(fd, iovecs, offset)
|
||||
writevRaceDetect(iovecs, n)
|
||||
return n, err
|
||||
}
|
||||
89
vendor/golang.org/x/sys/unix/syscall_darwin.go
generated
vendored
89
vendor/golang.org/x/sys/unix/syscall_darwin.go
generated
vendored
@ -602,95 +602,6 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI
|
||||
return
|
||||
}
|
||||
|
||||
const minIovec = 8
|
||||
|
||||
func Readv(fd int, iovs [][]byte) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
n, err = readv(fd, iovecs)
|
||||
readvRacedetect(iovecs, n, err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
n, err = preadv(fd, iovecs, offset)
|
||||
readvRacedetect(iovecs, n, err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func Writev(fd int, iovs [][]byte) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
if raceenabled {
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
n, err = writev(fd, iovecs)
|
||||
writevRacedetect(iovecs, n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
if raceenabled {
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
n, err = pwritev(fd, iovecs, offset)
|
||||
writevRacedetect(iovecs, n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func appendBytes(vecs []Iovec, bs [][]byte) []Iovec {
|
||||
for _, b := range bs {
|
||||
var v Iovec
|
||||
v.SetLen(len(b))
|
||||
if len(b) > 0 {
|
||||
v.Base = &b[0]
|
||||
} else {
|
||||
v.Base = (*byte)(unsafe.Pointer(&_zero))
|
||||
}
|
||||
vecs = append(vecs, v)
|
||||
}
|
||||
return vecs
|
||||
}
|
||||
|
||||
func writevRacedetect(iovecs []Iovec, n int) {
|
||||
if !raceenabled {
|
||||
return
|
||||
}
|
||||
for i := 0; n > 0 && i < len(iovecs); i++ {
|
||||
m := int(iovecs[i].Len)
|
||||
if m > n {
|
||||
m = n
|
||||
}
|
||||
n -= m
|
||||
if m > 0 {
|
||||
raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readvRacedetect(iovecs []Iovec, n int, err error) {
|
||||
if !raceenabled {
|
||||
return
|
||||
}
|
||||
for i := 0; n > 0 && i < len(iovecs); i++ {
|
||||
m := int(iovecs[i].Len)
|
||||
if m > n {
|
||||
m = n
|
||||
}
|
||||
n -= m
|
||||
if m > 0 {
|
||||
raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
raceAcquire(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
}
|
||||
|
||||
//sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error)
|
||||
//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
|
||||
|
||||
|
||||
114
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
114
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
@ -2150,33 +2150,10 @@ func Signalfd(fd int, sigmask *Sigset_t, flags int) (newfd int, err error) {
|
||||
//sys exitThread(code int) (err error) = SYS_EXIT
|
||||
//sys readv(fd int, iovs []Iovec) (n int, err error) = SYS_READV
|
||||
//sys writev(fd int, iovs []Iovec) (n int, err error) = SYS_WRITEV
|
||||
//sys preadv(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr) (n int, err error) = SYS_PREADV
|
||||
//sys pwritev(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr) (n int, err error) = SYS_PWRITEV
|
||||
//sys preadv2(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr, flags int) (n int, err error) = SYS_PREADV2
|
||||
//sys pwritev2(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr, flags int) (n int, err error) = SYS_PWRITEV2
|
||||
|
||||
// minIovec is the size of the small initial allocation used by
|
||||
// Readv, Writev, etc.
|
||||
//
|
||||
// This small allocation gets stack allocated, which lets the
|
||||
// common use case of len(iovs) <= minIovs avoid more expensive
|
||||
// heap allocations.
|
||||
const minIovec = 8
|
||||
|
||||
// appendBytes converts bs to Iovecs and appends them to vecs.
|
||||
func appendBytes(vecs []Iovec, bs [][]byte) []Iovec {
|
||||
for _, b := range bs {
|
||||
var v Iovec
|
||||
v.SetLen(len(b))
|
||||
if len(b) > 0 {
|
||||
v.Base = &b[0]
|
||||
} else {
|
||||
v.Base = (*byte)(unsafe.Pointer(&_zero))
|
||||
}
|
||||
vecs = append(vecs, v)
|
||||
}
|
||||
return vecs
|
||||
}
|
||||
//sys preadvSyscall(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr) (n int, err error) = SYS_PREADV
|
||||
//sys pwritevSyscall(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr) (n int, err error) = SYS_PWRITEV
|
||||
//sys preadv2Syscall(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr, flags int) (n int, err error) = SYS_PREADV2
|
||||
//sys pwritev2Syscall(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr, flags int) (n int, err error) = SYS_PWRITEV2
|
||||
|
||||
// offs2lohi splits offs into its low and high order bits.
|
||||
func offs2lohi(offs int64) (lo, hi uintptr) {
|
||||
@ -2184,69 +2161,23 @@ func offs2lohi(offs int64) (lo, hi uintptr) {
|
||||
return uintptr(offs), uintptr(uint64(offs) >> (longBits - 1) >> 1) // two shifts to avoid false positive in vet
|
||||
}
|
||||
|
||||
func Readv(fd int, iovs [][]byte) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
n, err = readv(fd, iovecs)
|
||||
readvRacedetect(iovecs, n, err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) {
|
||||
lo, hi := offs2lohi(offset)
|
||||
n, err = preadv(fd, iovecs, lo, hi)
|
||||
readvRacedetect(iovecs, n, err)
|
||||
return n, err
|
||||
return preadvSyscall(fd, iovecs, lo, hi)
|
||||
}
|
||||
|
||||
func Preadv2(fd int, iovs [][]byte, offset int64, flags int) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
lo, hi := offs2lohi(offset)
|
||||
n, err = preadv2(fd, iovecs, lo, hi, flags)
|
||||
readvRacedetect(iovecs, n, err)
|
||||
n, err = preadv2Syscall(fd, iovecs, lo, hi, flags)
|
||||
readvRaceDetect(iovecs, n, err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func readvRacedetect(iovecs []Iovec, n int, err error) {
|
||||
if !raceenabled {
|
||||
return
|
||||
}
|
||||
for i := 0; n > 0 && i < len(iovecs); i++ {
|
||||
m := min(int(iovecs[i].Len), n)
|
||||
n -= m
|
||||
if m > 0 {
|
||||
raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
raceAcquire(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
}
|
||||
|
||||
func Writev(fd int, iovs [][]byte) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
if raceenabled {
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
n, err = writev(fd, iovecs)
|
||||
writevRacedetect(iovecs, n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
if raceenabled {
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) {
|
||||
lo, hi := offs2lohi(offset)
|
||||
n, err = pwritev(fd, iovecs, lo, hi)
|
||||
writevRacedetect(iovecs, n)
|
||||
return n, err
|
||||
return pwritevSyscall(fd, iovecs, lo, hi)
|
||||
}
|
||||
|
||||
func Pwritev2(fd int, iovs [][]byte, offset int64, flags int) (n int, err error) {
|
||||
@ -2256,24 +2187,11 @@ func Pwritev2(fd int, iovs [][]byte, offset int64, flags int) (n int, err error)
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
lo, hi := offs2lohi(offset)
|
||||
n, err = pwritev2(fd, iovecs, lo, hi, flags)
|
||||
writevRacedetect(iovecs, n)
|
||||
n, err = pwritev2Syscall(fd, iovecs, lo, hi, flags)
|
||||
writevRaceDetect(iovecs, n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func writevRacedetect(iovecs []Iovec, n int) {
|
||||
if !raceenabled {
|
||||
return
|
||||
}
|
||||
for i := 0; n > 0 && i < len(iovecs); i++ {
|
||||
m := min(int(iovecs[i].Len), n)
|
||||
n -= m
|
||||
if m > 0 {
|
||||
raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mmap varies by architecture; see syscall_linux_*.go.
|
||||
//sys munmap(addr uintptr, length uintptr) (err error)
|
||||
//sys mremap(oldaddr uintptr, oldlength uintptr, newlength uintptr, flags int, newaddr uintptr) (xaddr uintptr, err error)
|
||||
@ -2644,8 +2562,12 @@ func SchedGetAttr(pid int, flags uint) (*SchedAttr, error) {
|
||||
//sys Cachestat(fd uint, crange *CachestatRange, cstat *Cachestat_t, flags uint) (err error)
|
||||
//sys Mseal(b []byte, flags uint) (err error)
|
||||
|
||||
//sys setMemPolicy(mode int, mask *CPUSet, size int) (err error) = SYS_SET_MEMPOLICY
|
||||
//sys setMemPolicy(mode int, mask unsafe.Pointer, size uintptr) (err error) = SYS_SET_MEMPOLICY
|
||||
|
||||
func SetMemPolicy(mode int, mask *CPUSet) error {
|
||||
return setMemPolicy(mode, mask, _CPU_SETSIZE)
|
||||
return setMemPolicy(mode, unsafe.Pointer(mask), _CPU_SETSIZE)
|
||||
}
|
||||
|
||||
func SetMemPolicyDynamic(mode int, mask CPUSetDynamic) error {
|
||||
return setMemPolicy(mode, mask.pointer(), mask.size())
|
||||
}
|
||||
|
||||
3
vendor/golang.org/x/sys/unix/syscall_linux_arm.go
generated
vendored
3
vendor/golang.org/x/sys/unix/syscall_linux_arm.go
generated
vendored
@ -82,6 +82,9 @@ func Time(t *Time_t) (Time_t, error) {
|
||||
}
|
||||
|
||||
func Utime(path string, buf *Utimbuf) error {
|
||||
if buf == nil {
|
||||
return Utimes(path, nil)
|
||||
}
|
||||
tv := []Timeval{
|
||||
{Sec: buf.Actime},
|
||||
{Sec: buf.Modtime},
|
||||
|
||||
3
vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
generated
vendored
3
vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
generated
vendored
@ -113,6 +113,9 @@ func Time(t *Time_t) (Time_t, error) {
|
||||
}
|
||||
|
||||
func Utime(path string, buf *Utimbuf) error {
|
||||
if buf == nil {
|
||||
return Utimes(path, nil)
|
||||
}
|
||||
tv := []Timeval{
|
||||
{Sec: buf.Actime},
|
||||
{Sec: buf.Modtime},
|
||||
|
||||
3
vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
generated
vendored
3
vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
generated
vendored
@ -150,6 +150,9 @@ func Time(t *Time_t) (Time_t, error) {
|
||||
}
|
||||
|
||||
func Utime(path string, buf *Utimbuf) error {
|
||||
if buf == nil {
|
||||
return Utimes(path, nil)
|
||||
}
|
||||
tv := []Timeval{
|
||||
{Sec: buf.Actime},
|
||||
{Sec: buf.Modtime},
|
||||
|
||||
3
vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
generated
vendored
3
vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
generated
vendored
@ -112,6 +112,9 @@ func Time(t *Time_t) (Time_t, error) {
|
||||
}
|
||||
|
||||
func Utime(path string, buf *Utimbuf) error {
|
||||
if buf == nil {
|
||||
return Utimes(path, nil)
|
||||
}
|
||||
tv := []Timeval{
|
||||
{Sec: buf.Actime},
|
||||
{Sec: buf.Modtime},
|
||||
|
||||
4
vendor/golang.org/x/sys/unix/syscall_openbsd.go
generated
vendored
4
vendor/golang.org/x/sys/unix/syscall_openbsd.go
generated
vendored
@ -300,6 +300,10 @@ func Uname(uname *Utsname) error {
|
||||
//sys Pathconf(path string, name int) (val int, err error)
|
||||
//sys pread(fd int, p []byte, offset int64) (n int, err error)
|
||||
//sys pwrite(fd int, p []byte, offset int64) (n int, err error)
|
||||
//sys readv(fd int, iovecs []Iovec) (n int, err error)
|
||||
//sys writev(fd int, iovecs []Iovec) (n int, err error)
|
||||
//sys preadv(fd int, iovecs []Iovec, offset int64) (n int, err error)
|
||||
//sys pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error)
|
||||
//sys read(fd int, p []byte) (n int, err error)
|
||||
//sys Readlink(path string, buf []byte) (n int, err error)
|
||||
//sys Readlinkat(dirfd int, path string, buf []byte) (n int, err error)
|
||||
|
||||
61
vendor/golang.org/x/sys/unix/zerrors_linux.go
generated
vendored
61
vendor/golang.org/x/sys/unix/zerrors_linux.go
generated
vendored
@ -353,8 +353,10 @@ const (
|
||||
AUDIT_MAC_IPSEC_EVENT = 0x587
|
||||
AUDIT_MAC_MAP_ADD = 0x581
|
||||
AUDIT_MAC_MAP_DEL = 0x582
|
||||
AUDIT_MAC_OBJ_CONTEXTS = 0x592
|
||||
AUDIT_MAC_POLICY_LOAD = 0x57b
|
||||
AUDIT_MAC_STATUS = 0x57c
|
||||
AUDIT_MAC_TASK_CONTEXTS = 0x591
|
||||
AUDIT_MAC_UNLBL_ALLOW = 0x57e
|
||||
AUDIT_MAC_UNLBL_STCADD = 0x588
|
||||
AUDIT_MAC_UNLBL_STCDEL = 0x589
|
||||
@ -591,8 +593,13 @@ const (
|
||||
CAN_CTRLMODE_LOOPBACK = 0x1
|
||||
CAN_CTRLMODE_ONE_SHOT = 0x8
|
||||
CAN_CTRLMODE_PRESUME_ACK = 0x40
|
||||
CAN_CTRLMODE_RESTRICTED = 0x800
|
||||
CAN_CTRLMODE_TDC_AUTO = 0x200
|
||||
CAN_CTRLMODE_TDC_MANUAL = 0x400
|
||||
CAN_CTRLMODE_XL = 0x1000
|
||||
CAN_CTRLMODE_XL_TDC_AUTO = 0x2000
|
||||
CAN_CTRLMODE_XL_TDC_MANUAL = 0x4000
|
||||
CAN_CTRLMODE_XL_TMS = 0x8000
|
||||
CAN_EFF_FLAG = 0x80000000
|
||||
CAN_EFF_ID_BITS = 0x1d
|
||||
CAN_EFF_MASK = 0x1fffffff
|
||||
@ -800,6 +807,8 @@ const (
|
||||
DEVLINK_PORT_FN_CAP_IPSEC_PACKET = 0x8
|
||||
DEVLINK_PORT_FN_CAP_MIGRATABLE = 0x2
|
||||
DEVLINK_PORT_FN_CAP_ROCE = 0x1
|
||||
DEVLINK_RATE_TCS_MAX = 0x8
|
||||
DEVLINK_RATE_TC_INDEX_MAX = 0x7
|
||||
DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX = 0x14
|
||||
DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS = 0x3
|
||||
DEVMEM_MAGIC = 0x454d444d
|
||||
@ -1186,6 +1195,7 @@ const (
|
||||
ETH_P_MPLS_UC = 0x8847
|
||||
ETH_P_MRP = 0x88e3
|
||||
ETH_P_MVRP = 0x88f5
|
||||
ETH_P_MXLGSW = 0x88c3
|
||||
ETH_P_NCSI = 0x88f8
|
||||
ETH_P_NSH = 0x894f
|
||||
ETH_P_PAE = 0x888e
|
||||
@ -1218,6 +1228,7 @@ const (
|
||||
ETH_P_WCCP = 0x883e
|
||||
ETH_P_X25 = 0x805
|
||||
ETH_P_XDSA = 0xf8
|
||||
ETH_P_YT921X = 0x9988
|
||||
ET_CORE = 0x4
|
||||
ET_DYN = 0x3
|
||||
ET_EXEC = 0x2
|
||||
@ -1258,6 +1269,7 @@ const (
|
||||
FALLOC_FL_NO_HIDE_STALE = 0x4
|
||||
FALLOC_FL_PUNCH_HOLE = 0x2
|
||||
FALLOC_FL_UNSHARE_RANGE = 0x40
|
||||
FALLOC_FL_WRITE_ZEROES = 0x80
|
||||
FALLOC_FL_ZERO_RANGE = 0x10
|
||||
FANOTIFY_METADATA_VERSION = 0x3
|
||||
FAN_ACCESS = 0x1
|
||||
@ -1477,6 +1489,7 @@ const (
|
||||
GRND_INSECURE = 0x4
|
||||
GRND_NONBLOCK = 0x1
|
||||
GRND_RANDOM = 0x2
|
||||
GUEST_MEMFD_MAGIC = 0x474d454d
|
||||
HDIO_DRIVE_CMD = 0x31f
|
||||
HDIO_DRIVE_CMD_AEB = 0x31e
|
||||
HDIO_DRIVE_CMD_HDR_SIZE = 0x4
|
||||
@ -1517,6 +1530,7 @@ const (
|
||||
HDIO_SET_XFER = 0x306
|
||||
HDIO_TRISTATE_HWIF = 0x31b
|
||||
HDIO_UNREGISTER_HWIF = 0x32a
|
||||
HIDIOCTL_LAST = 0xd
|
||||
HID_MAX_DESCRIPTOR_SIZE = 0x1000
|
||||
HOSTFS_SUPER_MAGIC = 0xc0ffee
|
||||
HPFS_SUPER_MAGIC = 0xf995e849
|
||||
@ -1809,6 +1823,8 @@ const (
|
||||
KEXEC_ARCH_X86_64 = 0x3e0000
|
||||
KEXEC_CRASH_HOTPLUG_SUPPORT = 0x8
|
||||
KEXEC_FILE_DEBUG = 0x8
|
||||
KEXEC_FILE_FORCE_DTB = 0x20
|
||||
KEXEC_FILE_NO_CMA = 0x10
|
||||
KEXEC_FILE_NO_INITRAMFS = 0x4
|
||||
KEXEC_FILE_ON_CRASH = 0x2
|
||||
KEXEC_FILE_UNLOAD = 0x1
|
||||
@ -1905,6 +1921,7 @@ const (
|
||||
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON = 0x2
|
||||
LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF = 0x1
|
||||
LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF = 0x4
|
||||
LANDLOCK_RESTRICT_SELF_TSYNC = 0x8
|
||||
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = 0x1
|
||||
LANDLOCK_SCOPE_SIGNAL = 0x2
|
||||
LINUX_REBOOT_CMD_CAD_OFF = 0x0
|
||||
@ -2412,6 +2429,7 @@ const (
|
||||
NN_PRXFPREG = "LINUX"
|
||||
NN_RISCV_CSR = "LINUX"
|
||||
NN_RISCV_TAGGED_ADDR_CTRL = "LINUX"
|
||||
NN_RISCV_USER_CFI = "LINUX"
|
||||
NN_RISCV_VECTOR = "LINUX"
|
||||
NN_S390_CTRS = "LINUX"
|
||||
NN_S390_GS_BC = "LINUX"
|
||||
@ -2493,6 +2511,7 @@ const (
|
||||
NT_PRXFPREG = 0x46e62b7f
|
||||
NT_RISCV_CSR = 0x900
|
||||
NT_RISCV_TAGGED_ADDR_CTRL = 0x902
|
||||
NT_RISCV_USER_CFI = 0x903
|
||||
NT_RISCV_VECTOR = 0x901
|
||||
NT_S390_CTRS = 0x304
|
||||
NT_S390_GS_BC = 0x30c
|
||||
@ -2515,6 +2534,7 @@ const (
|
||||
NT_X86_SHSTK = 0x204
|
||||
NT_X86_XSAVE_LAYOUT = 0x205
|
||||
NT_X86_XSTATE = 0x202
|
||||
NULL_FS_MAGIC = 0x4e554c4c
|
||||
OCFS2_SUPER_MAGIC = 0x7461636f
|
||||
OCRNL = 0x8
|
||||
OFDEL = 0x80
|
||||
@ -2594,6 +2614,7 @@ const (
|
||||
PERF_ATTR_SIZE_VER6 = 0x78
|
||||
PERF_ATTR_SIZE_VER7 = 0x80
|
||||
PERF_ATTR_SIZE_VER8 = 0x88
|
||||
PERF_ATTR_SIZE_VER9 = 0x90
|
||||
PERF_AUX_FLAG_COLLISION = 0x8
|
||||
PERF_AUX_FLAG_CORESIGHT_FORMAT_CORESIGHT = 0x0
|
||||
PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW = 0x100
|
||||
@ -2629,6 +2650,7 @@ const (
|
||||
PERF_MEM_LVLNUM_ANY_CACHE = 0xb
|
||||
PERF_MEM_LVLNUM_CXL = 0x9
|
||||
PERF_MEM_LVLNUM_IO = 0xa
|
||||
PERF_MEM_LVLNUM_L0 = 0x7
|
||||
PERF_MEM_LVLNUM_L1 = 0x1
|
||||
PERF_MEM_LVLNUM_L2 = 0x2
|
||||
PERF_MEM_LVLNUM_L2_MHB = 0x5
|
||||
@ -2662,6 +2684,23 @@ const (
|
||||
PERF_MEM_OP_PFETCH = 0x8
|
||||
PERF_MEM_OP_SHIFT = 0x0
|
||||
PERF_MEM_OP_STORE = 0x4
|
||||
PERF_MEM_REGION_L_NON_SHARE = 0x3
|
||||
PERF_MEM_REGION_L_SHARE = 0x2
|
||||
PERF_MEM_REGION_MEM0 = 0x8
|
||||
PERF_MEM_REGION_MEM1 = 0x9
|
||||
PERF_MEM_REGION_MEM2 = 0xa
|
||||
PERF_MEM_REGION_MEM3 = 0xb
|
||||
PERF_MEM_REGION_MEM4 = 0xc
|
||||
PERF_MEM_REGION_MEM5 = 0xd
|
||||
PERF_MEM_REGION_MEM6 = 0xe
|
||||
PERF_MEM_REGION_MEM7 = 0xf
|
||||
PERF_MEM_REGION_MMIO = 0x7
|
||||
PERF_MEM_REGION_NA = 0x0
|
||||
PERF_MEM_REGION_O_IO = 0x4
|
||||
PERF_MEM_REGION_O_NON_SHARE = 0x6
|
||||
PERF_MEM_REGION_O_SHARE = 0x5
|
||||
PERF_MEM_REGION_RSVD = 0x1
|
||||
PERF_MEM_REGION_SHIFT = 0x2e
|
||||
PERF_MEM_REMOTE_REMOTE = 0x1
|
||||
PERF_MEM_REMOTE_SHIFT = 0x25
|
||||
PERF_MEM_SNOOPX_FWD = 0x1
|
||||
@ -2776,6 +2815,10 @@ const (
|
||||
PR_CAP_AMBIENT_IS_SET = 0x1
|
||||
PR_CAP_AMBIENT_LOWER = 0x3
|
||||
PR_CAP_AMBIENT_RAISE = 0x2
|
||||
PR_CFI_BRANCH_LANDING_PADS = 0x0
|
||||
PR_CFI_DISABLE = 0x2
|
||||
PR_CFI_ENABLE = 0x1
|
||||
PR_CFI_LOCK = 0x4
|
||||
PR_ENDIAN_BIG = 0x0
|
||||
PR_ENDIAN_LITTLE = 0x1
|
||||
PR_ENDIAN_PPC_LITTLE = 0x2
|
||||
@ -2798,6 +2841,7 @@ const (
|
||||
PR_FUTEX_HASH_GET_SLOTS = 0x2
|
||||
PR_FUTEX_HASH_SET_SLOTS = 0x1
|
||||
PR_GET_AUXV = 0x41555856
|
||||
PR_GET_CFI = 0x50
|
||||
PR_GET_CHILD_SUBREAPER = 0x25
|
||||
PR_GET_DUMPABLE = 0x3
|
||||
PR_GET_ENDIAN = 0x13
|
||||
@ -2834,6 +2878,7 @@ const (
|
||||
PR_MDWE_REFUSE_EXEC_GAIN = 0x1
|
||||
PR_MPX_DISABLE_MANAGEMENT = 0x2c
|
||||
PR_MPX_ENABLE_MANAGEMENT = 0x2b
|
||||
PR_MTE_STORE_ONLY = 0x80000
|
||||
PR_MTE_TAG_MASK = 0x7fff8
|
||||
PR_MTE_TAG_SHIFT = 0x3
|
||||
PR_MTE_TCF_ASYNC = 0x4
|
||||
@ -2877,6 +2922,10 @@ const (
|
||||
PR_RISCV_V_VSTATE_CTRL_NEXT_MASK = 0xc
|
||||
PR_RISCV_V_VSTATE_CTRL_OFF = 0x1
|
||||
PR_RISCV_V_VSTATE_CTRL_ON = 0x2
|
||||
PR_RSEQ_SLICE_EXTENSION = 0x4f
|
||||
PR_RSEQ_SLICE_EXTENSION_GET = 0x1
|
||||
PR_RSEQ_SLICE_EXTENSION_SET = 0x2
|
||||
PR_RSEQ_SLICE_EXT_ENABLE = 0x1
|
||||
PR_SCHED_CORE = 0x3e
|
||||
PR_SCHED_CORE_CREATE = 0x1
|
||||
PR_SCHED_CORE_GET = 0x0
|
||||
@ -2886,6 +2935,7 @@ const (
|
||||
PR_SCHED_CORE_SCOPE_THREAD_GROUP = 0x1
|
||||
PR_SCHED_CORE_SHARE_FROM = 0x3
|
||||
PR_SCHED_CORE_SHARE_TO = 0x2
|
||||
PR_SET_CFI = 0x51
|
||||
PR_SET_CHILD_SUBREAPER = 0x24
|
||||
PR_SET_DUMPABLE = 0x4
|
||||
PR_SET_ENDIAN = 0x14
|
||||
@ -2951,11 +3001,14 @@ const (
|
||||
PR_SVE_SET_VL_ONEXEC = 0x40000
|
||||
PR_SVE_VL_INHERIT = 0x20000
|
||||
PR_SVE_VL_LEN_MASK = 0xffff
|
||||
PR_SYS_DISPATCH_EXCLUSIVE_ON = 0x1
|
||||
PR_SYS_DISPATCH_INCLUSIVE_ON = 0x2
|
||||
PR_SYS_DISPATCH_OFF = 0x0
|
||||
PR_SYS_DISPATCH_ON = 0x1
|
||||
PR_TAGGED_ADDR_ENABLE = 0x1
|
||||
PR_TASK_PERF_EVENTS_DISABLE = 0x1f
|
||||
PR_TASK_PERF_EVENTS_ENABLE = 0x20
|
||||
PR_THP_DISABLE_EXCEPT_ADVISED = 0x2
|
||||
PR_TIMER_CREATE_RESTORE_IDS = 0x4d
|
||||
PR_TIMER_CREATE_RESTORE_IDS_GET = 0x2
|
||||
PR_TIMER_CREATE_RESTORE_IDS_OFF = 0x0
|
||||
@ -2987,8 +3040,10 @@ const (
|
||||
PTP_STRICT_FLAGS = 0x8
|
||||
PTP_SYS_OFFSET_EXTENDED = 0xc4c03d09
|
||||
PTP_SYS_OFFSET_EXTENDED2 = 0xc4c03d12
|
||||
PTP_SYS_OFFSET_EXTENDED_CYCLES = 0xc4c03d16
|
||||
PTP_SYS_OFFSET_PRECISE = 0xc0403d08
|
||||
PTP_SYS_OFFSET_PRECISE2 = 0xc0403d11
|
||||
PTP_SYS_OFFSET_PRECISE_CYCLES = 0xc0403d15
|
||||
PTRACE_ATTACH = 0x10
|
||||
PTRACE_CONT = 0x7
|
||||
PTRACE_DETACH = 0x11
|
||||
@ -3330,8 +3385,9 @@ const (
|
||||
RWF_DSYNC = 0x2
|
||||
RWF_HIPRI = 0x1
|
||||
RWF_NOAPPEND = 0x20
|
||||
RWF_NOSIGNAL = 0x100
|
||||
RWF_NOWAIT = 0x8
|
||||
RWF_SUPPORTED = 0xff
|
||||
RWF_SUPPORTED = 0x1ff
|
||||
RWF_SYNC = 0x4
|
||||
RWF_WRITE_LIFE_NOT_SET = 0x0
|
||||
SCHED_BATCH = 0x3
|
||||
@ -3714,7 +3770,7 @@ const (
|
||||
TASKSTATS_GENL_NAME = "TASKSTATS"
|
||||
TASKSTATS_GENL_VERSION = 0x1
|
||||
TASKSTATS_TYPE_MAX = 0x6
|
||||
TASKSTATS_VERSION = 0x10
|
||||
TASKSTATS_VERSION = 0x11
|
||||
TCIFLUSH = 0x0
|
||||
TCIOFF = 0x2
|
||||
TCIOFLUSH = 0x2
|
||||
@ -4052,6 +4108,7 @@ const (
|
||||
XDP_FLAGS_REPLACE = 0x10
|
||||
XDP_FLAGS_SKB_MODE = 0x2
|
||||
XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1
|
||||
XDP_MAX_TX_SKB_BUDGET = 0x9
|
||||
XDP_MMAP_OFFSETS = 0x1
|
||||
XDP_OPTIONS = 0x8
|
||||
XDP_OPTIONS_ZEROCOPY = 0x1
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_386.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_386.go
generated
vendored
@ -159,6 +159,7 @@ const (
|
||||
NFDBITS = 0x20
|
||||
NLDLY = 0x100
|
||||
NOFLSH = 0x80
|
||||
NS_GET_ID = 0x8008b70d
|
||||
NS_GET_MNTNS_ID = 0x8008b705
|
||||
NS_GET_NSTYPE = 0xb703
|
||||
NS_GET_OWNER_UID = 0xb704
|
||||
@ -305,6 +306,7 @@ const (
|
||||
RTC_WKALM_SET = 0x4028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -352,6 +354,7 @@ const (
|
||||
SO_ERROR = 0x4
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x9
|
||||
SO_LINGER = 0xd
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -596,6 +599,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x59)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x7a)
|
||||
EFSBADCRC = syscall.Errno(0x4a)
|
||||
EFSCORRUPTED = syscall.Errno(0x75)
|
||||
EHOSTDOWN = syscall.Errno(0x70)
|
||||
EHOSTUNREACH = syscall.Errno(0x71)
|
||||
EHWPOISON = syscall.Errno(0x85)
|
||||
@ -819,7 +824,7 @@ var errorList = [...]struct {
|
||||
{114, "EALREADY", "operation already in progress"},
|
||||
{115, "EINPROGRESS", "operation now in progress"},
|
||||
{116, "ESTALE", "stale file handle"},
|
||||
{117, "EUCLEAN", "structure needs cleaning"},
|
||||
{117, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{118, "ENOTNAM", "not a XENIX named type file"},
|
||||
{119, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{120, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
generated
vendored
@ -159,6 +159,7 @@ const (
|
||||
NFDBITS = 0x40
|
||||
NLDLY = 0x100
|
||||
NOFLSH = 0x80
|
||||
NS_GET_ID = 0x8008b70d
|
||||
NS_GET_MNTNS_ID = 0x8008b705
|
||||
NS_GET_NSTYPE = 0xb703
|
||||
NS_GET_OWNER_UID = 0xb704
|
||||
@ -306,6 +307,7 @@ const (
|
||||
RTC_WKALM_SET = 0x4028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -353,6 +355,7 @@ const (
|
||||
SO_ERROR = 0x4
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x9
|
||||
SO_LINGER = 0xd
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -596,6 +599,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x59)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x7a)
|
||||
EFSBADCRC = syscall.Errno(0x4a)
|
||||
EFSCORRUPTED = syscall.Errno(0x75)
|
||||
EHOSTDOWN = syscall.Errno(0x70)
|
||||
EHOSTUNREACH = syscall.Errno(0x71)
|
||||
EHWPOISON = syscall.Errno(0x85)
|
||||
@ -819,7 +824,7 @@ var errorList = [...]struct {
|
||||
{114, "EALREADY", "operation already in progress"},
|
||||
{115, "EINPROGRESS", "operation now in progress"},
|
||||
{116, "ESTALE", "stale file handle"},
|
||||
{117, "EUCLEAN", "structure needs cleaning"},
|
||||
{117, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{118, "ENOTNAM", "not a XENIX named type file"},
|
||||
{119, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{120, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
generated
vendored
@ -156,6 +156,7 @@ const (
|
||||
NFDBITS = 0x20
|
||||
NLDLY = 0x100
|
||||
NOFLSH = 0x80
|
||||
NS_GET_ID = 0x8008b70d
|
||||
NS_GET_MNTNS_ID = 0x8008b705
|
||||
NS_GET_NSTYPE = 0xb703
|
||||
NS_GET_OWNER_UID = 0xb704
|
||||
@ -311,6 +312,7 @@ const (
|
||||
RTC_WKALM_SET = 0x4028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -358,6 +360,7 @@ const (
|
||||
SO_ERROR = 0x4
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x9
|
||||
SO_LINGER = 0xd
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -601,6 +604,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x59)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x7a)
|
||||
EFSBADCRC = syscall.Errno(0x4a)
|
||||
EFSCORRUPTED = syscall.Errno(0x75)
|
||||
EHOSTDOWN = syscall.Errno(0x70)
|
||||
EHOSTUNREACH = syscall.Errno(0x71)
|
||||
EHWPOISON = syscall.Errno(0x85)
|
||||
@ -824,7 +829,7 @@ var errorList = [...]struct {
|
||||
{114, "EALREADY", "operation already in progress"},
|
||||
{115, "EINPROGRESS", "operation now in progress"},
|
||||
{116, "ESTALE", "stale file handle"},
|
||||
{117, "EUCLEAN", "structure needs cleaning"},
|
||||
{117, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{118, "ENOTNAM", "not a XENIX named type file"},
|
||||
{119, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{120, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
generated
vendored
@ -161,6 +161,7 @@ const (
|
||||
NFDBITS = 0x40
|
||||
NLDLY = 0x100
|
||||
NOFLSH = 0x80
|
||||
NS_GET_ID = 0x8008b70d
|
||||
NS_GET_MNTNS_ID = 0x8008b705
|
||||
NS_GET_NSTYPE = 0xb703
|
||||
NS_GET_OWNER_UID = 0xb704
|
||||
@ -304,6 +305,7 @@ const (
|
||||
RTC_WKALM_SET = 0x4028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -351,6 +353,7 @@ const (
|
||||
SO_ERROR = 0x4
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x9
|
||||
SO_LINGER = 0xd
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -598,6 +601,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x59)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x7a)
|
||||
EFSBADCRC = syscall.Errno(0x4a)
|
||||
EFSCORRUPTED = syscall.Errno(0x75)
|
||||
EHOSTDOWN = syscall.Errno(0x70)
|
||||
EHOSTUNREACH = syscall.Errno(0x71)
|
||||
EHWPOISON = syscall.Errno(0x85)
|
||||
@ -821,7 +826,7 @@ var errorList = [...]struct {
|
||||
{114, "EALREADY", "operation already in progress"},
|
||||
{115, "EINPROGRESS", "operation now in progress"},
|
||||
{116, "ESTALE", "stale file handle"},
|
||||
{117, "EUCLEAN", "structure needs cleaning"},
|
||||
{117, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{118, "ENOTNAM", "not a XENIX named type file"},
|
||||
{119, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{120, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
generated
vendored
@ -160,6 +160,7 @@ const (
|
||||
NFDBITS = 0x40
|
||||
NLDLY = 0x100
|
||||
NOFLSH = 0x80
|
||||
NS_GET_ID = 0x8008b70d
|
||||
NS_GET_MNTNS_ID = 0x8008b705
|
||||
NS_GET_NSTYPE = 0xb703
|
||||
NS_GET_OWNER_UID = 0xb704
|
||||
@ -298,6 +299,7 @@ const (
|
||||
RTC_WKALM_SET = 0x4028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -345,6 +347,7 @@ const (
|
||||
SO_ERROR = 0x4
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x9
|
||||
SO_LINGER = 0xd
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -588,6 +591,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x59)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x7a)
|
||||
EFSBADCRC = syscall.Errno(0x4a)
|
||||
EFSCORRUPTED = syscall.Errno(0x75)
|
||||
EHOSTDOWN = syscall.Errno(0x70)
|
||||
EHOSTUNREACH = syscall.Errno(0x71)
|
||||
EHWPOISON = syscall.Errno(0x85)
|
||||
@ -811,7 +816,7 @@ var errorList = [...]struct {
|
||||
{114, "EALREADY", "operation already in progress"},
|
||||
{115, "EINPROGRESS", "operation now in progress"},
|
||||
{116, "ESTALE", "stale file handle"},
|
||||
{117, "EUCLEAN", "structure needs cleaning"},
|
||||
{117, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{118, "ENOTNAM", "not a XENIX named type file"},
|
||||
{119, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{120, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
generated
vendored
@ -156,6 +156,7 @@ const (
|
||||
NFDBITS = 0x20
|
||||
NLDLY = 0x100
|
||||
NOFLSH = 0x80
|
||||
NS_GET_ID = 0x4008b70d
|
||||
NS_GET_MNTNS_ID = 0x4008b705
|
||||
NS_GET_NSTYPE = 0x2000b703
|
||||
NS_GET_OWNER_UID = 0x2000b704
|
||||
@ -304,6 +305,7 @@ const (
|
||||
RTC_WKALM_SET = 0x8028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -351,6 +353,7 @@ const (
|
||||
SO_ERROR = 0x1007
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x8
|
||||
SO_LINGER = 0x80
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -597,6 +600,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x60)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x46d)
|
||||
EFSBADCRC = syscall.Errno(0x4d)
|
||||
EFSCORRUPTED = syscall.Errno(0x87)
|
||||
EHOSTDOWN = syscall.Errno(0x93)
|
||||
EHOSTUNREACH = syscall.Errno(0x94)
|
||||
EHWPOISON = syscall.Errno(0xa8)
|
||||
@ -814,7 +819,7 @@ var errorList = [...]struct {
|
||||
{132, "ENOBUFS", "no buffer space available"},
|
||||
{133, "EISCONN", "transport endpoint is already connected"},
|
||||
{134, "ENOTCONN", "transport endpoint is not connected"},
|
||||
{135, "EUCLEAN", "structure needs cleaning"},
|
||||
{135, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{137, "ENOTNAM", "not a XENIX named type file"},
|
||||
{138, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{139, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
generated
vendored
@ -156,6 +156,7 @@ const (
|
||||
NFDBITS = 0x40
|
||||
NLDLY = 0x100
|
||||
NOFLSH = 0x80
|
||||
NS_GET_ID = 0x4008b70d
|
||||
NS_GET_MNTNS_ID = 0x4008b705
|
||||
NS_GET_NSTYPE = 0x2000b703
|
||||
NS_GET_OWNER_UID = 0x2000b704
|
||||
@ -304,6 +305,7 @@ const (
|
||||
RTC_WKALM_SET = 0x8028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -351,6 +353,7 @@ const (
|
||||
SO_ERROR = 0x1007
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x8
|
||||
SO_LINGER = 0x80
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -597,6 +600,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x60)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x46d)
|
||||
EFSBADCRC = syscall.Errno(0x4d)
|
||||
EFSCORRUPTED = syscall.Errno(0x87)
|
||||
EHOSTDOWN = syscall.Errno(0x93)
|
||||
EHOSTUNREACH = syscall.Errno(0x94)
|
||||
EHWPOISON = syscall.Errno(0xa8)
|
||||
@ -814,7 +819,7 @@ var errorList = [...]struct {
|
||||
{132, "ENOBUFS", "no buffer space available"},
|
||||
{133, "EISCONN", "transport endpoint is already connected"},
|
||||
{134, "ENOTCONN", "transport endpoint is not connected"},
|
||||
{135, "EUCLEAN", "structure needs cleaning"},
|
||||
{135, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{137, "ENOTNAM", "not a XENIX named type file"},
|
||||
{138, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{139, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
generated
vendored
@ -156,6 +156,7 @@ const (
|
||||
NFDBITS = 0x40
|
||||
NLDLY = 0x100
|
||||
NOFLSH = 0x80
|
||||
NS_GET_ID = 0x4008b70d
|
||||
NS_GET_MNTNS_ID = 0x4008b705
|
||||
NS_GET_NSTYPE = 0x2000b703
|
||||
NS_GET_OWNER_UID = 0x2000b704
|
||||
@ -304,6 +305,7 @@ const (
|
||||
RTC_WKALM_SET = 0x8028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -351,6 +353,7 @@ const (
|
||||
SO_ERROR = 0x1007
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x8
|
||||
SO_LINGER = 0x80
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -597,6 +600,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x60)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x46d)
|
||||
EFSBADCRC = syscall.Errno(0x4d)
|
||||
EFSCORRUPTED = syscall.Errno(0x87)
|
||||
EHOSTDOWN = syscall.Errno(0x93)
|
||||
EHOSTUNREACH = syscall.Errno(0x94)
|
||||
EHWPOISON = syscall.Errno(0xa8)
|
||||
@ -814,7 +819,7 @@ var errorList = [...]struct {
|
||||
{132, "ENOBUFS", "no buffer space available"},
|
||||
{133, "EISCONN", "transport endpoint is already connected"},
|
||||
{134, "ENOTCONN", "transport endpoint is not connected"},
|
||||
{135, "EUCLEAN", "structure needs cleaning"},
|
||||
{135, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{137, "ENOTNAM", "not a XENIX named type file"},
|
||||
{138, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{139, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
generated
vendored
@ -156,6 +156,7 @@ const (
|
||||
NFDBITS = 0x20
|
||||
NLDLY = 0x100
|
||||
NOFLSH = 0x80
|
||||
NS_GET_ID = 0x4008b70d
|
||||
NS_GET_MNTNS_ID = 0x4008b705
|
||||
NS_GET_NSTYPE = 0x2000b703
|
||||
NS_GET_OWNER_UID = 0x2000b704
|
||||
@ -304,6 +305,7 @@ const (
|
||||
RTC_WKALM_SET = 0x8028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -351,6 +353,7 @@ const (
|
||||
SO_ERROR = 0x1007
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x8
|
||||
SO_LINGER = 0x80
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -597,6 +600,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x60)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x46d)
|
||||
EFSBADCRC = syscall.Errno(0x4d)
|
||||
EFSCORRUPTED = syscall.Errno(0x87)
|
||||
EHOSTDOWN = syscall.Errno(0x93)
|
||||
EHOSTUNREACH = syscall.Errno(0x94)
|
||||
EHWPOISON = syscall.Errno(0xa8)
|
||||
@ -814,7 +819,7 @@ var errorList = [...]struct {
|
||||
{132, "ENOBUFS", "no buffer space available"},
|
||||
{133, "EISCONN", "transport endpoint is already connected"},
|
||||
{134, "ENOTCONN", "transport endpoint is not connected"},
|
||||
{135, "EUCLEAN", "structure needs cleaning"},
|
||||
{135, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{137, "ENOTNAM", "not a XENIX named type file"},
|
||||
{138, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{139, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
generated
vendored
@ -158,6 +158,7 @@ const (
|
||||
NL3 = 0x300
|
||||
NLDLY = 0x300
|
||||
NOFLSH = 0x80000000
|
||||
NS_GET_ID = 0x4008b70d
|
||||
NS_GET_MNTNS_ID = 0x4008b705
|
||||
NS_GET_NSTYPE = 0x2000b703
|
||||
NS_GET_OWNER_UID = 0x2000b704
|
||||
@ -359,6 +360,7 @@ const (
|
||||
RTC_WKALM_SET = 0x8028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -406,6 +408,7 @@ const (
|
||||
SO_ERROR = 0x4
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x9
|
||||
SO_LINGER = 0xd
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -653,6 +656,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x59)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x7a)
|
||||
EFSBADCRC = syscall.Errno(0x4a)
|
||||
EFSCORRUPTED = syscall.Errno(0x75)
|
||||
EHOSTDOWN = syscall.Errno(0x70)
|
||||
EHOSTUNREACH = syscall.Errno(0x71)
|
||||
EHWPOISON = syscall.Errno(0x85)
|
||||
@ -877,7 +882,7 @@ var errorList = [...]struct {
|
||||
{114, "EALREADY", "operation already in progress"},
|
||||
{115, "EINPROGRESS", "operation now in progress"},
|
||||
{116, "ESTALE", "stale file handle"},
|
||||
{117, "EUCLEAN", "structure needs cleaning"},
|
||||
{117, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{118, "ENOTNAM", "not a XENIX named type file"},
|
||||
{119, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{120, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
generated
vendored
@ -158,6 +158,7 @@ const (
|
||||
NL3 = 0x300
|
||||
NLDLY = 0x300
|
||||
NOFLSH = 0x80000000
|
||||
NS_GET_ID = 0x4008b70d
|
||||
NS_GET_MNTNS_ID = 0x4008b705
|
||||
NS_GET_NSTYPE = 0x2000b703
|
||||
NS_GET_OWNER_UID = 0x2000b704
|
||||
@ -363,6 +364,7 @@ const (
|
||||
RTC_WKALM_SET = 0x8028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -410,6 +412,7 @@ const (
|
||||
SO_ERROR = 0x4
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x9
|
||||
SO_LINGER = 0xd
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -657,6 +660,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x59)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x7a)
|
||||
EFSBADCRC = syscall.Errno(0x4a)
|
||||
EFSCORRUPTED = syscall.Errno(0x75)
|
||||
EHOSTDOWN = syscall.Errno(0x70)
|
||||
EHOSTUNREACH = syscall.Errno(0x71)
|
||||
EHWPOISON = syscall.Errno(0x85)
|
||||
@ -881,7 +886,7 @@ var errorList = [...]struct {
|
||||
{114, "EALREADY", "operation already in progress"},
|
||||
{115, "EINPROGRESS", "operation now in progress"},
|
||||
{116, "ESTALE", "stale file handle"},
|
||||
{117, "EUCLEAN", "structure needs cleaning"},
|
||||
{117, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{118, "ENOTNAM", "not a XENIX named type file"},
|
||||
{119, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{120, "EISNAM", "is a named type file"},
|
||||
|
||||
7
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
generated
vendored
7
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
generated
vendored
@ -158,6 +158,7 @@ const (
|
||||
NL3 = 0x300
|
||||
NLDLY = 0x300
|
||||
NOFLSH = 0x80000000
|
||||
NS_GET_ID = 0x4008b70d
|
||||
NS_GET_MNTNS_ID = 0x4008b705
|
||||
NS_GET_NSTYPE = 0x2000b703
|
||||
NS_GET_OWNER_UID = 0x2000b704
|
||||
@ -363,6 +364,7 @@ const (
|
||||
RTC_WKALM_SET = 0x8028700f
|
||||
SCM_DEVMEM_DMABUF = 0x4f
|
||||
SCM_DEVMEM_LINEAR = 0x4e
|
||||
SCM_INQ = 0x54
|
||||
SCM_TIMESTAMPING = 0x25
|
||||
SCM_TIMESTAMPING_OPT_STATS = 0x36
|
||||
SCM_TIMESTAMPING_PKTINFO = 0x3a
|
||||
@ -410,6 +412,7 @@ const (
|
||||
SO_ERROR = 0x4
|
||||
SO_INCOMING_CPU = 0x31
|
||||
SO_INCOMING_NAPI_ID = 0x38
|
||||
SO_INQ = 0x54
|
||||
SO_KEEPALIVE = 0x9
|
||||
SO_LINGER = 0xd
|
||||
SO_LOCK_FILTER = 0x2c
|
||||
@ -657,6 +660,8 @@ const (
|
||||
EDESTADDRREQ = syscall.Errno(0x59)
|
||||
EDOTDOT = syscall.Errno(0x49)
|
||||
EDQUOT = syscall.Errno(0x7a)
|
||||
EFSBADCRC = syscall.Errno(0x4a)
|
||||
EFSCORRUPTED = syscall.Errno(0x75)
|
||||
EHOSTDOWN = syscall.Errno(0x70)
|
||||
EHOSTUNREACH = syscall.Errno(0x71)
|
||||
EHWPOISON = syscall.Errno(0x85)
|
||||
@ -881,7 +886,7 @@ var errorList = [...]struct {
|
||||
{114, "EALREADY", "operation already in progress"},
|
||||
{115, "EINPROGRESS", "operation now in progress"},
|
||||
{116, "ESTALE", "stale file handle"},
|
||||
{117, "EUCLEAN", "structure needs cleaning"},
|
||||
{117, "EFSCORRUPTED", "structure needs cleaning"},
|
||||
{118, "ENOTNAM", "not a XENIX named type file"},
|
||||
{119, "ENAVAIL", "no XENIX semaphores available"},
|
||||
{120, "EISNAM", "is a named type file"},
|
||||
|
||||
1114
vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
generated
vendored
1114
vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
generated
vendored
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user