Compare commits
No commits in common. "master" and "1.0.2" have entirely different histories.
113
.drone.yml
113
.drone.yml
@ -1,71 +1,88 @@
|
|||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
type: docker
|
type: docker
|
||||||
name: build-linux
|
name: build-linux-amd64
|
||||||
|
|
||||||
|
environment:
|
||||||
|
GOOS: linux
|
||||||
|
GOARCH: amd64
|
||||||
|
GOOPTIONS: -mod=vendor
|
||||||
|
SRCFILES: cmd/go-aptproxy/*.go
|
||||||
|
PROJECTNAME: go-aptproxy
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build-linux-amd64
|
- name: build
|
||||||
|
image: golang
|
||||||
|
environment:
|
||||||
|
VERSION: dev
|
||||||
|
commands:
|
||||||
|
- go generate $SRCFILES
|
||||||
|
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: build-linux-arm64
|
||||||
|
|
||||||
|
environment:
|
||||||
|
GOOS: linux
|
||||||
|
GOARCH: arm64
|
||||||
|
GOOPTIONS: -mod=vendor
|
||||||
|
SRCFILES: cmd/go-aptproxy/*.go
|
||||||
|
PROJECTNAME: go-aptproxy
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build
|
||||||
|
image: golang
|
||||||
|
environment:
|
||||||
|
VERSION: dev
|
||||||
|
commands:
|
||||||
|
- go generate $SRCFILES
|
||||||
|
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: gitea-release
|
||||||
|
|
||||||
|
environment:
|
||||||
|
GOOS: linux
|
||||||
|
GOOPTIONS: -mod=vendor
|
||||||
|
SRCFILES: cmd/go-aptproxy/*.go
|
||||||
|
PROJECTNAME: go-aptproxy
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build-amd64
|
||||||
image: golang
|
image: golang
|
||||||
commands:
|
|
||||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
|
||||||
environment:
|
environment:
|
||||||
GOOS: linux
|
|
||||||
GOARCH: amd64
|
GOARCH: amd64
|
||||||
GOOPTIONS: -mod=vendor
|
|
||||||
SRCFILES: cmd/go-aptproxy/*.go
|
|
||||||
PROJECTNAME: go-aptproxy
|
|
||||||
when:
|
|
||||||
event:
|
|
||||||
exclude:
|
|
||||||
- tag
|
|
||||||
- name: build-linux-arm64
|
|
||||||
image: golang
|
|
||||||
commands:
|
|
||||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
|
||||||
environment:
|
|
||||||
GOOS: linux
|
|
||||||
GOARCH: arm64
|
|
||||||
GOOPTIONS: -mod=vendor
|
|
||||||
SRCFILES: cmd/go-aptproxy/*.go
|
|
||||||
PROJECTNAME: go-aptproxy
|
|
||||||
when:
|
|
||||||
event:
|
|
||||||
exclude:
|
|
||||||
- tag
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: gitea-release-linux
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build-linux-amd64
|
|
||||||
image: golang
|
|
||||||
commands:
|
commands:
|
||||||
|
- export VERSION=$DRONE_TAG
|
||||||
|
- go generate $SRCFILES
|
||||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
||||||
- tar -czvf $PROJECTNAME-$DRONE_TAG-$GOOS-$GOARCH.tar.gz $PROJECTNAME
|
- tar -czvf $PROJECTNAME-$DRONE_TAG-$GOOS-$GOARCH.tar.gz $PROJECTNAME
|
||||||
- echo $PROJECTNAME $DRONE_TAG > VERSION
|
- echo $PROJECTNAME $DRONE_TAG > VERSION
|
||||||
environment:
|
|
||||||
GOOS: linux
|
|
||||||
GOARCH: amd64
|
|
||||||
GOOPTIONS: -mod=vendor
|
|
||||||
SRCFILES: cmd/go-aptproxy/*.go
|
|
||||||
PROJECTNAME: go-aptproxy
|
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- tag
|
- tag
|
||||||
- name: build-linux-arm64
|
- name: build-arm64
|
||||||
image: golang
|
image: golang
|
||||||
|
environment:
|
||||||
|
GOARCH: arm64
|
||||||
commands:
|
commands:
|
||||||
|
- export VERSION=$DRONE_TAG
|
||||||
|
- go generate $SRCFILES
|
||||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
||||||
- tar -czvf $PROJECTNAME-$DRONE_TAG-$GOOS-$GOARCH.tar.gz $PROJECTNAME
|
- tar -czvf $PROJECTNAME-$DRONE_TAG-$GOOS-$GOARCH.tar.gz $PROJECTNAME
|
||||||
- echo $PROJECTNAME $DRONE_TAG > VERSION
|
- echo $PROJECTNAME $DRONE_TAG > VERSION
|
||||||
environment:
|
|
||||||
GOOS: linux
|
|
||||||
GOARCH: arm64
|
|
||||||
GOOPTIONS: -mod=vendor
|
|
||||||
SRCFILES: cmd/go-aptproxy/*.go
|
|
||||||
PROJECTNAME: go-aptproxy
|
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- tag
|
- tag
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
|||||||
/go-aptproxy*
|
/go-aptproxy
|
||||||
|
67
ci-build.sh
Executable file
67
ci-build.sh
Executable file
@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
PROJECTNAME="go-aptproxy"
|
||||||
|
RELEASENAME=${PROJECTNAME}
|
||||||
|
VERSION="0"
|
||||||
|
|
||||||
|
GOOPTIONS="-mod=vendor"
|
||||||
|
SRCFILES=cmd/${PROJECTNAME}/*.go
|
||||||
|
|
||||||
|
build() {
|
||||||
|
echo "Begin of build"
|
||||||
|
if [[ ! -z ${DRONE_TAG} ]]
|
||||||
|
then
|
||||||
|
echo "Drone tag set, let's do a release"
|
||||||
|
VERSION=${DRONE_TAG}
|
||||||
|
echo "${PROJECTNAME} ${VERSION}" > /build/VERSION
|
||||||
|
elif [[ ! -z ${DRONE_COMMIT} ]]
|
||||||
|
then
|
||||||
|
echo "Drone not set, let's only do a build"
|
||||||
|
VERSION=${DRONE_COMMIT}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -z ${VERSION} && ! -z ${GOOS} && ! -z ${GOARCH} ]]
|
||||||
|
then
|
||||||
|
echo "Let's set a release name"
|
||||||
|
RELEASENAME=${PROJECTNAME}-${VERSION}-${GOOS}-${GOARCH}
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building project"
|
||||||
|
go generate ${SRCFILES}
|
||||||
|
go build -o ${PROJECTNAME} ${GOOPTIONS} ${SRCFILES}
|
||||||
|
|
||||||
|
if [[ ! -z ${DRONE_TAG} ]]
|
||||||
|
then
|
||||||
|
echo "Let's make archives"
|
||||||
|
mkdir -p /build
|
||||||
|
tar -czvf /build/${RELEASENAME}.tar.gz ${PROJECTNAME}
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Removing binary file"
|
||||||
|
rm ${PROJECTNAME}
|
||||||
|
|
||||||
|
echo "End of build"
|
||||||
|
}
|
||||||
|
|
||||||
|
clean() {
|
||||||
|
rm -rf ${RELEASEDIR}
|
||||||
|
for i in ${PROJECTNAME} "cmd/${PROJECTNAME}/packrd" "cmd/${PROJECTNAME}/main-packr.go"
|
||||||
|
do
|
||||||
|
rm -rf ${i}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
"build")
|
||||||
|
build
|
||||||
|
;;
|
||||||
|
"clean")
|
||||||
|
clean
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "No options choosen"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
@ -20,13 +20,12 @@ func main() {
|
|||||||
host = flag.String("host", "0.0.0.0", "`host` to listen on")
|
host = flag.String("host", "0.0.0.0", "`host` to listen on")
|
||||||
port = flag.Int("port", 8000, "`port` to listen on")
|
port = flag.Int("port", 8000, "`port` to listen on")
|
||||||
directory = flag.String("directory", "/var/cache/go-aptproxy", "`directory` used for storing packages")
|
directory = flag.String("directory", "/var/cache/go-aptproxy", "`directory` used for storing packages")
|
||||||
migrate = flag.Bool("migrate", false, "`migrate` applies operations to be done on go-aptproxy update")
|
|
||||||
)
|
)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// Create the HTTP server and initialize the cache
|
// Create the HTTP server and initialize the cache
|
||||||
addr := fmt.Sprintf("%s:%d", *host, *port)
|
addr := fmt.Sprintf("%s:%d", *host, *port)
|
||||||
httpServer, err := server.NewServer(addr, *directory, *migrate)
|
httpServer, err := server.NewServer(addr, *directory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
14
go.mod
14
go.mod
@ -1,18 +1,16 @@
|
|||||||
module github.com/paulbsd/go-aptproxy
|
module github.com/paulbsd/go-aptproxy
|
||||||
|
|
||||||
go 1.20
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fsnotify/fsnotify v1.6.0
|
github.com/fsnotify/fsnotify v1.5.1
|
||||||
github.com/hashicorp/mdns v1.0.5
|
github.com/hashicorp/mdns v1.0.4
|
||||||
github.com/hectane/go-asyncserver v0.1.0
|
github.com/hectane/go-asyncserver v0.1.0
|
||||||
github.com/pquerna/cachecontrol v0.1.0
|
github.com/pquerna/cachecontrol v0.1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/miekg/dns v1.1.50 // indirect
|
github.com/miekg/dns v1.1.43 // indirect
|
||||||
golang.org/x/mod v0.6.0 // indirect
|
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 // indirect
|
||||||
golang.org/x/net v0.1.0 // indirect
|
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect
|
||||||
golang.org/x/sys v0.1.0 // indirect
|
|
||||||
golang.org/x/tools v0.1.12 // indirect
|
|
||||||
)
|
)
|
||||||
|
49
go.sum
49
go.sum
@ -1,14 +1,14 @@
|
|||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||||
github.com/hashicorp/mdns v1.0.5 h1:1M5hW1cunYeoXOqHwEb/GBDDHAFo0Yqb/uz/beC6LbE=
|
github.com/hashicorp/mdns v1.0.4 h1:sY0CMhFmjIPDMlTB+HfymFHCaYLhgifZ0QhjaYKD/UQ=
|
||||||
github.com/hashicorp/mdns v1.0.5/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||||
github.com/hectane/go-asyncserver v0.1.0 h1:miQMVjLchB0fklo4nKoUp3votMOCSJhddVlPSmyiieM=
|
github.com/hectane/go-asyncserver v0.1.0 h1:miQMVjLchB0fklo4nKoUp3votMOCSJhddVlPSmyiieM=
|
||||||
github.com/hectane/go-asyncserver v0.1.0/go.mod h1:waBaOSU0nKsRCHYMISp/+MSakn6C5HyDSF3y0NUknu0=
|
github.com/hectane/go-asyncserver v0.1.0/go.mod h1:waBaOSU0nKsRCHYMISp/+MSakn6C5HyDSF3y0NUknu0=
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
|
||||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc=
|
github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc=
|
||||||
@ -16,46 +16,27 @@ github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQ
|
|||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
|
|
||||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
|
||||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||||
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 h1:0qxwC5n+ttVOINCBeRHO0nq9X7uy8SDsPoi5OaCdIEI=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c h1:DHcbWVXeY+0Y8HHKR+rbLwnoh2F4tNCY7rTiHJ30RmA=
|
||||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc=
|
||||||
|
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
56
src/cache/cache.go
vendored
56
src/cache/cache.go
vendored
@ -8,17 +8,15 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var filepattern = regexp.MustCompile(`((In)?Release(\.gpg)?|Packages(\.gz|\.bz2)?|Contents-(arm64|armhf|amd64)(\.gz)|Sources.bz2?)`)
|
var filepattern = regexp.MustCompile(`((In)?Release(.gpg)?|Packages.(gz|bz2))`)
|
||||||
|
|
||||||
// Reader is a generic interface for reading cache entries either from disk or
|
// Reader is a generic interface for reading cache entries either from disk or
|
||||||
// directly attached to a downloader.
|
// directly attached to a downloader.
|
||||||
@ -46,16 +44,6 @@ func NewCache(directory string) (*Cache, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFilenames returns the filenames for the JSON and data files from a URL.
|
|
||||||
func getRelURL(rawurl string) (relurl string) {
|
|
||||||
parsed, err := url.Parse(rawurl)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
relurl = parsed.Path
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFilenames returns the filenames for the JSON and data files from a URL.
|
// getFilenames returns the filenames for the JSON and data files from a URL.
|
||||||
func (c *Cache) getFilenames(rawurl string) (hash, jsonFilename, dataFilename string) {
|
func (c *Cache) getFilenames(rawurl string) (hash, jsonFilename, dataFilename string) {
|
||||||
b := md5.Sum([]byte(rawurl))
|
b := md5.Sum([]byte(rawurl))
|
||||||
@ -70,8 +58,7 @@ func (c *Cache) getFilenames(rawurl string) (hash, jsonFilename, dataFilename st
|
|||||||
// If the URL exists in the cache, it is read using the standard file API. If
|
// If the URL exists in the cache, it is read using the standard file API. If
|
||||||
// not, a downloader and live reader are created.
|
// not, a downloader and live reader are created.
|
||||||
func (c *Cache) GetReader(rawurl string, maxAge time.Duration) (Reader, error) {
|
func (c *Cache) GetReader(rawurl string, maxAge time.Duration) (Reader, error) {
|
||||||
relurl := getRelURL(rawurl)
|
hash, jsonFilename, dataFilename := c.getFilenames(rawurl)
|
||||||
hash, jsonFilename, dataFilename := c.getFilenames(relurl)
|
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
d, ok := c.downloaders[hash]
|
d, ok := c.downloaders[hash]
|
||||||
@ -113,8 +100,7 @@ func (c *Cache) GetReader(rawurl string, maxAge time.Duration) (Reader, error) {
|
|||||||
|
|
||||||
// Insert adds an item into the cache.
|
// Insert adds an item into the cache.
|
||||||
func (c *Cache) Insert(rawurl string, r io.Reader) error {
|
func (c *Cache) Insert(rawurl string, r io.Reader) error {
|
||||||
relurl := getRelURL(rawurl)
|
_, jsonFilename, dataFilename := c.getFilenames(rawurl)
|
||||||
_, jsonFilename, dataFilename := c.getFilenames(relurl)
|
|
||||||
f, err := os.Open(dataFilename)
|
f, err := os.Open(dataFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -126,12 +112,10 @@ func (c *Cache) Insert(rawurl string, r io.Reader) error {
|
|||||||
}
|
}
|
||||||
e := &Entry{
|
e := &Entry{
|
||||||
URL: rawurl,
|
URL: rawurl,
|
||||||
RelURL: relurl,
|
|
||||||
Complete: true,
|
Complete: true,
|
||||||
ContentLength: strconv.FormatInt(n, 10),
|
ContentLength: strconv.FormatInt(n, 10),
|
||||||
ContentType: mime.TypeByExtension(rawurl),
|
ContentType: mime.TypeByExtension(rawurl),
|
||||||
LastModified: time.Now().Format(http.TimeFormat),
|
LastModified: time.Now().Format(http.TimeFormat),
|
||||||
LastAccessed: time.Now().Format(http.TimeFormat),
|
|
||||||
}
|
}
|
||||||
return e.Save(jsonFilename)
|
return e.Save(jsonFilename)
|
||||||
}
|
}
|
||||||
@ -143,37 +127,3 @@ func (c *Cache) Insert(rawurl string, r io.Reader) error {
|
|||||||
func (c *Cache) Close() {
|
func (c *Cache) Close() {
|
||||||
c.waitGroup.Wait()
|
c.waitGroup.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate make file migrations with older versions
|
|
||||||
func (c *Cache) Migrate(pathname *string) (err error) {
|
|
||||||
files, err := os.ReadDir(*pathname)
|
|
||||||
for _, f := range files {
|
|
||||||
if strings.HasSuffix(f.Name(), ".json") {
|
|
||||||
basename := strings.Split(f.Name(), ".")[0]
|
|
||||||
jsonfile := fmt.Sprintf("%s/%s.json", *pathname, basename)
|
|
||||||
datafile := fmt.Sprintf("%s/%s.data", *pathname, basename)
|
|
||||||
newDiskReader(jsonfile, datafile)
|
|
||||||
|
|
||||||
e := Entry{}
|
|
||||||
err = e.Load(jsonfile)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
relurl := getRelURL(e.URL)
|
|
||||||
_, newjsonfile, newdatafile := c.getFilenames(relurl)
|
|
||||||
err = os.Rename(jsonfile, newjsonfile)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
err = os.Rename(datafile, newdatafile)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
12
src/cache/diskreader.go
vendored
12
src/cache/diskreader.go
vendored
@ -1,8 +1,6 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,22 +15,12 @@ type diskReader struct {
|
|||||||
func newDiskReader(jsonFilename, dataFilename string) (*diskReader, error) {
|
func newDiskReader(jsonFilename, dataFilename string) (*diskReader, error) {
|
||||||
e := &Entry{}
|
e := &Entry{}
|
||||||
if err := e.Load(jsonFilename); err != nil {
|
if err := e.Load(jsonFilename); err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
f, err := os.Open(dataFilename)
|
f, err := os.Open(dataFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if e.LastAccessed == "" {
|
|
||||||
stat, _ := f.Stat()
|
|
||||||
e.LastAccessed = stat.ModTime().Format(http.TimeFormat)
|
|
||||||
e.Save(jsonFilename)
|
|
||||||
}
|
|
||||||
if e.RelURL == "" {
|
|
||||||
e.RelURL = getRelURL(e.URL)
|
|
||||||
e.Save(jsonFilename)
|
|
||||||
}
|
|
||||||
return &diskReader{
|
return &diskReader{
|
||||||
entry: e,
|
entry: e,
|
||||||
file: f,
|
file: f,
|
||||||
|
6
src/cache/downloader.go
vendored
6
src/cache/downloader.go
vendored
@ -61,21 +61,17 @@ func newDownloader(rawurl, jsonFilename, dataFilename string) *downloader {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
relurl := getRelURL(rawurl)
|
|
||||||
d.entry = &Entry{
|
d.entry = &Entry{
|
||||||
URL: rawurl,
|
URL: rawurl,
|
||||||
RelURL: relurl,
|
|
||||||
ContentLength: strconv.FormatInt(resp.ContentLength, 10),
|
ContentLength: strconv.FormatInt(resp.ContentLength, 10),
|
||||||
ContentType: resp.Header.Get("Content-Type"),
|
ContentType: resp.Header.Get("Content-Type"),
|
||||||
LastModified: resp.Header.Get("Last-Modified"),
|
LastModified: resp.Header.Get("Last-Modified"),
|
||||||
LastAccessed: resp.Header.Get("Last-Modified"),
|
|
||||||
}
|
}
|
||||||
if d.entry.ContentType == "" {
|
if d.entry.ContentType == "" {
|
||||||
d.entry.ContentType = "application/octet-stream"
|
d.entry.ContentType = "application/octet-stream"
|
||||||
}
|
}
|
||||||
if d.entry.LastModified == "" || d.entry.LastAccessed == "" {
|
if d.entry.LastModified == "" {
|
||||||
d.entry.LastModified = time.Now().Format(http.TimeFormat)
|
d.entry.LastModified = time.Now().Format(http.TimeFormat)
|
||||||
d.entry.LastAccessed = time.Now().Format(http.TimeFormat)
|
|
||||||
}
|
}
|
||||||
if err = d.entry.Save(jsonFilename); err != nil {
|
if err = d.entry.Save(jsonFilename); err != nil {
|
||||||
d.err = err
|
d.err = err
|
||||||
|
2
src/cache/entry.go
vendored
2
src/cache/entry.go
vendored
@ -8,12 +8,10 @@ import (
|
|||||||
// Entry represents an individual item in the cache.
|
// Entry represents an individual item in the cache.
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
RelURL string `json:"rel_url"`
|
|
||||||
Complete bool `json:"complete"`
|
Complete bool `json:"complete"`
|
||||||
ContentLength string `json:"content_length"`
|
ContentLength string `json:"content_length"`
|
||||||
ContentType string `json:"content_type"`
|
ContentType string `json:"content_type"`
|
||||||
LastModified string `json:"last_modified"`
|
LastModified string `json:"last_modified"`
|
||||||
LastAccessed string `json:"last_accessed"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load reads the entry from disk.
|
// Load reads the entry from disk.
|
||||||
|
@ -64,10 +64,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.RequestURI == "/health" {
|
|
||||||
http.Error(w, "OK", http.StatusOK)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r, err := s.cache.GetReader(rewrite(req.RequestURI), maxAge(req))
|
r, err := s.cache.GetReader(rewrite(req.RequestURI), maxAge(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
@ -93,17 +89,11 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewServer creates a new server.
|
// NewServer creates a new server.
|
||||||
func NewServer(addr, directory string, migrate bool) (*Server, error) {
|
func NewServer(addr, directory string) (*Server, error) {
|
||||||
c, err := cache.NewCache(directory)
|
c, err := cache.NewCache(directory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upgrade current database
|
|
||||||
if migrate {
|
|
||||||
c.Migrate(&directory)
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Server{
|
s := &Server{
|
||||||
server: server.New(addr),
|
server: server.New(addr),
|
||||||
cache: c,
|
cache: c,
|
||||||
|
10
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
10
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
@ -1,6 +1,6 @@
|
|||||||
# go test -c output
|
# Setup a Global .gitignore for OS and editor generated files:
|
||||||
*.test
|
# https://help.github.com/articles/ignoring-files
|
||||||
*.test.exe
|
# git config --global core.excludesfile ~/.gitignore_global
|
||||||
|
|
||||||
# Output of go build ./cmd/fsnotify
|
.vagrant
|
||||||
/fsnotify
|
*.sublime-project
|
||||||
|
62
vendor/github.com/fsnotify/fsnotify/AUTHORS
generated
vendored
Normal file
62
vendor/github.com/fsnotify/fsnotify/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# Names should be added to this file as
|
||||||
|
# Name or Organization <email address>
|
||||||
|
# The email address is not required for organizations.
|
||||||
|
|
||||||
|
# You can update this list using the following command:
|
||||||
|
#
|
||||||
|
# $ (head -n10 AUTHORS && git shortlog -se | sed -E 's/^\s+[0-9]+\t//') | tee AUTHORS
|
||||||
|
|
||||||
|
# Please keep the list sorted.
|
||||||
|
|
||||||
|
Aaron L <aaron@bettercoder.net>
|
||||||
|
Adrien Bustany <adrien@bustany.org>
|
||||||
|
Alexey Kazakov <alkazako@redhat.com>
|
||||||
|
Amit Krishnan <amit.krishnan@oracle.com>
|
||||||
|
Anmol Sethi <me@anmol.io>
|
||||||
|
Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
|
||||||
|
Brian Goff <cpuguy83@gmail.com>
|
||||||
|
Bruno Bigras <bigras.bruno@gmail.com>
|
||||||
|
Caleb Spare <cespare@gmail.com>
|
||||||
|
Case Nelson <case@teammating.com>
|
||||||
|
Chris Howey <howeyc@gmail.com>
|
||||||
|
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||||
|
Daniel Wagner-Hall <dawagner@gmail.com>
|
||||||
|
Dave Cheney <dave@cheney.net>
|
||||||
|
Eric Lin <linxiulei@gmail.com>
|
||||||
|
Evan Phoenix <evan@fallingsnow.net>
|
||||||
|
Francisco Souza <f@souza.cc>
|
||||||
|
Gautam Dey <gautam.dey77@gmail.com>
|
||||||
|
Hari haran <hariharan.uno@gmail.com>
|
||||||
|
Ichinose Shogo <shogo82148@gmail.com>
|
||||||
|
Johannes Ebke <johannes@ebke.org>
|
||||||
|
John C Barstow <jbowtie@amathaine.com>
|
||||||
|
Kelvin Fo <vmirage@gmail.com>
|
||||||
|
Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
|
||||||
|
Matt Layher <mdlayher@gmail.com>
|
||||||
|
Matthias Stone <matthias@bellstone.ca>
|
||||||
|
Nathan Youngman <git@nathany.com>
|
||||||
|
Nickolai Zeldovich <nickolai@csail.mit.edu>
|
||||||
|
Oliver Bristow <evilumbrella+github@gmail.com>
|
||||||
|
Patrick <patrick@dropbox.com>
|
||||||
|
Paul Hammond <paul@paulhammond.org>
|
||||||
|
Pawel Knap <pawelknap88@gmail.com>
|
||||||
|
Pieter Droogendijk <pieter@binky.org.uk>
|
||||||
|
Pratik Shinde <pratikshinde320@gmail.com>
|
||||||
|
Pursuit92 <JoshChase@techpursuit.net>
|
||||||
|
Riku Voipio <riku.voipio@linaro.org>
|
||||||
|
Rob Figueiredo <robfig@gmail.com>
|
||||||
|
Rodrigo Chiossi <rodrigochiossi@gmail.com>
|
||||||
|
Slawek Ligus <root@ooz.ie>
|
||||||
|
Soge Zhang <zhssoge@gmail.com>
|
||||||
|
Tiffany Jernigan <tiffany.jernigan@intel.com>
|
||||||
|
Tilak Sharma <tilaks@google.com>
|
||||||
|
Tobias Klauser <tobias.klauser@gmail.com>
|
||||||
|
Tom Payne <twpayne@gmail.com>
|
||||||
|
Travis Cline <travis.cline@gmail.com>
|
||||||
|
Tudor Golubenco <tudor.g@gmail.com>
|
||||||
|
Vahe Khachikyan <vahe@live.ca>
|
||||||
|
Yukang <moorekang@gmail.com>
|
||||||
|
bronze1man <bronze1man@gmail.com>
|
||||||
|
debrando <denis.brandolini@gmail.com>
|
||||||
|
henrikedwards <henrik.edwards@gmail.com>
|
||||||
|
铁哥 <guotie.9@gmail.com>
|
133
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
133
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
@ -7,116 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
Nothing yet.
|
|
||||||
|
|
||||||
## [1.6.0] - 2022-10-13
|
|
||||||
|
|
||||||
This version of fsnotify needs Go 1.16 (this was already the case since 1.5.1,
|
|
||||||
but not documented). It also increases the minimum Linux version to 2.6.32.
|
|
||||||
|
|
||||||
### Additions
|
|
||||||
|
|
||||||
- all: add `Event.Has()` and `Op.Has()` ([#477])
|
|
||||||
|
|
||||||
This makes checking events a lot easier; for example:
|
|
||||||
|
|
||||||
if event.Op&Write == Write && !(event.Op&Remove == Remove) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Becomes:
|
|
||||||
|
|
||||||
if event.Has(Write) && !event.Has(Remove) {
|
|
||||||
}
|
|
||||||
|
|
||||||
- all: add cmd/fsnotify ([#463])
|
|
||||||
|
|
||||||
A command-line utility for testing and some examples.
|
|
||||||
|
|
||||||
### Changes and fixes
|
|
||||||
|
|
||||||
- inotify: don't ignore events for files that don't exist ([#260], [#470])
|
|
||||||
|
|
||||||
Previously the inotify watcher would call `os.Lstat()` to check if a file
|
|
||||||
still exists before emitting events.
|
|
||||||
|
|
||||||
This was inconsistent with other platforms and resulted in inconsistent event
|
|
||||||
reporting (e.g. when a file is quickly removed and re-created), and generally
|
|
||||||
a source of confusion. It was added in 2013 to fix a memory leak that no
|
|
||||||
longer exists.
|
|
||||||
|
|
||||||
- all: return `ErrNonExistentWatch` when `Remove()` is called on a path that's
|
|
||||||
not watched ([#460])
|
|
||||||
|
|
||||||
- inotify: replace epoll() with non-blocking inotify ([#434])
|
|
||||||
|
|
||||||
Non-blocking inotify was not generally available at the time this library was
|
|
||||||
written in 2014, but now it is. As a result, the minimum Linux version is
|
|
||||||
bumped from 2.6.27 to 2.6.32. This hugely simplifies the code and is faster.
|
|
||||||
|
|
||||||
- kqueue: don't check for events every 100ms ([#480])
|
|
||||||
|
|
||||||
The watcher would wake up every 100ms, even when there was nothing to do. Now
|
|
||||||
it waits until there is something to do.
|
|
||||||
|
|
||||||
- macos: retry opening files on EINTR ([#475])
|
|
||||||
|
|
||||||
- kqueue: skip unreadable files ([#479])
|
|
||||||
|
|
||||||
kqueue requires a file descriptor for every file in a directory; this would
|
|
||||||
fail if a file was unreadable by the current user. Now these files are simply
|
|
||||||
skipped.
|
|
||||||
|
|
||||||
- windows: fix renaming a watched directory if the parent is also watched ([#370])
|
|
||||||
|
|
||||||
- windows: increase buffer size from 4K to 64K ([#485])
|
|
||||||
|
|
||||||
- windows: close file handle on Remove() ([#288])
|
|
||||||
|
|
||||||
- kqueue: put pathname in the error if watching a file fails ([#471])
|
|
||||||
|
|
||||||
- inotify, windows: calling Close() more than once could race ([#465])
|
|
||||||
|
|
||||||
- kqueue: improve Close() performance ([#233])
|
|
||||||
|
|
||||||
- all: various documentation additions and clarifications.
|
|
||||||
|
|
||||||
[#233]: https://github.com/fsnotify/fsnotify/pull/233
|
|
||||||
[#260]: https://github.com/fsnotify/fsnotify/pull/260
|
|
||||||
[#288]: https://github.com/fsnotify/fsnotify/pull/288
|
|
||||||
[#370]: https://github.com/fsnotify/fsnotify/pull/370
|
|
||||||
[#434]: https://github.com/fsnotify/fsnotify/pull/434
|
|
||||||
[#460]: https://github.com/fsnotify/fsnotify/pull/460
|
|
||||||
[#463]: https://github.com/fsnotify/fsnotify/pull/463
|
|
||||||
[#465]: https://github.com/fsnotify/fsnotify/pull/465
|
|
||||||
[#470]: https://github.com/fsnotify/fsnotify/pull/470
|
|
||||||
[#471]: https://github.com/fsnotify/fsnotify/pull/471
|
|
||||||
[#475]: https://github.com/fsnotify/fsnotify/pull/475
|
|
||||||
[#477]: https://github.com/fsnotify/fsnotify/pull/477
|
|
||||||
[#479]: https://github.com/fsnotify/fsnotify/pull/479
|
|
||||||
[#480]: https://github.com/fsnotify/fsnotify/pull/480
|
|
||||||
[#485]: https://github.com/fsnotify/fsnotify/pull/485
|
|
||||||
|
|
||||||
## [1.5.4] - 2022-04-25
|
|
||||||
|
|
||||||
* Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447)
|
|
||||||
* go.mod: use latest x/sys [#444](https://github.com/fsnotify/fsnotify/pull/444)
|
|
||||||
* Fix compilation for OpenBSD [#443](https://github.com/fsnotify/fsnotify/pull/443)
|
|
||||||
|
|
||||||
## [1.5.3] - 2022-04-22
|
|
||||||
|
|
||||||
* This version is retracted. An incorrect branch is published accidentally [#445](https://github.com/fsnotify/fsnotify/issues/445)
|
|
||||||
|
|
||||||
## [1.5.2] - 2022-04-21
|
|
||||||
|
|
||||||
* Add a feature to return the directories and files that are being monitored [#374](https://github.com/fsnotify/fsnotify/pull/374)
|
|
||||||
* Fix potential crash on windows if `raw.FileNameLength` exceeds `syscall.MAX_PATH` [#361](https://github.com/fsnotify/fsnotify/pull/361)
|
|
||||||
* Allow build on unsupported GOOS [#424](https://github.com/fsnotify/fsnotify/pull/424)
|
|
||||||
* Don't set `poller.fd` twice in `newFdPoller` [#406](https://github.com/fsnotify/fsnotify/pull/406)
|
|
||||||
* fix go vet warnings: call to `(*T).Fatalf` from a non-test goroutine [#416](https://github.com/fsnotify/fsnotify/pull/416)
|
|
||||||
|
|
||||||
## [1.5.1] - 2021-08-24
|
## [1.5.1] - 2021-08-24
|
||||||
|
|
||||||
* Revert Add AddRaw to not follow symlinks [#394](https://github.com/fsnotify/fsnotify/pull/394)
|
* Revert Add AddRaw to not follow symlinks
|
||||||
|
|
||||||
## [1.5.0] - 2021-08-20
|
## [1.5.0] - 2021-08-20
|
||||||
|
|
||||||
@ -129,30 +22,6 @@ but not documented). It also increases the minimum Linux version to 2.6.32.
|
|||||||
[#385](https://github.com/fsnotify/fsnotify/pull/385)
|
[#385](https://github.com/fsnotify/fsnotify/pull/385)
|
||||||
* Go 1.14+: Fix unsafe pointer conversion [#325](https://github.com/fsnotify/fsnotify/pull/325)
|
* Go 1.14+: Fix unsafe pointer conversion [#325](https://github.com/fsnotify/fsnotify/pull/325)
|
||||||
|
|
||||||
## [1.4.9] - 2020-03-11
|
|
||||||
|
|
||||||
* Move example usage to the readme #329. This may resolve #328.
|
|
||||||
|
|
||||||
## [1.4.8] - 2020-03-10
|
|
||||||
|
|
||||||
* CI: test more go versions (@nathany 1d13583d846ea9d66dcabbfefbfb9d8e6fb05216)
|
|
||||||
* Tests: Queued inotify events could have been read by the test before max_queued_events was hit (@matthias-stone #265)
|
|
||||||
* Tests: t.Fatalf -> t.Errorf in go routines (@gdey #266)
|
|
||||||
* CI: Less verbosity (@nathany #267)
|
|
||||||
* Tests: Darwin: Exchangedata is deprecated on 10.13 (@nathany #267)
|
|
||||||
* Tests: Check if channels are closed in the example (@alexeykazakov #244)
|
|
||||||
* CI: Only run golint on latest version of go and fix issues (@cpuguy83 #284)
|
|
||||||
* CI: Add windows to travis matrix (@cpuguy83 #284)
|
|
||||||
* Docs: Remover appveyor badge (@nathany 11844c0959f6fff69ba325d097fce35bd85a8e93)
|
|
||||||
* Linux: create epoll and pipe fds with close-on-exec (@JohannesEbke #219)
|
|
||||||
* Linux: open files with close-on-exec (@linxiulei #273)
|
|
||||||
* Docs: Plan to support fanotify (@nathany ab058b44498e8b7566a799372a39d150d9ea0119 )
|
|
||||||
* Project: Add go.mod (@nathany #309)
|
|
||||||
* Project: Revise editor config (@nathany #309)
|
|
||||||
* Project: Update copyright for 2019 (@nathany #309)
|
|
||||||
* CI: Drop go1.8 from CI matrix (@nathany #309)
|
|
||||||
* Docs: Updating the FAQ section for supportability with NFS & FUSE filesystems (@Pratik32 4bf2d1fec78374803a39307bfb8d340688f4f28e )
|
|
||||||
|
|
||||||
## [1.4.7] - 2018-01-09
|
## [1.4.7] - 2018-01-09
|
||||||
|
|
||||||
* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
|
* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
|
||||||
|
89
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
89
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
@ -1,26 +1,77 @@
|
|||||||
Thank you for your interest in contributing to fsnotify! We try to review and
|
# Contributing
|
||||||
merge PRs in a reasonable timeframe, but please be aware that:
|
|
||||||
|
|
||||||
- To avoid "wasted" work, please discus changes on the issue tracker first. You
|
## Issues
|
||||||
can just send PRs, but they may end up being rejected for one reason or the
|
|
||||||
other.
|
|
||||||
|
|
||||||
- fsnotify is a cross-platform library, and changes must work reasonably well on
|
* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues).
|
||||||
all supported platforms.
|
* Please indicate the platform you are using fsnotify on.
|
||||||
|
* A code example to reproduce the problem is appreciated.
|
||||||
|
|
||||||
- Changes will need to be compatible; old code should still compile, and the
|
## Pull Requests
|
||||||
runtime behaviour can't change in ways that are likely to lead to problems for
|
|
||||||
users.
|
|
||||||
|
|
||||||
Testing
|
### Contributor License Agreement
|
||||||
-------
|
|
||||||
Just `go test ./...` runs all the tests; the CI runs this on all supported
|
|
||||||
platforms. Testing different platforms locally can be done with something like
|
|
||||||
[goon] or [Vagrant], but this isn't super-easy to set up at the moment.
|
|
||||||
|
|
||||||
Use the `-short` flag to make the "stress test" run faster.
|
fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
|
||||||
|
|
||||||
|
Please indicate that you have signed the CLA in your pull request.
|
||||||
|
|
||||||
[goon]: https://github.com/arp242/goon
|
### How fsnotify is Developed
|
||||||
[Vagrant]: https://www.vagrantup.com/
|
|
||||||
[integration_test.go]: /integration_test.go
|
* Development is done on feature branches.
|
||||||
|
* Tests are run on BSD, Linux, macOS and Windows.
|
||||||
|
* Pull requests are reviewed and [applied to master][am] using [hub][].
|
||||||
|
* Maintainers may modify or squash commits rather than asking contributors to.
|
||||||
|
* To issue a new release, the maintainers will:
|
||||||
|
* Update the CHANGELOG
|
||||||
|
* Tag a version, which will become available through gopkg.in.
|
||||||
|
|
||||||
|
### How to Fork
|
||||||
|
|
||||||
|
For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
|
||||||
|
|
||||||
|
1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`)
|
||||||
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||||
|
3. Ensure everything works and the tests pass (see below)
|
||||||
|
4. Commit your changes (`git commit -am 'Add some feature'`)
|
||||||
|
|
||||||
|
Contribute upstream:
|
||||||
|
|
||||||
|
1. Fork fsnotify on GitHub
|
||||||
|
2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
|
||||||
|
3. Push to the branch (`git push fork my-new-feature`)
|
||||||
|
4. Create a new Pull Request on GitHub
|
||||||
|
|
||||||
|
This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/).
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows.
|
||||||
|
|
||||||
|
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
|
||||||
|
|
||||||
|
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
|
||||||
|
|
||||||
|
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
|
||||||
|
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
|
||||||
|
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
|
||||||
|
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
|
||||||
|
* When you're done, you will want to halt or destroy the Vagrant boxes.
|
||||||
|
|
||||||
|
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
|
||||||
|
|
||||||
|
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
|
||||||
|
|
||||||
|
### Maintainers
|
||||||
|
|
||||||
|
Help maintaining fsnotify is welcome. To be a maintainer:
|
||||||
|
|
||||||
|
* Submit a pull request and sign the CLA as above.
|
||||||
|
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
|
||||||
|
|
||||||
|
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
|
||||||
|
|
||||||
|
All code changes should be internal pull requests.
|
||||||
|
|
||||||
|
Releases are tagged using [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
[hub]: https://github.com/github/hub
|
||||||
|
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
|
||||||
|
47
vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
47
vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
@ -1,25 +1,28 @@
|
|||||||
Copyright © 2012 The Go Authors. All rights reserved.
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
Copyright © fsnotify Authors. All rights reserved.
|
Copyright (c) 2012-2019 fsnotify Authors. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
Redistribution and use in source and binary forms, with or without
|
||||||
are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
* Redistributions of source code must retain the above copyright
|
||||||
list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
* Redistributions in binary form must reproduce the above
|
||||||
list of conditions and the following disclaimer in the documentation and/or
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
other materials provided with the distribution.
|
in the documentation and/or other materials provided with the
|
||||||
* Neither the name of Google Inc. nor the names of its contributors may be used
|
distribution.
|
||||||
to endorse or promote products derived from this software without specific
|
* Neither the name of Google Inc. nor the names of its
|
||||||
prior written permission.
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
237
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
237
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
@ -1,161 +1,130 @@
|
|||||||
fsnotify is a Go library to provide cross-platform filesystem notifications on
|
# File system notifications for Go
|
||||||
Windows, Linux, macOS, and BSD systems.
|
|
||||||
|
|
||||||
Go 1.16 or newer is required; the full documentation is at
|
[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
|
||||||
https://pkg.go.dev/github.com/fsnotify/fsnotify
|
|
||||||
|
|
||||||
**It's best to read the documentation at pkg.go.dev, as it's pinned to the last
|
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
|
||||||
released version, whereas this README is for the last development version which
|
|
||||||
may include additions/changes.**
|
|
||||||
|
|
||||||
---
|
```console
|
||||||
|
go get -u golang.org/x/sys/...
|
||||||
|
```
|
||||||
|
|
||||||
Platform support:
|
Cross platform: Windows, Linux, BSD and macOS.
|
||||||
|
|
||||||
| Adapter | OS | Status |
|
| Adapter | OS | Status |
|
||||||
| --------------------- | ---------------| -------------------------------------------------------------|
|
| --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| inotify | Linux 2.6.32+ | Supported |
|
| inotify | Linux 2.6.27 or later, Android\* | Supported |
|
||||||
| kqueue | BSD, macOS | Supported |
|
| kqueue | BSD, macOS, iOS\* | Supported |
|
||||||
| ReadDirectoryChangesW | Windows | Supported |
|
| ReadDirectoryChangesW | Windows | Supported |
|
||||||
| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
|
| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
|
||||||
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) |
|
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/issues/12) |
|
||||||
| fanotify | Linux 5.9+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) |
|
| fanotify | Linux 2.6.37+ | [Planned](https://github.com/fsnotify/fsnotify/issues/114) |
|
||||||
| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) |
|
| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) |
|
||||||
| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) |
|
| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) |
|
||||||
|
|
||||||
Linux and macOS should include Android and iOS, but these are currently untested.
|
\* Android and iOS are untested.
|
||||||
|
|
||||||
Usage
|
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
|
||||||
-----
|
|
||||||
A basic example:
|
## API stability
|
||||||
|
|
||||||
|
fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
|
||||||
|
|
||||||
|
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
|
||||||
|
|
||||||
|
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Create new watcher.
|
watcher, err := fsnotify.NewWatcher()
|
||||||
watcher, err := fsnotify.NewWatcher()
|
if err != nil {
|
||||||
if err != nil {
|
log.Fatal(err)
|
||||||
log.Fatal(err)
|
}
|
||||||
}
|
defer watcher.Close()
|
||||||
defer watcher.Close()
|
|
||||||
|
|
||||||
// Start listening for events.
|
done := make(chan bool)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case event, ok := <-watcher.Events:
|
case event, ok := <-watcher.Events:
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Println("event:", event)
|
log.Println("event:", event)
|
||||||
if event.Has(fsnotify.Write) {
|
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||||
log.Println("modified file:", event.Name)
|
log.Println("modified file:", event.Name)
|
||||||
}
|
}
|
||||||
case err, ok := <-watcher.Errors:
|
case err, ok := <-watcher.Errors:
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Println("error:", err)
|
log.Println("error:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Add a path.
|
err = watcher.Add("/tmp/foo")
|
||||||
err = watcher.Add("/tmp")
|
if err != nil {
|
||||||
if err != nil {
|
log.Fatal(err)
|
||||||
log.Fatal(err)
|
}
|
||||||
}
|
<-done
|
||||||
|
|
||||||
// Block main goroutine forever.
|
|
||||||
<-make(chan struct{})
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Some more examples can be found in [cmd/fsnotify](cmd/fsnotify), which can be
|
## Contributing
|
||||||
run with:
|
|
||||||
|
|
||||||
% go run ./cmd/fsnotify
|
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
|
||||||
|
|
||||||
FAQ
|
## Example
|
||||||
---
|
|
||||||
### Will a file still be watched when it's moved to another directory?
|
|
||||||
No, not unless you are watching the location it was moved to.
|
|
||||||
|
|
||||||
### Are subdirectories watched too?
|
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
|
||||||
No, you must add watches for any directory you want to watch (a recursive
|
|
||||||
watcher is on the roadmap: [#18]).
|
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
**When a file is moved to another directory is it still being watched?**
|
||||||
|
|
||||||
|
No (it shouldn't be, unless you are watching where it was moved to).
|
||||||
|
|
||||||
|
**When I watch a directory, are all subdirectories watched as well?**
|
||||||
|
|
||||||
|
No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]).
|
||||||
|
|
||||||
|
**Do I have to watch the Error and Event channels in a separate goroutine?**
|
||||||
|
|
||||||
|
As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7])
|
||||||
|
|
||||||
|
**Why am I receiving multiple events for the same file on OS X?**
|
||||||
|
|
||||||
|
Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]).
|
||||||
|
|
||||||
|
**How many files can be watched at once?**
|
||||||
|
|
||||||
|
There are OS-specific limits as to how many watches can be created:
|
||||||
|
* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error.
|
||||||
|
* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
|
||||||
|
|
||||||
|
**Why don't notifications work with NFS filesystems or filesystem in userspace (FUSE)?**
|
||||||
|
|
||||||
|
fsnotify requires support from underlying OS to work. The current NFS protocol does not provide network level support for file notifications.
|
||||||
|
|
||||||
|
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||||
[#18]: https://github.com/fsnotify/fsnotify/issues/18
|
[#18]: https://github.com/fsnotify/fsnotify/issues/18
|
||||||
|
|
||||||
### Do I have to watch the Error and Event channels in a goroutine?
|
|
||||||
As of now, yes (you can read both channels in the same goroutine using `select`,
|
|
||||||
you don't need a separate goroutine for both channels; see the example).
|
|
||||||
|
|
||||||
### Why don't notifications work with NFS, SMB, FUSE, /proc, or /sys?
|
|
||||||
fsnotify requires support from underlying OS to work. The current NFS and SMB
|
|
||||||
protocols does not provide network level support for file notifications, and
|
|
||||||
neither do the /proc and /sys virtual filesystems.
|
|
||||||
|
|
||||||
This could be fixed with a polling watcher ([#9]), but it's not yet implemented.
|
|
||||||
|
|
||||||
[#9]: https://github.com/fsnotify/fsnotify/issues/9
|
|
||||||
|
|
||||||
Platform-specific notes
|
|
||||||
-----------------------
|
|
||||||
### Linux
|
|
||||||
When a file is removed a REMOVE event won't be emitted until all file
|
|
||||||
descriptors are closed; it will emit a CHMOD instead:
|
|
||||||
|
|
||||||
fp := os.Open("file")
|
|
||||||
os.Remove("file") // CHMOD
|
|
||||||
fp.Close() // REMOVE
|
|
||||||
|
|
||||||
This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
|
|
||||||
The `fs.inotify.max_user_watches` sysctl variable specifies the upper limit for
|
|
||||||
the number of watches per user, and `fs.inotify.max_user_instances` specifies
|
|
||||||
the maximum number of inotify instances per user. Every Watcher you create is an
|
|
||||||
"instance", and every path you add is a "watch".
|
|
||||||
|
|
||||||
These are also exposed in `/proc` as `/proc/sys/fs/inotify/max_user_watches` and
|
|
||||||
`/proc/sys/fs/inotify/max_user_instances`
|
|
||||||
|
|
||||||
To increase them you can use `sysctl` or write the value to proc file:
|
|
||||||
|
|
||||||
# The default values on Linux 5.18
|
|
||||||
sysctl fs.inotify.max_user_watches=124983
|
|
||||||
sysctl fs.inotify.max_user_instances=128
|
|
||||||
|
|
||||||
To make the changes persist on reboot edit `/etc/sysctl.conf` or
|
|
||||||
`/usr/lib/sysctl.d/50-default.conf` (details differ per Linux distro; check your
|
|
||||||
distro's documentation):
|
|
||||||
|
|
||||||
fs.inotify.max_user_watches=124983
|
|
||||||
fs.inotify.max_user_instances=128
|
|
||||||
|
|
||||||
Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
files" error.
|
|
||||||
|
|
||||||
### kqueue (macOS, all BSD systems)
|
|
||||||
kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
so if you're watching a directory with five files then that's six file
|
|
||||||
descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
these platforms.
|
|
||||||
|
|
||||||
The sysctl variables `kern.maxfiles` and `kern.maxfilesperproc` can be used to
|
|
||||||
control the maximum number of open files.
|
|
||||||
|
|
||||||
### macOS
|
|
||||||
Spotlight indexing on macOS can result in multiple events (see [#15]). A temporary
|
|
||||||
workaround is to add your folder(s) to the *Spotlight Privacy settings* until we
|
|
||||||
have a native FSEvents implementation (see [#11]).
|
|
||||||
|
|
||||||
[#11]: https://github.com/fsnotify/fsnotify/issues/11
|
[#11]: https://github.com/fsnotify/fsnotify/issues/11
|
||||||
[#15]: https://github.com/fsnotify/fsnotify/issues/15
|
[#7]: https://github.com/howeyc/fsnotify/issues/7
|
||||||
|
|
||||||
|
[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md
|
||||||
|
|
||||||
|
## Related Projects
|
||||||
|
|
||||||
|
* [notify](https://github.com/rjeczalik/notify)
|
||||||
|
* [fsevents](https://github.com/fsnotify/fsevents)
|
||||||
|
|
||||||
|
162
vendor/github.com/fsnotify/fsnotify/backend_fen.go
generated
vendored
162
vendor/github.com/fsnotify/fsnotify/backend_fen.go
generated
vendored
@ -1,162 +0,0 @@
|
|||||||
//go:build solaris
|
|
||||||
// +build solaris
|
|
||||||
|
|
||||||
package fsnotify
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Watcher watches a set of paths, delivering events on a channel.
|
|
||||||
//
|
|
||||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
|
||||||
// value).
|
|
||||||
//
|
|
||||||
// # Linux notes
|
|
||||||
//
|
|
||||||
// When a file is removed a Remove event won't be emitted until all file
|
|
||||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
|
||||||
//
|
|
||||||
// fp := os.Open("file")
|
|
||||||
// os.Remove("file") // Triggers Chmod
|
|
||||||
// fp.Close() // Triggers Remove
|
|
||||||
//
|
|
||||||
// This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
//
|
|
||||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
|
||||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
|
||||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
|
||||||
// create is an "instance", and every path you add is a "watch".
|
|
||||||
//
|
|
||||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
|
||||||
// /proc/sys/fs/inotify/max_user_instances
|
|
||||||
//
|
|
||||||
// To increase them you can use sysctl or write the value to the /proc file:
|
|
||||||
//
|
|
||||||
// # Default values on Linux 5.18
|
|
||||||
// sysctl fs.inotify.max_user_watches=124983
|
|
||||||
// sysctl fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
|
||||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
|
||||||
// your distro's documentation):
|
|
||||||
//
|
|
||||||
// fs.inotify.max_user_watches=124983
|
|
||||||
// fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
// files" error.
|
|
||||||
//
|
|
||||||
// # kqueue notes (macOS, BSD)
|
|
||||||
//
|
|
||||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
// so if you're watching a directory with five files then that's six file
|
|
||||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
// these platforms.
|
|
||||||
//
|
|
||||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
|
||||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
|
||||||
// systems.
|
|
||||||
//
|
|
||||||
// # macOS notes
|
|
||||||
//
|
|
||||||
// Spotlight indexing on macOS can result in multiple events (see [#15]). A
|
|
||||||
// temporary workaround is to add your folder(s) to the "Spotlight Privacy
|
|
||||||
// Settings" until we have a native FSEvents implementation (see [#11]).
|
|
||||||
//
|
|
||||||
// [#11]: https://github.com/fsnotify/fsnotify/issues/11
|
|
||||||
// [#15]: https://github.com/fsnotify/fsnotify/issues/15
|
|
||||||
type Watcher struct {
|
|
||||||
// Events sends the filesystem change events.
|
|
||||||
//
|
|
||||||
// fsnotify can send the following events; a "path" here can refer to a
|
|
||||||
// file, directory, symbolic link, or special file like a FIFO.
|
|
||||||
//
|
|
||||||
// fsnotify.Create A new path was created; this may be followed by one
|
|
||||||
// or more Write events if data also gets written to a
|
|
||||||
// file.
|
|
||||||
//
|
|
||||||
// fsnotify.Remove A path was removed.
|
|
||||||
//
|
|
||||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
|
||||||
// old path as Event.Name, and a Create event will be
|
|
||||||
// sent with the new name. Renames are only sent for
|
|
||||||
// paths that are currently watched; e.g. moving an
|
|
||||||
// unmonitored file into a monitored directory will
|
|
||||||
// show up as just a Create. Similarly, renaming a file
|
|
||||||
// to outside a monitored directory will show up as
|
|
||||||
// only a Rename.
|
|
||||||
//
|
|
||||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
|
||||||
// also trigger a Write. A single "write action"
|
|
||||||
// initiated by the user may show up as one or multiple
|
|
||||||
// writes, depending on when the system syncs things to
|
|
||||||
// disk. For example when compiling a large Go program
|
|
||||||
// you may get hundreds of Write events, so you
|
|
||||||
// probably want to wait until you've stopped receiving
|
|
||||||
// them (see the dedup example in cmd/fsnotify).
|
|
||||||
//
|
|
||||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
|
||||||
// when a file is removed (or more accurately, when a
|
|
||||||
// link to an inode is removed). On kqueue it's sent
|
|
||||||
// and on kqueue when a file is truncated. On Windows
|
|
||||||
// it's never sent.
|
|
||||||
Events chan Event
|
|
||||||
|
|
||||||
// Errors sends any errors.
|
|
||||||
Errors chan error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWatcher creates a new Watcher.
|
|
||||||
func NewWatcher() (*Watcher, error) {
|
|
||||||
return nil, errors.New("FEN based watcher not yet supported for fsnotify\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close removes all watches and closes the events channel.
|
|
||||||
func (w *Watcher) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add starts monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// A path can only be watched once; attempting to watch it more than once will
|
|
||||||
// return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// added. A watch will be automatically removed if the path is deleted.
|
|
||||||
//
|
|
||||||
// A path will remain watched if it gets renamed to somewhere else on the same
|
|
||||||
// filesystem, but the monitor will get removed if the path gets deleted and
|
|
||||||
// re-created, or if it's moved to a different filesystem.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many tools update files atomically. Instead of "just" writing
|
|
||||||
// to the file a temporary file will be written to first, and if successful the
|
|
||||||
// temporary file is moved to to destination removing the original, or some
|
|
||||||
// variant thereof. The watcher on the original file is now lost, as it no
|
|
||||||
// longer exists.
|
|
||||||
//
|
|
||||||
// Instead, watch the parent directory and use Event.Name to filter out files
|
|
||||||
// you're not interested in. There is an example of this in [cmd/fsnotify/file.go].
|
|
||||||
func (w *Watcher) Add(name string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove stops monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
func (w *Watcher) Remove(name string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
459
vendor/github.com/fsnotify/fsnotify/backend_inotify.go
generated
vendored
459
vendor/github.com/fsnotify/fsnotify/backend_inotify.go
generated
vendored
@ -1,459 +0,0 @@
|
|||||||
//go:build linux
|
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package fsnotify
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Watcher watches a set of paths, delivering events on a channel.
|
|
||||||
//
|
|
||||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
|
||||||
// value).
|
|
||||||
//
|
|
||||||
// # Linux notes
|
|
||||||
//
|
|
||||||
// When a file is removed a Remove event won't be emitted until all file
|
|
||||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
|
||||||
//
|
|
||||||
// fp := os.Open("file")
|
|
||||||
// os.Remove("file") // Triggers Chmod
|
|
||||||
// fp.Close() // Triggers Remove
|
|
||||||
//
|
|
||||||
// This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
//
|
|
||||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
|
||||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
|
||||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
|
||||||
// create is an "instance", and every path you add is a "watch".
|
|
||||||
//
|
|
||||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
|
||||||
// /proc/sys/fs/inotify/max_user_instances
|
|
||||||
//
|
|
||||||
// To increase them you can use sysctl or write the value to the /proc file:
|
|
||||||
//
|
|
||||||
// # Default values on Linux 5.18
|
|
||||||
// sysctl fs.inotify.max_user_watches=124983
|
|
||||||
// sysctl fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
|
||||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
|
||||||
// your distro's documentation):
|
|
||||||
//
|
|
||||||
// fs.inotify.max_user_watches=124983
|
|
||||||
// fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
// files" error.
|
|
||||||
//
|
|
||||||
// # kqueue notes (macOS, BSD)
|
|
||||||
//
|
|
||||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
// so if you're watching a directory with five files then that's six file
|
|
||||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
// these platforms.
|
|
||||||
//
|
|
||||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
|
||||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
|
||||||
// systems.
|
|
||||||
//
|
|
||||||
// # macOS notes
|
|
||||||
//
|
|
||||||
// Spotlight indexing on macOS can result in multiple events (see [#15]). A
|
|
||||||
// temporary workaround is to add your folder(s) to the "Spotlight Privacy
|
|
||||||
// Settings" until we have a native FSEvents implementation (see [#11]).
|
|
||||||
//
|
|
||||||
// [#11]: https://github.com/fsnotify/fsnotify/issues/11
|
|
||||||
// [#15]: https://github.com/fsnotify/fsnotify/issues/15
|
|
||||||
type Watcher struct {
|
|
||||||
// Events sends the filesystem change events.
|
|
||||||
//
|
|
||||||
// fsnotify can send the following events; a "path" here can refer to a
|
|
||||||
// file, directory, symbolic link, or special file like a FIFO.
|
|
||||||
//
|
|
||||||
// fsnotify.Create A new path was created; this may be followed by one
|
|
||||||
// or more Write events if data also gets written to a
|
|
||||||
// file.
|
|
||||||
//
|
|
||||||
// fsnotify.Remove A path was removed.
|
|
||||||
//
|
|
||||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
|
||||||
// old path as Event.Name, and a Create event will be
|
|
||||||
// sent with the new name. Renames are only sent for
|
|
||||||
// paths that are currently watched; e.g. moving an
|
|
||||||
// unmonitored file into a monitored directory will
|
|
||||||
// show up as just a Create. Similarly, renaming a file
|
|
||||||
// to outside a monitored directory will show up as
|
|
||||||
// only a Rename.
|
|
||||||
//
|
|
||||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
|
||||||
// also trigger a Write. A single "write action"
|
|
||||||
// initiated by the user may show up as one or multiple
|
|
||||||
// writes, depending on when the system syncs things to
|
|
||||||
// disk. For example when compiling a large Go program
|
|
||||||
// you may get hundreds of Write events, so you
|
|
||||||
// probably want to wait until you've stopped receiving
|
|
||||||
// them (see the dedup example in cmd/fsnotify).
|
|
||||||
//
|
|
||||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
|
||||||
// when a file is removed (or more accurately, when a
|
|
||||||
// link to an inode is removed). On kqueue it's sent
|
|
||||||
// and on kqueue when a file is truncated. On Windows
|
|
||||||
// it's never sent.
|
|
||||||
Events chan Event
|
|
||||||
|
|
||||||
// Errors sends any errors.
|
|
||||||
Errors chan error
|
|
||||||
|
|
||||||
// Store fd here as os.File.Read() will no longer return on close after
|
|
||||||
// calling Fd(). See: https://github.com/golang/go/issues/26439
|
|
||||||
fd int
|
|
||||||
mu sync.Mutex // Map access
|
|
||||||
inotifyFile *os.File
|
|
||||||
watches map[string]*watch // Map of inotify watches (key: path)
|
|
||||||
paths map[int]string // Map of watched paths (key: watch descriptor)
|
|
||||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
|
||||||
doneResp chan struct{} // Channel to respond to Close
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWatcher creates a new Watcher.
|
|
||||||
func NewWatcher() (*Watcher, error) {
|
|
||||||
// Create inotify fd
|
|
||||||
// Need to set the FD to nonblocking mode in order for SetDeadline methods to work
|
|
||||||
// Otherwise, blocking i/o operations won't terminate on close
|
|
||||||
fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK)
|
|
||||||
if fd == -1 {
|
|
||||||
return nil, errno
|
|
||||||
}
|
|
||||||
|
|
||||||
w := &Watcher{
|
|
||||||
fd: fd,
|
|
||||||
inotifyFile: os.NewFile(uintptr(fd), ""),
|
|
||||||
watches: make(map[string]*watch),
|
|
||||||
paths: make(map[int]string),
|
|
||||||
Events: make(chan Event),
|
|
||||||
Errors: make(chan error),
|
|
||||||
done: make(chan struct{}),
|
|
||||||
doneResp: make(chan struct{}),
|
|
||||||
}
|
|
||||||
|
|
||||||
go w.readEvents()
|
|
||||||
return w, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the event was sent, or false if watcher is closed.
|
|
||||||
func (w *Watcher) sendEvent(e Event) bool {
|
|
||||||
select {
|
|
||||||
case w.Events <- e:
|
|
||||||
return true
|
|
||||||
case <-w.done:
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the error was sent, or false if watcher is closed.
|
|
||||||
func (w *Watcher) sendError(err error) bool {
|
|
||||||
select {
|
|
||||||
case w.Errors <- err:
|
|
||||||
return true
|
|
||||||
case <-w.done:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) isClosed() bool {
|
|
||||||
select {
|
|
||||||
case <-w.done:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close removes all watches and closes the events channel.
|
|
||||||
func (w *Watcher) Close() error {
|
|
||||||
w.mu.Lock()
|
|
||||||
if w.isClosed() {
|
|
||||||
w.mu.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send 'close' signal to goroutine, and set the Watcher to closed.
|
|
||||||
close(w.done)
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
// Causes any blocking reads to return with an error, provided the file
|
|
||||||
// still supports deadline operations.
|
|
||||||
err := w.inotifyFile.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for goroutine to close
|
|
||||||
<-w.doneResp
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add starts monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// A path can only be watched once; attempting to watch it more than once will
|
|
||||||
// return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// added. A watch will be automatically removed if the path is deleted.
|
|
||||||
//
|
|
||||||
// A path will remain watched if it gets renamed to somewhere else on the same
|
|
||||||
// filesystem, but the monitor will get removed if the path gets deleted and
|
|
||||||
// re-created, or if it's moved to a different filesystem.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many tools update files atomically. Instead of "just" writing
|
|
||||||
// to the file a temporary file will be written to first, and if successful the
|
|
||||||
// temporary file is moved to to destination removing the original, or some
|
|
||||||
// variant thereof. The watcher on the original file is now lost, as it no
|
|
||||||
// longer exists.
|
|
||||||
//
|
|
||||||
// Instead, watch the parent directory and use Event.Name to filter out files
|
|
||||||
// you're not interested in. There is an example of this in [cmd/fsnotify/file.go].
|
|
||||||
func (w *Watcher) Add(name string) error {
|
|
||||||
name = filepath.Clean(name)
|
|
||||||
if w.isClosed() {
|
|
||||||
return errors.New("inotify instance already closed")
|
|
||||||
}
|
|
||||||
|
|
||||||
var flags uint32 = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
|
|
||||||
unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
|
|
||||||
unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
|
|
||||||
|
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
watchEntry := w.watches[name]
|
|
||||||
if watchEntry != nil {
|
|
||||||
flags |= watchEntry.flags | unix.IN_MASK_ADD
|
|
||||||
}
|
|
||||||
wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
|
|
||||||
if wd == -1 {
|
|
||||||
return errno
|
|
||||||
}
|
|
||||||
|
|
||||||
if watchEntry == nil {
|
|
||||||
w.watches[name] = &watch{wd: uint32(wd), flags: flags}
|
|
||||||
w.paths[wd] = name
|
|
||||||
} else {
|
|
||||||
watchEntry.wd = uint32(wd)
|
|
||||||
watchEntry.flags = flags
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove stops monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
func (w *Watcher) Remove(name string) error {
|
|
||||||
name = filepath.Clean(name)
|
|
||||||
|
|
||||||
// Fetch the watch.
|
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
watch, ok := w.watches[name]
|
|
||||||
|
|
||||||
// Remove it from inotify.
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("%w: %s", ErrNonExistentWatch, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We successfully removed the watch if InotifyRmWatch doesn't return an
|
|
||||||
// error, we need to clean up our internal state to ensure it matches
|
|
||||||
// inotify's kernel state.
|
|
||||||
delete(w.paths, int(watch.wd))
|
|
||||||
delete(w.watches, name)
|
|
||||||
|
|
||||||
// inotify_rm_watch will return EINVAL if the file has been deleted;
|
|
||||||
// the inotify will already have been removed.
|
|
||||||
// watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
|
|
||||||
// by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE
|
|
||||||
// so that EINVAL means that the wd is being rm_watch()ed or its file removed
|
|
||||||
// by another thread and we have not received IN_IGNORE event.
|
|
||||||
success, errno := unix.InotifyRmWatch(w.fd, watch.wd)
|
|
||||||
if success == -1 {
|
|
||||||
// TODO: Perhaps it's not helpful to return an error here in every case;
|
|
||||||
// The only two possible errors are:
|
|
||||||
//
|
|
||||||
// - EBADF, which happens when w.fd is not a valid file descriptor
|
|
||||||
// of any kind.
|
|
||||||
// - EINVAL, which is when fd is not an inotify descriptor or wd
|
|
||||||
// is not a valid watch descriptor. Watch descriptors are
|
|
||||||
// invalidated when they are removed explicitly or implicitly;
|
|
||||||
// explicitly by inotify_rm_watch, implicitly when the file they
|
|
||||||
// are watching is deleted.
|
|
||||||
return errno
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchList returns all paths added with [Add] (and are not yet removed).
|
|
||||||
func (w *Watcher) WatchList() []string {
|
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
|
|
||||||
entries := make([]string, 0, len(w.watches))
|
|
||||||
for pathname := range w.watches {
|
|
||||||
entries = append(entries, pathname)
|
|
||||||
}
|
|
||||||
|
|
||||||
return entries
|
|
||||||
}
|
|
||||||
|
|
||||||
type watch struct {
|
|
||||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
|
||||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// readEvents reads from the inotify file descriptor, converts the
|
|
||||||
// received events into Event objects and sends them via the Events channel
|
|
||||||
func (w *Watcher) readEvents() {
|
|
||||||
defer func() {
|
|
||||||
close(w.doneResp)
|
|
||||||
close(w.Errors)
|
|
||||||
close(w.Events)
|
|
||||||
}()
|
|
||||||
|
|
||||||
var (
|
|
||||||
buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
|
|
||||||
errno error // Syscall errno
|
|
||||||
)
|
|
||||||
for {
|
|
||||||
// See if we have been closed.
|
|
||||||
if w.isClosed() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := w.inotifyFile.Read(buf[:])
|
|
||||||
switch {
|
|
||||||
case errors.Unwrap(err) == os.ErrClosed:
|
|
||||||
return
|
|
||||||
case err != nil:
|
|
||||||
if !w.sendError(err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if n < unix.SizeofInotifyEvent {
|
|
||||||
var err error
|
|
||||||
if n == 0 {
|
|
||||||
// If EOF is received. This should really never happen.
|
|
||||||
err = io.EOF
|
|
||||||
} else if n < 0 {
|
|
||||||
// If an error occurred while reading.
|
|
||||||
err = errno
|
|
||||||
} else {
|
|
||||||
// Read was too short.
|
|
||||||
err = errors.New("notify: short read in readEvents()")
|
|
||||||
}
|
|
||||||
if !w.sendError(err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var offset uint32
|
|
||||||
// We don't know how many events we just read into the buffer
|
|
||||||
// While the offset points to at least one whole event...
|
|
||||||
for offset <= uint32(n-unix.SizeofInotifyEvent) {
|
|
||||||
var (
|
|
||||||
// Point "raw" to the event in the buffer
|
|
||||||
raw = (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
|
|
||||||
mask = uint32(raw.Mask)
|
|
||||||
nameLen = uint32(raw.Len)
|
|
||||||
)
|
|
||||||
|
|
||||||
if mask&unix.IN_Q_OVERFLOW != 0 {
|
|
||||||
if !w.sendError(ErrEventOverflow) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the event happened to the watched directory or the watched file, the kernel
|
|
||||||
// doesn't append the filename to the event, but we would like to always fill the
|
|
||||||
// the "Name" field with a valid filename. We retrieve the path of the watch from
|
|
||||||
// the "paths" map.
|
|
||||||
w.mu.Lock()
|
|
||||||
name, ok := w.paths[int(raw.Wd)]
|
|
||||||
// IN_DELETE_SELF occurs when the file/directory being watched is removed.
|
|
||||||
// This is a sign to clean up the maps, otherwise we are no longer in sync
|
|
||||||
// with the inotify kernel state which has already deleted the watch
|
|
||||||
// automatically.
|
|
||||||
if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
|
|
||||||
delete(w.paths, int(raw.Wd))
|
|
||||||
delete(w.watches, name)
|
|
||||||
}
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
if nameLen > 0 {
|
|
||||||
// Point "bytes" at the first byte of the filename
|
|
||||||
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]
|
|
||||||
// The filename is padded with NULL bytes. TrimRight() gets rid of those.
|
|
||||||
name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
|
|
||||||
}
|
|
||||||
|
|
||||||
event := w.newEvent(name, mask)
|
|
||||||
|
|
||||||
// Send the events that are not ignored on the events channel
|
|
||||||
if mask&unix.IN_IGNORED == 0 {
|
|
||||||
if !w.sendEvent(event) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to the next event in the buffer
|
|
||||||
offset += unix.SizeofInotifyEvent + nameLen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newEvent returns an platform-independent Event based on an inotify mask.
|
|
||||||
func (w *Watcher) newEvent(name string, mask uint32) Event {
|
|
||||||
e := Event{Name: name}
|
|
||||||
if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
|
|
||||||
e.Op |= Create
|
|
||||||
}
|
|
||||||
if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE {
|
|
||||||
e.Op |= Remove
|
|
||||||
}
|
|
||||||
if mask&unix.IN_MODIFY == unix.IN_MODIFY {
|
|
||||||
e.Op |= Write
|
|
||||||
}
|
|
||||||
if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
|
|
||||||
e.Op |= Rename
|
|
||||||
}
|
|
||||||
if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
|
|
||||||
e.Op |= Chmod
|
|
||||||
}
|
|
||||||
return e
|
|
||||||
}
|
|
707
vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
generated
vendored
707
vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
generated
vendored
@ -1,707 +0,0 @@
|
|||||||
//go:build freebsd || openbsd || netbsd || dragonfly || darwin
|
|
||||||
// +build freebsd openbsd netbsd dragonfly darwin
|
|
||||||
|
|
||||||
package fsnotify
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Watcher watches a set of paths, delivering events on a channel.
|
|
||||||
//
|
|
||||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
|
||||||
// value).
|
|
||||||
//
|
|
||||||
// # Linux notes
|
|
||||||
//
|
|
||||||
// When a file is removed a Remove event won't be emitted until all file
|
|
||||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
|
||||||
//
|
|
||||||
// fp := os.Open("file")
|
|
||||||
// os.Remove("file") // Triggers Chmod
|
|
||||||
// fp.Close() // Triggers Remove
|
|
||||||
//
|
|
||||||
// This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
//
|
|
||||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
|
||||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
|
||||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
|
||||||
// create is an "instance", and every path you add is a "watch".
|
|
||||||
//
|
|
||||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
|
||||||
// /proc/sys/fs/inotify/max_user_instances
|
|
||||||
//
|
|
||||||
// To increase them you can use sysctl or write the value to the /proc file:
|
|
||||||
//
|
|
||||||
// # Default values on Linux 5.18
|
|
||||||
// sysctl fs.inotify.max_user_watches=124983
|
|
||||||
// sysctl fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
|
||||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
|
||||||
// your distro's documentation):
|
|
||||||
//
|
|
||||||
// fs.inotify.max_user_watches=124983
|
|
||||||
// fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
// files" error.
|
|
||||||
//
|
|
||||||
// # kqueue notes (macOS, BSD)
|
|
||||||
//
|
|
||||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
// so if you're watching a directory with five files then that's six file
|
|
||||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
// these platforms.
|
|
||||||
//
|
|
||||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
|
||||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
|
||||||
// systems.
|
|
||||||
//
|
|
||||||
// # macOS notes
|
|
||||||
//
|
|
||||||
// Spotlight indexing on macOS can result in multiple events (see [#15]). A
|
|
||||||
// temporary workaround is to add your folder(s) to the "Spotlight Privacy
|
|
||||||
// Settings" until we have a native FSEvents implementation (see [#11]).
|
|
||||||
//
|
|
||||||
// [#11]: https://github.com/fsnotify/fsnotify/issues/11
|
|
||||||
// [#15]: https://github.com/fsnotify/fsnotify/issues/15
|
|
||||||
type Watcher struct {
|
|
||||||
// Events sends the filesystem change events.
|
|
||||||
//
|
|
||||||
// fsnotify can send the following events; a "path" here can refer to a
|
|
||||||
// file, directory, symbolic link, or special file like a FIFO.
|
|
||||||
//
|
|
||||||
// fsnotify.Create A new path was created; this may be followed by one
|
|
||||||
// or more Write events if data also gets written to a
|
|
||||||
// file.
|
|
||||||
//
|
|
||||||
// fsnotify.Remove A path was removed.
|
|
||||||
//
|
|
||||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
|
||||||
// old path as Event.Name, and a Create event will be
|
|
||||||
// sent with the new name. Renames are only sent for
|
|
||||||
// paths that are currently watched; e.g. moving an
|
|
||||||
// unmonitored file into a monitored directory will
|
|
||||||
// show up as just a Create. Similarly, renaming a file
|
|
||||||
// to outside a monitored directory will show up as
|
|
||||||
// only a Rename.
|
|
||||||
//
|
|
||||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
|
||||||
// also trigger a Write. A single "write action"
|
|
||||||
// initiated by the user may show up as one or multiple
|
|
||||||
// writes, depending on when the system syncs things to
|
|
||||||
// disk. For example when compiling a large Go program
|
|
||||||
// you may get hundreds of Write events, so you
|
|
||||||
// probably want to wait until you've stopped receiving
|
|
||||||
// them (see the dedup example in cmd/fsnotify).
|
|
||||||
//
|
|
||||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
|
||||||
// when a file is removed (or more accurately, when a
|
|
||||||
// link to an inode is removed). On kqueue it's sent
|
|
||||||
// and on kqueue when a file is truncated. On Windows
|
|
||||||
// it's never sent.
|
|
||||||
Events chan Event
|
|
||||||
|
|
||||||
// Errors sends any errors.
|
|
||||||
Errors chan error
|
|
||||||
|
|
||||||
done chan struct{}
|
|
||||||
kq int // File descriptor (as returned by the kqueue() syscall).
|
|
||||||
closepipe [2]int // Pipe used for closing.
|
|
||||||
mu sync.Mutex // Protects access to watcher data
|
|
||||||
watches map[string]int // Watched file descriptors (key: path).
|
|
||||||
watchesByDir map[string]map[int]struct{} // Watched file descriptors indexed by the parent directory (key: dirname(path)).
|
|
||||||
userWatches map[string]struct{} // Watches added with Watcher.Add()
|
|
||||||
dirFlags map[string]uint32 // Watched directories to fflags used in kqueue.
|
|
||||||
paths map[int]pathInfo // File descriptors to path names for processing kqueue events.
|
|
||||||
fileExists map[string]struct{} // Keep track of if we know this file exists (to stop duplicate create events).
|
|
||||||
isClosed bool // Set to true when Close() is first called
|
|
||||||
}
|
|
||||||
|
|
||||||
type pathInfo struct {
|
|
||||||
name string
|
|
||||||
isDir bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWatcher creates a new Watcher.
|
|
||||||
func NewWatcher() (*Watcher, error) {
|
|
||||||
kq, closepipe, err := newKqueue()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
w := &Watcher{
|
|
||||||
kq: kq,
|
|
||||||
closepipe: closepipe,
|
|
||||||
watches: make(map[string]int),
|
|
||||||
watchesByDir: make(map[string]map[int]struct{}),
|
|
||||||
dirFlags: make(map[string]uint32),
|
|
||||||
paths: make(map[int]pathInfo),
|
|
||||||
fileExists: make(map[string]struct{}),
|
|
||||||
userWatches: make(map[string]struct{}),
|
|
||||||
Events: make(chan Event),
|
|
||||||
Errors: make(chan error),
|
|
||||||
done: make(chan struct{}),
|
|
||||||
}
|
|
||||||
|
|
||||||
go w.readEvents()
|
|
||||||
return w, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newKqueue creates a new kernel event queue and returns a descriptor.
|
|
||||||
//
|
|
||||||
// This registers a new event on closepipe, which will trigger an event when
|
|
||||||
// it's closed. This way we can use kevent() without timeout/polling; without
|
|
||||||
// the closepipe, it would block forever and we wouldn't be able to stop it at
|
|
||||||
// all.
|
|
||||||
func newKqueue() (kq int, closepipe [2]int, err error) {
|
|
||||||
kq, err = unix.Kqueue()
|
|
||||||
if kq == -1 {
|
|
||||||
return kq, closepipe, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the close pipe.
|
|
||||||
err = unix.Pipe(closepipe[:])
|
|
||||||
if err != nil {
|
|
||||||
unix.Close(kq)
|
|
||||||
return kq, closepipe, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register changes to listen on the closepipe.
|
|
||||||
changes := make([]unix.Kevent_t, 1)
|
|
||||||
// SetKevent converts int to the platform-specific types.
|
|
||||||
unix.SetKevent(&changes[0], closepipe[0], unix.EVFILT_READ,
|
|
||||||
unix.EV_ADD|unix.EV_ENABLE|unix.EV_ONESHOT)
|
|
||||||
|
|
||||||
ok, err := unix.Kevent(kq, changes, nil, nil)
|
|
||||||
if ok == -1 {
|
|
||||||
unix.Close(kq)
|
|
||||||
unix.Close(closepipe[0])
|
|
||||||
unix.Close(closepipe[1])
|
|
||||||
return kq, closepipe, err
|
|
||||||
}
|
|
||||||
return kq, closepipe, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the event was sent, or false if watcher is closed.
|
|
||||||
func (w *Watcher) sendEvent(e Event) bool {
|
|
||||||
select {
|
|
||||||
case w.Events <- e:
|
|
||||||
return true
|
|
||||||
case <-w.done:
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the error was sent, or false if watcher is closed.
|
|
||||||
func (w *Watcher) sendError(err error) bool {
|
|
||||||
select {
|
|
||||||
case w.Errors <- err:
|
|
||||||
return true
|
|
||||||
case <-w.done:
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close removes all watches and closes the events channel.
|
|
||||||
func (w *Watcher) Close() error {
|
|
||||||
w.mu.Lock()
|
|
||||||
if w.isClosed {
|
|
||||||
w.mu.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
w.isClosed = true
|
|
||||||
|
|
||||||
// copy paths to remove while locked
|
|
||||||
pathsToRemove := make([]string, 0, len(w.watches))
|
|
||||||
for name := range w.watches {
|
|
||||||
pathsToRemove = append(pathsToRemove, name)
|
|
||||||
}
|
|
||||||
w.mu.Unlock() // Unlock before calling Remove, which also locks
|
|
||||||
for _, name := range pathsToRemove {
|
|
||||||
w.Remove(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send "quit" message to the reader goroutine.
|
|
||||||
unix.Close(w.closepipe[1])
|
|
||||||
close(w.done)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add starts monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// A path can only be watched once; attempting to watch it more than once will
|
|
||||||
// return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// added. A watch will be automatically removed if the path is deleted.
|
|
||||||
//
|
|
||||||
// A path will remain watched if it gets renamed to somewhere else on the same
|
|
||||||
// filesystem, but the monitor will get removed if the path gets deleted and
|
|
||||||
// re-created, or if it's moved to a different filesystem.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many tools update files atomically. Instead of "just" writing
|
|
||||||
// to the file a temporary file will be written to first, and if successful the
|
|
||||||
// temporary file is moved to to destination removing the original, or some
|
|
||||||
// variant thereof. The watcher on the original file is now lost, as it no
|
|
||||||
// longer exists.
|
|
||||||
//
|
|
||||||
// Instead, watch the parent directory and use Event.Name to filter out files
|
|
||||||
// you're not interested in. There is an example of this in [cmd/fsnotify/file.go].
|
|
||||||
func (w *Watcher) Add(name string) error {
|
|
||||||
w.mu.Lock()
|
|
||||||
w.userWatches[name] = struct{}{}
|
|
||||||
w.mu.Unlock()
|
|
||||||
_, err := w.addWatch(name, noteAllEvents)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove stops monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
func (w *Watcher) Remove(name string) error {
|
|
||||||
name = filepath.Clean(name)
|
|
||||||
w.mu.Lock()
|
|
||||||
watchfd, ok := w.watches[name]
|
|
||||||
w.mu.Unlock()
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("%w: %s", ErrNonExistentWatch, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := w.register([]int{watchfd}, unix.EV_DELETE, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
unix.Close(watchfd)
|
|
||||||
|
|
||||||
w.mu.Lock()
|
|
||||||
isDir := w.paths[watchfd].isDir
|
|
||||||
delete(w.watches, name)
|
|
||||||
delete(w.userWatches, name)
|
|
||||||
|
|
||||||
parentName := filepath.Dir(name)
|
|
||||||
delete(w.watchesByDir[parentName], watchfd)
|
|
||||||
|
|
||||||
if len(w.watchesByDir[parentName]) == 0 {
|
|
||||||
delete(w.watchesByDir, parentName)
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(w.paths, watchfd)
|
|
||||||
delete(w.dirFlags, name)
|
|
||||||
delete(w.fileExists, name)
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
// Find all watched paths that are in this directory that are not external.
|
|
||||||
if isDir {
|
|
||||||
var pathsToRemove []string
|
|
||||||
w.mu.Lock()
|
|
||||||
for fd := range w.watchesByDir[name] {
|
|
||||||
path := w.paths[fd]
|
|
||||||
if _, ok := w.userWatches[path.name]; !ok {
|
|
||||||
pathsToRemove = append(pathsToRemove, path.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.mu.Unlock()
|
|
||||||
for _, name := range pathsToRemove {
|
|
||||||
// Since these are internal, not much sense in propagating error
|
|
||||||
// to the user, as that will just confuse them with an error about
|
|
||||||
// a path they did not explicitly watch themselves.
|
|
||||||
w.Remove(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchList returns all paths added with [Add] (and are not yet removed).
|
|
||||||
func (w *Watcher) WatchList() []string {
|
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
|
|
||||||
entries := make([]string, 0, len(w.userWatches))
|
|
||||||
for pathname := range w.userWatches {
|
|
||||||
entries = append(entries, pathname)
|
|
||||||
}
|
|
||||||
|
|
||||||
return entries
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
|
|
||||||
const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME
|
|
||||||
|
|
||||||
// addWatch adds name to the watched file set.
|
|
||||||
// The flags are interpreted as described in kevent(2).
|
|
||||||
// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks.
|
|
||||||
func (w *Watcher) addWatch(name string, flags uint32) (string, error) {
|
|
||||||
var isDir bool
|
|
||||||
// Make ./name and name equivalent
|
|
||||||
name = filepath.Clean(name)
|
|
||||||
|
|
||||||
w.mu.Lock()
|
|
||||||
if w.isClosed {
|
|
||||||
w.mu.Unlock()
|
|
||||||
return "", errors.New("kevent instance already closed")
|
|
||||||
}
|
|
||||||
watchfd, alreadyWatching := w.watches[name]
|
|
||||||
// We already have a watch, but we can still override flags.
|
|
||||||
if alreadyWatching {
|
|
||||||
isDir = w.paths[watchfd].isDir
|
|
||||||
}
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
if !alreadyWatching {
|
|
||||||
fi, err := os.Lstat(name)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't watch sockets or named pipes
|
|
||||||
if (fi.Mode()&os.ModeSocket == os.ModeSocket) || (fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe) {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Follow Symlinks
|
|
||||||
//
|
|
||||||
// Linux can add unresolvable symlinks to the watch list without issue,
|
|
||||||
// and Windows can't do symlinks period. To maintain consistency, we
|
|
||||||
// will act like everything is fine if the link can't be resolved.
|
|
||||||
// There will simply be no file events for broken symlinks. Hence the
|
|
||||||
// returns of nil on errors.
|
|
||||||
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
|
|
||||||
name, err = filepath.EvalSymlinks(name)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
w.mu.Lock()
|
|
||||||
_, alreadyWatching = w.watches[name]
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
if alreadyWatching {
|
|
||||||
return name, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err = os.Lstat(name)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retry on EINTR; open() can return EINTR in practice on macOS.
|
|
||||||
// See #354, and go issues 11180 and 39237.
|
|
||||||
for {
|
|
||||||
watchfd, err = unix.Open(name, openMode, 0)
|
|
||||||
if err == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if errors.Is(err, unix.EINTR) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
isDir = fi.IsDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
err := w.register([]int{watchfd}, unix.EV_ADD|unix.EV_CLEAR|unix.EV_ENABLE, flags)
|
|
||||||
if err != nil {
|
|
||||||
unix.Close(watchfd)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !alreadyWatching {
|
|
||||||
w.mu.Lock()
|
|
||||||
parentName := filepath.Dir(name)
|
|
||||||
w.watches[name] = watchfd
|
|
||||||
|
|
||||||
watchesByDir, ok := w.watchesByDir[parentName]
|
|
||||||
if !ok {
|
|
||||||
watchesByDir = make(map[int]struct{}, 1)
|
|
||||||
w.watchesByDir[parentName] = watchesByDir
|
|
||||||
}
|
|
||||||
watchesByDir[watchfd] = struct{}{}
|
|
||||||
|
|
||||||
w.paths[watchfd] = pathInfo{name: name, isDir: isDir}
|
|
||||||
w.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
if isDir {
|
|
||||||
// Watch the directory if it has not been watched before,
|
|
||||||
// or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles)
|
|
||||||
w.mu.Lock()
|
|
||||||
|
|
||||||
watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE &&
|
|
||||||
(!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE)
|
|
||||||
// Store flags so this watch can be updated later
|
|
||||||
w.dirFlags[name] = flags
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
if watchDir {
|
|
||||||
if err := w.watchDirectoryFiles(name); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return name, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// readEvents reads from kqueue and converts the received kevents into
|
|
||||||
// Event values that it sends down the Events channel.
|
|
||||||
func (w *Watcher) readEvents() {
|
|
||||||
defer func() {
|
|
||||||
err := unix.Close(w.kq)
|
|
||||||
if err != nil {
|
|
||||||
w.Errors <- err
|
|
||||||
}
|
|
||||||
unix.Close(w.closepipe[0])
|
|
||||||
close(w.Events)
|
|
||||||
close(w.Errors)
|
|
||||||
}()
|
|
||||||
|
|
||||||
eventBuffer := make([]unix.Kevent_t, 10)
|
|
||||||
for closed := false; !closed; {
|
|
||||||
kevents, err := w.read(eventBuffer)
|
|
||||||
// EINTR is okay, the syscall was interrupted before timeout expired.
|
|
||||||
if err != nil && err != unix.EINTR {
|
|
||||||
if !w.sendError(fmt.Errorf("fsnotify.readEvents: %w", err)) {
|
|
||||||
closed = true
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush the events we received to the Events channel
|
|
||||||
for _, kevent := range kevents {
|
|
||||||
var (
|
|
||||||
watchfd = int(kevent.Ident)
|
|
||||||
mask = uint32(kevent.Fflags)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Shut down the loop when the pipe is closed, but only after all
|
|
||||||
// other events have been processed.
|
|
||||||
if watchfd == w.closepipe[0] {
|
|
||||||
closed = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
w.mu.Lock()
|
|
||||||
path := w.paths[watchfd]
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
event := w.newEvent(path.name, mask)
|
|
||||||
|
|
||||||
if path.isDir && !event.Has(Remove) {
|
|
||||||
// Double check to make sure the directory exists. This can
|
|
||||||
// happen when we do a rm -fr on a recursively watched folders
|
|
||||||
// and we receive a modification event first but the folder has
|
|
||||||
// been deleted and later receive the delete event.
|
|
||||||
if _, err := os.Lstat(event.Name); os.IsNotExist(err) {
|
|
||||||
event.Op |= Remove
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if event.Has(Rename) || event.Has(Remove) {
|
|
||||||
w.Remove(event.Name)
|
|
||||||
w.mu.Lock()
|
|
||||||
delete(w.fileExists, event.Name)
|
|
||||||
w.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
if path.isDir && event.Has(Write) && !event.Has(Remove) {
|
|
||||||
w.sendDirectoryChangeEvents(event.Name)
|
|
||||||
} else {
|
|
||||||
if !w.sendEvent(event) {
|
|
||||||
closed = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if event.Has(Remove) {
|
|
||||||
// Look for a file that may have overwritten this.
|
|
||||||
// For example, mv f1 f2 will delete f2, then create f2.
|
|
||||||
if path.isDir {
|
|
||||||
fileDir := filepath.Clean(event.Name)
|
|
||||||
w.mu.Lock()
|
|
||||||
_, found := w.watches[fileDir]
|
|
||||||
w.mu.Unlock()
|
|
||||||
if found {
|
|
||||||
// make sure the directory exists before we watch for changes. When we
|
|
||||||
// do a recursive watch and perform rm -fr, the parent directory might
|
|
||||||
// have gone missing, ignore the missing directory and let the
|
|
||||||
// upcoming delete event remove the watch from the parent directory.
|
|
||||||
if _, err := os.Lstat(fileDir); err == nil {
|
|
||||||
w.sendDirectoryChangeEvents(fileDir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
filePath := filepath.Clean(event.Name)
|
|
||||||
if fileInfo, err := os.Lstat(filePath); err == nil {
|
|
||||||
w.sendFileCreatedEventIfNew(filePath, fileInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newEvent returns an platform-independent Event based on kqueue Fflags.
|
|
||||||
func (w *Watcher) newEvent(name string, mask uint32) Event {
|
|
||||||
e := Event{Name: name}
|
|
||||||
if mask&unix.NOTE_DELETE == unix.NOTE_DELETE {
|
|
||||||
e.Op |= Remove
|
|
||||||
}
|
|
||||||
if mask&unix.NOTE_WRITE == unix.NOTE_WRITE {
|
|
||||||
e.Op |= Write
|
|
||||||
}
|
|
||||||
if mask&unix.NOTE_RENAME == unix.NOTE_RENAME {
|
|
||||||
e.Op |= Rename
|
|
||||||
}
|
|
||||||
if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB {
|
|
||||||
e.Op |= Chmod
|
|
||||||
}
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// watchDirectoryFiles to mimic inotify when adding a watch on a directory
|
|
||||||
func (w *Watcher) watchDirectoryFiles(dirPath string) error {
|
|
||||||
// Get all files
|
|
||||||
files, err := ioutil.ReadDir(dirPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fileInfo := range files {
|
|
||||||
path := filepath.Join(dirPath, fileInfo.Name())
|
|
||||||
|
|
||||||
cleanPath, err := w.internalWatch(path, fileInfo)
|
|
||||||
if err != nil {
|
|
||||||
// No permission to read the file; that's not a problem: just skip.
|
|
||||||
// But do add it to w.fileExists to prevent it from being picked up
|
|
||||||
// as a "new" file later (it still shows up in the directory
|
|
||||||
// listing).
|
|
||||||
switch {
|
|
||||||
case errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM):
|
|
||||||
cleanPath = filepath.Clean(path)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("%q: %w", filepath.Join(dirPath, fileInfo.Name()), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w.mu.Lock()
|
|
||||||
w.fileExists[cleanPath] = struct{}{}
|
|
||||||
w.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search the directory for new files and send an event for them.
|
|
||||||
//
|
|
||||||
// This functionality is to have the BSD watcher match the inotify, which sends
|
|
||||||
// a create event for files created in a watched directory.
|
|
||||||
func (w *Watcher) sendDirectoryChangeEvents(dir string) {
|
|
||||||
// Get all files
|
|
||||||
files, err := ioutil.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
if !w.sendError(fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for new files
|
|
||||||
for _, fi := range files {
|
|
||||||
err := w.sendFileCreatedEventIfNew(filepath.Join(dir, fi.Name()), fi)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendFileCreatedEvent sends a create event if the file isn't already being tracked.
|
|
||||||
func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) {
|
|
||||||
w.mu.Lock()
|
|
||||||
_, doesExist := w.fileExists[filePath]
|
|
||||||
w.mu.Unlock()
|
|
||||||
if !doesExist {
|
|
||||||
if !w.sendEvent(Event{Name: filePath, Op: Create}) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// like watchDirectoryFiles (but without doing another ReadDir)
|
|
||||||
filePath, err = w.internalWatch(filePath, fileInfo)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
w.mu.Lock()
|
|
||||||
w.fileExists[filePath] = struct{}{}
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) {
|
|
||||||
if fileInfo.IsDir() {
|
|
||||||
// mimic Linux providing delete events for subdirectories
|
|
||||||
// but preserve the flags used if currently watching subdirectory
|
|
||||||
w.mu.Lock()
|
|
||||||
flags := w.dirFlags[name]
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
flags |= unix.NOTE_DELETE | unix.NOTE_RENAME
|
|
||||||
return w.addWatch(name, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// watch file to mimic Linux inotify
|
|
||||||
return w.addWatch(name, noteAllEvents)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register events with the queue.
|
|
||||||
func (w *Watcher) register(fds []int, flags int, fflags uint32) error {
|
|
||||||
changes := make([]unix.Kevent_t, len(fds))
|
|
||||||
for i, fd := range fds {
|
|
||||||
// SetKevent converts int to the platform-specific types.
|
|
||||||
unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags)
|
|
||||||
changes[i].Fflags = fflags
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the events.
|
|
||||||
success, err := unix.Kevent(w.kq, changes, nil, nil)
|
|
||||||
if success == -1 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// read retrieves pending events, or waits until an event occurs.
|
|
||||||
func (w *Watcher) read(events []unix.Kevent_t) ([]unix.Kevent_t, error) {
|
|
||||||
n, err := unix.Kevent(w.kq, nil, events, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return events[0:n], nil
|
|
||||||
}
|
|
66
vendor/github.com/fsnotify/fsnotify/backend_other.go
generated
vendored
66
vendor/github.com/fsnotify/fsnotify/backend_other.go
generated
vendored
@ -1,66 +0,0 @@
|
|||||||
//go:build !darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows
|
|
||||||
// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
|
|
||||||
|
|
||||||
package fsnotify
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Watcher watches a set of files, delivering events to a channel.
|
|
||||||
type Watcher struct{}
|
|
||||||
|
|
||||||
// NewWatcher creates a new Watcher.
|
|
||||||
func NewWatcher() (*Watcher, error) {
|
|
||||||
return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close removes all watches and closes the events channel.
|
|
||||||
func (w *Watcher) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add starts monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// A path can only be watched once; attempting to watch it more than once will
|
|
||||||
// return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// added. A watch will be automatically removed if the path is deleted.
|
|
||||||
//
|
|
||||||
// A path will remain watched if it gets renamed to somewhere else on the same
|
|
||||||
// filesystem, but the monitor will get removed if the path gets deleted and
|
|
||||||
// re-created, or if it's moved to a different filesystem.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many tools update files atomically. Instead of "just" writing
|
|
||||||
// to the file a temporary file will be written to first, and if successful the
|
|
||||||
// temporary file is moved to to destination removing the original, or some
|
|
||||||
// variant thereof. The watcher on the original file is now lost, as it no
|
|
||||||
// longer exists.
|
|
||||||
//
|
|
||||||
// Instead, watch the parent directory and use Event.Name to filter out files
|
|
||||||
// you're not interested in. There is an example of this in [cmd/fsnotify/file.go].
|
|
||||||
func (w *Watcher) Add(name string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove stops monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
func (w *Watcher) Remove(name string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
746
vendor/github.com/fsnotify/fsnotify/backend_windows.go
generated
vendored
746
vendor/github.com/fsnotify/fsnotify/backend_windows.go
generated
vendored
@ -1,746 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package fsnotify
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Watcher watches a set of paths, delivering events on a channel.
|
|
||||||
//
|
|
||||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
|
||||||
// value).
|
|
||||||
//
|
|
||||||
// # Linux notes
|
|
||||||
//
|
|
||||||
// When a file is removed a Remove event won't be emitted until all file
|
|
||||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
|
||||||
//
|
|
||||||
// fp := os.Open("file")
|
|
||||||
// os.Remove("file") // Triggers Chmod
|
|
||||||
// fp.Close() // Triggers Remove
|
|
||||||
//
|
|
||||||
// This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
//
|
|
||||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
|
||||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
|
||||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
|
||||||
// create is an "instance", and every path you add is a "watch".
|
|
||||||
//
|
|
||||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
|
||||||
// /proc/sys/fs/inotify/max_user_instances
|
|
||||||
//
|
|
||||||
// To increase them you can use sysctl or write the value to the /proc file:
|
|
||||||
//
|
|
||||||
// # Default values on Linux 5.18
|
|
||||||
// sysctl fs.inotify.max_user_watches=124983
|
|
||||||
// sysctl fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
|
||||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
|
||||||
// your distro's documentation):
|
|
||||||
//
|
|
||||||
// fs.inotify.max_user_watches=124983
|
|
||||||
// fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
// files" error.
|
|
||||||
//
|
|
||||||
// # kqueue notes (macOS, BSD)
|
|
||||||
//
|
|
||||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
// so if you're watching a directory with five files then that's six file
|
|
||||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
// these platforms.
|
|
||||||
//
|
|
||||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
|
||||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
|
||||||
// systems.
|
|
||||||
//
|
|
||||||
// # macOS notes
|
|
||||||
//
|
|
||||||
// Spotlight indexing on macOS can result in multiple events (see [#15]). A
|
|
||||||
// temporary workaround is to add your folder(s) to the "Spotlight Privacy
|
|
||||||
// Settings" until we have a native FSEvents implementation (see [#11]).
|
|
||||||
//
|
|
||||||
// [#11]: https://github.com/fsnotify/fsnotify/issues/11
|
|
||||||
// [#15]: https://github.com/fsnotify/fsnotify/issues/15
|
|
||||||
type Watcher struct {
|
|
||||||
// Events sends the filesystem change events.
|
|
||||||
//
|
|
||||||
// fsnotify can send the following events; a "path" here can refer to a
|
|
||||||
// file, directory, symbolic link, or special file like a FIFO.
|
|
||||||
//
|
|
||||||
// fsnotify.Create A new path was created; this may be followed by one
|
|
||||||
// or more Write events if data also gets written to a
|
|
||||||
// file.
|
|
||||||
//
|
|
||||||
// fsnotify.Remove A path was removed.
|
|
||||||
//
|
|
||||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
|
||||||
// old path as Event.Name, and a Create event will be
|
|
||||||
// sent with the new name. Renames are only sent for
|
|
||||||
// paths that are currently watched; e.g. moving an
|
|
||||||
// unmonitored file into a monitored directory will
|
|
||||||
// show up as just a Create. Similarly, renaming a file
|
|
||||||
// to outside a monitored directory will show up as
|
|
||||||
// only a Rename.
|
|
||||||
//
|
|
||||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
|
||||||
// also trigger a Write. A single "write action"
|
|
||||||
// initiated by the user may show up as one or multiple
|
|
||||||
// writes, depending on when the system syncs things to
|
|
||||||
// disk. For example when compiling a large Go program
|
|
||||||
// you may get hundreds of Write events, so you
|
|
||||||
// probably want to wait until you've stopped receiving
|
|
||||||
// them (see the dedup example in cmd/fsnotify).
|
|
||||||
//
|
|
||||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
|
||||||
// when a file is removed (or more accurately, when a
|
|
||||||
// link to an inode is removed). On kqueue it's sent
|
|
||||||
// and on kqueue when a file is truncated. On Windows
|
|
||||||
// it's never sent.
|
|
||||||
Events chan Event
|
|
||||||
|
|
||||||
// Errors sends any errors.
|
|
||||||
Errors chan error
|
|
||||||
|
|
||||||
port windows.Handle // Handle to completion port
|
|
||||||
input chan *input // Inputs to the reader are sent on this channel
|
|
||||||
quit chan chan<- error
|
|
||||||
|
|
||||||
mu sync.Mutex // Protects access to watches, isClosed
|
|
||||||
watches watchMap // Map of watches (key: i-number)
|
|
||||||
isClosed bool // Set to true when Close() is first called
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWatcher creates a new Watcher.
|
|
||||||
func NewWatcher() (*Watcher, error) {
|
|
||||||
port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, os.NewSyscallError("CreateIoCompletionPort", err)
|
|
||||||
}
|
|
||||||
w := &Watcher{
|
|
||||||
port: port,
|
|
||||||
watches: make(watchMap),
|
|
||||||
input: make(chan *input, 1),
|
|
||||||
Events: make(chan Event, 50),
|
|
||||||
Errors: make(chan error),
|
|
||||||
quit: make(chan chan<- error, 1),
|
|
||||||
}
|
|
||||||
go w.readEvents()
|
|
||||||
return w, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) sendEvent(name string, mask uint64) bool {
|
|
||||||
if mask == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
event := w.newEvent(name, uint32(mask))
|
|
||||||
select {
|
|
||||||
case ch := <-w.quit:
|
|
||||||
w.quit <- ch
|
|
||||||
case w.Events <- event:
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the error was sent, or false if watcher is closed.
|
|
||||||
func (w *Watcher) sendError(err error) bool {
|
|
||||||
select {
|
|
||||||
case w.Errors <- err:
|
|
||||||
return true
|
|
||||||
case <-w.quit:
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close removes all watches and closes the events channel.
|
|
||||||
func (w *Watcher) Close() error {
|
|
||||||
w.mu.Lock()
|
|
||||||
if w.isClosed {
|
|
||||||
w.mu.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
w.isClosed = true
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
// Send "quit" message to the reader goroutine
|
|
||||||
ch := make(chan error)
|
|
||||||
w.quit <- ch
|
|
||||||
if err := w.wakeupReader(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return <-ch
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add starts monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// A path can only be watched once; attempting to watch it more than once will
|
|
||||||
// return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// added. A watch will be automatically removed if the path is deleted.
|
|
||||||
//
|
|
||||||
// A path will remain watched if it gets renamed to somewhere else on the same
|
|
||||||
// filesystem, but the monitor will get removed if the path gets deleted and
|
|
||||||
// re-created, or if it's moved to a different filesystem.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many tools update files atomically. Instead of "just" writing
|
|
||||||
// to the file a temporary file will be written to first, and if successful the
|
|
||||||
// temporary file is moved to to destination removing the original, or some
|
|
||||||
// variant thereof. The watcher on the original file is now lost, as it no
|
|
||||||
// longer exists.
|
|
||||||
//
|
|
||||||
// Instead, watch the parent directory and use Event.Name to filter out files
|
|
||||||
// you're not interested in. There is an example of this in [cmd/fsnotify/file.go].
|
|
||||||
func (w *Watcher) Add(name string) error {
|
|
||||||
w.mu.Lock()
|
|
||||||
if w.isClosed {
|
|
||||||
w.mu.Unlock()
|
|
||||||
return errors.New("watcher already closed")
|
|
||||||
}
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
in := &input{
|
|
||||||
op: opAddWatch,
|
|
||||||
path: filepath.Clean(name),
|
|
||||||
flags: sysFSALLEVENTS,
|
|
||||||
reply: make(chan error),
|
|
||||||
}
|
|
||||||
w.input <- in
|
|
||||||
if err := w.wakeupReader(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return <-in.reply
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove stops monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
func (w *Watcher) Remove(name string) error {
|
|
||||||
in := &input{
|
|
||||||
op: opRemoveWatch,
|
|
||||||
path: filepath.Clean(name),
|
|
||||||
reply: make(chan error),
|
|
||||||
}
|
|
||||||
w.input <- in
|
|
||||||
if err := w.wakeupReader(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return <-in.reply
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchList returns all paths added with [Add] (and are not yet removed).
|
|
||||||
func (w *Watcher) WatchList() []string {
|
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
|
|
||||||
entries := make([]string, 0, len(w.watches))
|
|
||||||
for _, entry := range w.watches {
|
|
||||||
for _, watchEntry := range entry {
|
|
||||||
entries = append(entries, watchEntry.path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return entries
|
|
||||||
}
|
|
||||||
|
|
||||||
// These options are from the old golang.org/x/exp/winfsnotify, where you could
|
|
||||||
// add various options to the watch. This has long since been removed.
|
|
||||||
//
|
|
||||||
// The "sys" in the name is misleading as they're not part of any "system".
|
|
||||||
//
|
|
||||||
// This should all be removed at some point, and just use windows.FILE_NOTIFY_*
|
|
||||||
const (
|
|
||||||
sysFSALLEVENTS = 0xfff
|
|
||||||
sysFSATTRIB = 0x4
|
|
||||||
sysFSCREATE = 0x100
|
|
||||||
sysFSDELETE = 0x200
|
|
||||||
sysFSDELETESELF = 0x400
|
|
||||||
sysFSMODIFY = 0x2
|
|
||||||
sysFSMOVE = 0xc0
|
|
||||||
sysFSMOVEDFROM = 0x40
|
|
||||||
sysFSMOVEDTO = 0x80
|
|
||||||
sysFSMOVESELF = 0x800
|
|
||||||
sysFSIGNORED = 0x8000
|
|
||||||
)
|
|
||||||
|
|
||||||
func (w *Watcher) newEvent(name string, mask uint32) Event {
|
|
||||||
e := Event{Name: name}
|
|
||||||
if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
|
|
||||||
e.Op |= Create
|
|
||||||
}
|
|
||||||
if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF {
|
|
||||||
e.Op |= Remove
|
|
||||||
}
|
|
||||||
if mask&sysFSMODIFY == sysFSMODIFY {
|
|
||||||
e.Op |= Write
|
|
||||||
}
|
|
||||||
if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM {
|
|
||||||
e.Op |= Rename
|
|
||||||
}
|
|
||||||
if mask&sysFSATTRIB == sysFSATTRIB {
|
|
||||||
e.Op |= Chmod
|
|
||||||
}
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
opAddWatch = iota
|
|
||||||
opRemoveWatch
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
provisional uint64 = 1 << (32 + iota)
|
|
||||||
)
|
|
||||||
|
|
||||||
type input struct {
|
|
||||||
op int
|
|
||||||
path string
|
|
||||||
flags uint32
|
|
||||||
reply chan error
|
|
||||||
}
|
|
||||||
|
|
||||||
type inode struct {
|
|
||||||
handle windows.Handle
|
|
||||||
volume uint32
|
|
||||||
index uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type watch struct {
|
|
||||||
ov windows.Overlapped
|
|
||||||
ino *inode // i-number
|
|
||||||
path string // Directory path
|
|
||||||
mask uint64 // Directory itself is being watched with these notify flags
|
|
||||||
names map[string]uint64 // Map of names being watched and their notify flags
|
|
||||||
rename string // Remembers the old name while renaming a file
|
|
||||||
buf [65536]byte // 64K buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
type (
|
|
||||||
indexMap map[uint64]*watch
|
|
||||||
watchMap map[uint32]indexMap
|
|
||||||
)
|
|
||||||
|
|
||||||
func (w *Watcher) wakeupReader() error {
|
|
||||||
err := windows.PostQueuedCompletionStatus(w.port, 0, 0, nil)
|
|
||||||
if err != nil {
|
|
||||||
return os.NewSyscallError("PostQueuedCompletionStatus", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) getDir(pathname string) (dir string, err error) {
|
|
||||||
attr, err := windows.GetFileAttributes(windows.StringToUTF16Ptr(pathname))
|
|
||||||
if err != nil {
|
|
||||||
return "", os.NewSyscallError("GetFileAttributes", err)
|
|
||||||
}
|
|
||||||
if attr&windows.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
|
||||||
dir = pathname
|
|
||||||
} else {
|
|
||||||
dir, _ = filepath.Split(pathname)
|
|
||||||
dir = filepath.Clean(dir)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) getIno(path string) (ino *inode, err error) {
|
|
||||||
h, err := windows.CreateFile(windows.StringToUTF16Ptr(path),
|
|
||||||
windows.FILE_LIST_DIRECTORY,
|
|
||||||
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
|
|
||||||
nil, windows.OPEN_EXISTING,
|
|
||||||
windows.FILE_FLAG_BACKUP_SEMANTICS|windows.FILE_FLAG_OVERLAPPED, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, os.NewSyscallError("CreateFile", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var fi windows.ByHandleFileInformation
|
|
||||||
err = windows.GetFileInformationByHandle(h, &fi)
|
|
||||||
if err != nil {
|
|
||||||
windows.CloseHandle(h)
|
|
||||||
return nil, os.NewSyscallError("GetFileInformationByHandle", err)
|
|
||||||
}
|
|
||||||
ino = &inode{
|
|
||||||
handle: h,
|
|
||||||
volume: fi.VolumeSerialNumber,
|
|
||||||
index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
|
|
||||||
}
|
|
||||||
return ino, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must run within the I/O thread.
|
|
||||||
func (m watchMap) get(ino *inode) *watch {
|
|
||||||
if i := m[ino.volume]; i != nil {
|
|
||||||
return i[ino.index]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must run within the I/O thread.
|
|
||||||
func (m watchMap) set(ino *inode, watch *watch) {
|
|
||||||
i := m[ino.volume]
|
|
||||||
if i == nil {
|
|
||||||
i = make(indexMap)
|
|
||||||
m[ino.volume] = i
|
|
||||||
}
|
|
||||||
i[ino.index] = watch
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must run within the I/O thread.
|
|
||||||
func (w *Watcher) addWatch(pathname string, flags uint64) error {
|
|
||||||
dir, err := w.getDir(pathname)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ino, err := w.getIno(dir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.mu.Lock()
|
|
||||||
watchEntry := w.watches.get(ino)
|
|
||||||
w.mu.Unlock()
|
|
||||||
if watchEntry == nil {
|
|
||||||
_, err := windows.CreateIoCompletionPort(ino.handle, w.port, 0, 0)
|
|
||||||
if err != nil {
|
|
||||||
windows.CloseHandle(ino.handle)
|
|
||||||
return os.NewSyscallError("CreateIoCompletionPort", err)
|
|
||||||
}
|
|
||||||
watchEntry = &watch{
|
|
||||||
ino: ino,
|
|
||||||
path: dir,
|
|
||||||
names: make(map[string]uint64),
|
|
||||||
}
|
|
||||||
w.mu.Lock()
|
|
||||||
w.watches.set(ino, watchEntry)
|
|
||||||
w.mu.Unlock()
|
|
||||||
flags |= provisional
|
|
||||||
} else {
|
|
||||||
windows.CloseHandle(ino.handle)
|
|
||||||
}
|
|
||||||
if pathname == dir {
|
|
||||||
watchEntry.mask |= flags
|
|
||||||
} else {
|
|
||||||
watchEntry.names[filepath.Base(pathname)] |= flags
|
|
||||||
}
|
|
||||||
|
|
||||||
err = w.startRead(watchEntry)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if pathname == dir {
|
|
||||||
watchEntry.mask &= ^provisional
|
|
||||||
} else {
|
|
||||||
watchEntry.names[filepath.Base(pathname)] &= ^provisional
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must run within the I/O thread.
|
|
||||||
func (w *Watcher) remWatch(pathname string) error {
|
|
||||||
dir, err := w.getDir(pathname)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ino, err := w.getIno(dir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
w.mu.Lock()
|
|
||||||
watch := w.watches.get(ino)
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
err = windows.CloseHandle(ino.handle)
|
|
||||||
if err != nil {
|
|
||||||
w.sendError(os.NewSyscallError("CloseHandle", err))
|
|
||||||
}
|
|
||||||
if watch == nil {
|
|
||||||
return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname)
|
|
||||||
}
|
|
||||||
if pathname == dir {
|
|
||||||
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
|
||||||
watch.mask = 0
|
|
||||||
} else {
|
|
||||||
name := filepath.Base(pathname)
|
|
||||||
w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED)
|
|
||||||
delete(watch.names, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return w.startRead(watch)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must run within the I/O thread.
|
|
||||||
func (w *Watcher) deleteWatch(watch *watch) {
|
|
||||||
for name, mask := range watch.names {
|
|
||||||
if mask&provisional == 0 {
|
|
||||||
w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
|
|
||||||
}
|
|
||||||
delete(watch.names, name)
|
|
||||||
}
|
|
||||||
if watch.mask != 0 {
|
|
||||||
if watch.mask&provisional == 0 {
|
|
||||||
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
|
||||||
}
|
|
||||||
watch.mask = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must run within the I/O thread.
|
|
||||||
func (w *Watcher) startRead(watch *watch) error {
|
|
||||||
err := windows.CancelIo(watch.ino.handle)
|
|
||||||
if err != nil {
|
|
||||||
w.sendError(os.NewSyscallError("CancelIo", err))
|
|
||||||
w.deleteWatch(watch)
|
|
||||||
}
|
|
||||||
mask := w.toWindowsFlags(watch.mask)
|
|
||||||
for _, m := range watch.names {
|
|
||||||
mask |= w.toWindowsFlags(m)
|
|
||||||
}
|
|
||||||
if mask == 0 {
|
|
||||||
err := windows.CloseHandle(watch.ino.handle)
|
|
||||||
if err != nil {
|
|
||||||
w.sendError(os.NewSyscallError("CloseHandle", err))
|
|
||||||
}
|
|
||||||
w.mu.Lock()
|
|
||||||
delete(w.watches[watch.ino.volume], watch.ino.index)
|
|
||||||
w.mu.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rdErr := windows.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
|
|
||||||
uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
|
|
||||||
if rdErr != nil {
|
|
||||||
err := os.NewSyscallError("ReadDirectoryChanges", rdErr)
|
|
||||||
if rdErr == windows.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
|
|
||||||
// Watched directory was probably removed
|
|
||||||
w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
w.deleteWatch(watch)
|
|
||||||
w.startRead(watch)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// readEvents reads from the I/O completion port, converts the
|
|
||||||
// received events into Event objects and sends them via the Events channel.
|
|
||||||
// Entry point to the I/O thread.
|
|
||||||
func (w *Watcher) readEvents() {
|
|
||||||
var (
|
|
||||||
n uint32
|
|
||||||
key uintptr
|
|
||||||
ov *windows.Overlapped
|
|
||||||
)
|
|
||||||
runtime.LockOSThread()
|
|
||||||
|
|
||||||
for {
|
|
||||||
qErr := windows.GetQueuedCompletionStatus(w.port, &n, &key, &ov, windows.INFINITE)
|
|
||||||
// This error is handled after the watch == nil check below. NOTE: this
|
|
||||||
// seems odd, note sure if it's correct.
|
|
||||||
|
|
||||||
watch := (*watch)(unsafe.Pointer(ov))
|
|
||||||
if watch == nil {
|
|
||||||
select {
|
|
||||||
case ch := <-w.quit:
|
|
||||||
w.mu.Lock()
|
|
||||||
var indexes []indexMap
|
|
||||||
for _, index := range w.watches {
|
|
||||||
indexes = append(indexes, index)
|
|
||||||
}
|
|
||||||
w.mu.Unlock()
|
|
||||||
for _, index := range indexes {
|
|
||||||
for _, watch := range index {
|
|
||||||
w.deleteWatch(watch)
|
|
||||||
w.startRead(watch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err := windows.CloseHandle(w.port)
|
|
||||||
if err != nil {
|
|
||||||
err = os.NewSyscallError("CloseHandle", err)
|
|
||||||
}
|
|
||||||
close(w.Events)
|
|
||||||
close(w.Errors)
|
|
||||||
ch <- err
|
|
||||||
return
|
|
||||||
case in := <-w.input:
|
|
||||||
switch in.op {
|
|
||||||
case opAddWatch:
|
|
||||||
in.reply <- w.addWatch(in.path, uint64(in.flags))
|
|
||||||
case opRemoveWatch:
|
|
||||||
in.reply <- w.remWatch(in.path)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch qErr {
|
|
||||||
case windows.ERROR_MORE_DATA:
|
|
||||||
if watch == nil {
|
|
||||||
w.sendError(errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer"))
|
|
||||||
} else {
|
|
||||||
// The i/o succeeded but the buffer is full.
|
|
||||||
// In theory we should be building up a full packet.
|
|
||||||
// In practice we can get away with just carrying on.
|
|
||||||
n = uint32(unsafe.Sizeof(watch.buf))
|
|
||||||
}
|
|
||||||
case windows.ERROR_ACCESS_DENIED:
|
|
||||||
// Watched directory was probably removed
|
|
||||||
w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
|
|
||||||
w.deleteWatch(watch)
|
|
||||||
w.startRead(watch)
|
|
||||||
continue
|
|
||||||
case windows.ERROR_OPERATION_ABORTED:
|
|
||||||
// CancelIo was called on this handle
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
w.sendError(os.NewSyscallError("GetQueuedCompletionPort", qErr))
|
|
||||||
continue
|
|
||||||
case nil:
|
|
||||||
}
|
|
||||||
|
|
||||||
var offset uint32
|
|
||||||
for {
|
|
||||||
if n == 0 {
|
|
||||||
w.sendError(errors.New("short read in readEvents()"))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Point "raw" to the event in the buffer
|
|
||||||
raw := (*windows.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
|
|
||||||
|
|
||||||
// Create a buf that is the size of the path name
|
|
||||||
size := int(raw.FileNameLength / 2)
|
|
||||||
var buf []uint16
|
|
||||||
// TODO: Use unsafe.Slice in Go 1.17; https://stackoverflow.com/questions/51187973
|
|
||||||
sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
|
|
||||||
sh.Data = uintptr(unsafe.Pointer(&raw.FileName))
|
|
||||||
sh.Len = size
|
|
||||||
sh.Cap = size
|
|
||||||
name := windows.UTF16ToString(buf)
|
|
||||||
fullname := filepath.Join(watch.path, name)
|
|
||||||
|
|
||||||
var mask uint64
|
|
||||||
switch raw.Action {
|
|
||||||
case windows.FILE_ACTION_REMOVED:
|
|
||||||
mask = sysFSDELETESELF
|
|
||||||
case windows.FILE_ACTION_MODIFIED:
|
|
||||||
mask = sysFSMODIFY
|
|
||||||
case windows.FILE_ACTION_RENAMED_OLD_NAME:
|
|
||||||
watch.rename = name
|
|
||||||
case windows.FILE_ACTION_RENAMED_NEW_NAME:
|
|
||||||
// Update saved path of all sub-watches.
|
|
||||||
old := filepath.Join(watch.path, watch.rename)
|
|
||||||
w.mu.Lock()
|
|
||||||
for _, watchMap := range w.watches {
|
|
||||||
for _, ww := range watchMap {
|
|
||||||
if strings.HasPrefix(ww.path, old) {
|
|
||||||
ww.path = filepath.Join(fullname, strings.TrimPrefix(ww.path, old))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.mu.Unlock()
|
|
||||||
|
|
||||||
if watch.names[watch.rename] != 0 {
|
|
||||||
watch.names[name] |= watch.names[watch.rename]
|
|
||||||
delete(watch.names, watch.rename)
|
|
||||||
mask = sysFSMOVESELF
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sendNameEvent := func() {
|
|
||||||
w.sendEvent(fullname, watch.names[name]&mask)
|
|
||||||
}
|
|
||||||
if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME {
|
|
||||||
sendNameEvent()
|
|
||||||
}
|
|
||||||
if raw.Action == windows.FILE_ACTION_REMOVED {
|
|
||||||
w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
|
|
||||||
delete(watch.names, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.sendEvent(fullname, watch.mask&w.toFSnotifyFlags(raw.Action))
|
|
||||||
if raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME {
|
|
||||||
fullname = filepath.Join(watch.path, watch.rename)
|
|
||||||
sendNameEvent()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to the next event in the buffer
|
|
||||||
if raw.NextEntryOffset == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
offset += raw.NextEntryOffset
|
|
||||||
|
|
||||||
// Error!
|
|
||||||
if offset >= n {
|
|
||||||
w.sendError(errors.New(
|
|
||||||
"Windows system assumed buffer larger than it is, events have likely been missed."))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := w.startRead(watch); err != nil {
|
|
||||||
w.sendError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) toWindowsFlags(mask uint64) uint32 {
|
|
||||||
var m uint32
|
|
||||||
if mask&sysFSMODIFY != 0 {
|
|
||||||
m |= windows.FILE_NOTIFY_CHANGE_LAST_WRITE
|
|
||||||
}
|
|
||||||
if mask&sysFSATTRIB != 0 {
|
|
||||||
m |= windows.FILE_NOTIFY_CHANGE_ATTRIBUTES
|
|
||||||
}
|
|
||||||
if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 {
|
|
||||||
m |= windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) toFSnotifyFlags(action uint32) uint64 {
|
|
||||||
switch action {
|
|
||||||
case windows.FILE_ACTION_ADDED:
|
|
||||||
return sysFSCREATE
|
|
||||||
case windows.FILE_ACTION_REMOVED:
|
|
||||||
return sysFSDELETE
|
|
||||||
case windows.FILE_ACTION_MODIFIED:
|
|
||||||
return sysFSMODIFY
|
|
||||||
case windows.FILE_ACTION_RENAMED_OLD_NAME:
|
|
||||||
return sysFSMOVEDFROM
|
|
||||||
case windows.FILE_ACTION_RENAMED_NEW_NAME:
|
|
||||||
return sysFSMOVEDTO
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
38
vendor/github.com/fsnotify/fsnotify/fen.go
generated
vendored
Normal file
38
vendor/github.com/fsnotify/fsnotify/fen.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2010 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 solaris
|
||||||
|
// +build solaris
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Watcher watches a set of files, delivering events to a channel.
|
||||||
|
type Watcher struct {
|
||||||
|
Events chan Event
|
||||||
|
Errors chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||||
|
func NewWatcher() (*Watcher, error) {
|
||||||
|
return nil, errors.New("FEN based watcher not yet supported for fsnotify\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close removes all watches and closes the events channel.
|
||||||
|
func (w *Watcher) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add starts watching the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Add(name string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove stops watching the the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Remove(name string) error {
|
||||||
|
return nil
|
||||||
|
}
|
96
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
96
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
@ -1,37 +1,29 @@
|
|||||||
|
// Copyright 2012 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 !plan9
|
//go:build !plan9
|
||||||
// +build !plan9
|
// +build !plan9
|
||||||
|
|
||||||
// Package fsnotify provides a cross-platform interface for file system
|
// Package fsnotify provides a platform-independent interface for file system notifications.
|
||||||
// notifications.
|
|
||||||
package fsnotify
|
package fsnotify
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Event represents a file system notification.
|
// Event represents a single file system notification.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
// Path to the file or directory.
|
Name string // Relative path to the file or directory.
|
||||||
//
|
Op Op // File operation that triggered the event.
|
||||||
// Paths are relative to the input; for example with Add("dir") the Name
|
|
||||||
// will be set to "dir/file" if you create that file, but if you use
|
|
||||||
// Add("/path/to/dir") it will be "/path/to/dir/file".
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// File operation that triggered the event.
|
|
||||||
//
|
|
||||||
// This is a bitmask and some systems may send multiple operations at once.
|
|
||||||
// Use the Event.Has() method instead of comparing with ==.
|
|
||||||
Op Op
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Op describes a set of file operations.
|
// Op describes a set of file operations.
|
||||||
type Op uint32
|
type Op uint32
|
||||||
|
|
||||||
// The operations fsnotify can trigger; see the documentation on [Watcher] for a
|
// These are the generalized file operations that can trigger a notification.
|
||||||
// full description, and check them with [Event.Has].
|
|
||||||
const (
|
const (
|
||||||
Create Op = 1 << iota
|
Create Op = 1 << iota
|
||||||
Write
|
Write
|
||||||
@ -40,42 +32,38 @@ const (
|
|||||||
Chmod
|
Chmod
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (op Op) String() string {
|
||||||
|
// Use a buffer for efficient string concatenation
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
if op&Create == Create {
|
||||||
|
buffer.WriteString("|CREATE")
|
||||||
|
}
|
||||||
|
if op&Remove == Remove {
|
||||||
|
buffer.WriteString("|REMOVE")
|
||||||
|
}
|
||||||
|
if op&Write == Write {
|
||||||
|
buffer.WriteString("|WRITE")
|
||||||
|
}
|
||||||
|
if op&Rename == Rename {
|
||||||
|
buffer.WriteString("|RENAME")
|
||||||
|
}
|
||||||
|
if op&Chmod == Chmod {
|
||||||
|
buffer.WriteString("|CHMOD")
|
||||||
|
}
|
||||||
|
if buffer.Len() == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return buffer.String()[1:] // Strip leading pipe
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of the event in the form
|
||||||
|
// "file: REMOVE|WRITE|..."
|
||||||
|
func (e Event) String() string {
|
||||||
|
return fmt.Sprintf("%q: %s", e.Name, e.Op.String())
|
||||||
|
}
|
||||||
|
|
||||||
// Common errors that can be reported by a watcher
|
// Common errors that can be reported by a watcher
|
||||||
var (
|
var (
|
||||||
ErrNonExistentWatch = errors.New("can't remove non-existent watcher")
|
ErrEventOverflow = errors.New("fsnotify queue overflow")
|
||||||
ErrEventOverflow = errors.New("fsnotify queue overflow")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (op Op) String() string {
|
|
||||||
var b strings.Builder
|
|
||||||
if op.Has(Create) {
|
|
||||||
b.WriteString("|CREATE")
|
|
||||||
}
|
|
||||||
if op.Has(Remove) {
|
|
||||||
b.WriteString("|REMOVE")
|
|
||||||
}
|
|
||||||
if op.Has(Write) {
|
|
||||||
b.WriteString("|WRITE")
|
|
||||||
}
|
|
||||||
if op.Has(Rename) {
|
|
||||||
b.WriteString("|RENAME")
|
|
||||||
}
|
|
||||||
if op.Has(Chmod) {
|
|
||||||
b.WriteString("|CHMOD")
|
|
||||||
}
|
|
||||||
if b.Len() == 0 {
|
|
||||||
return "[no events]"
|
|
||||||
}
|
|
||||||
return b.String()[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Has reports if this operation has the given operation.
|
|
||||||
func (o Op) Has(h Op) bool { return o&h == h }
|
|
||||||
|
|
||||||
// Has reports if this event has the given operation.
|
|
||||||
func (e Event) Has(op Op) bool { return e.Op.Has(op) }
|
|
||||||
|
|
||||||
// String returns a string representation of the event with their path.
|
|
||||||
func (e Event) String() string {
|
|
||||||
return fmt.Sprintf("%-13s %q", e.Op.String(), e.Name)
|
|
||||||
}
|
|
||||||
|
338
vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
Normal file
338
vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
// Copyright 2010 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 linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Watcher watches a set of files, delivering events to a channel.
|
||||||
|
type Watcher struct {
|
||||||
|
Events chan Event
|
||||||
|
Errors chan error
|
||||||
|
mu sync.Mutex // Map access
|
||||||
|
fd int
|
||||||
|
poller *fdPoller
|
||||||
|
watches map[string]*watch // Map of inotify watches (key: path)
|
||||||
|
paths map[int]string // Map of watched paths (key: watch descriptor)
|
||||||
|
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||||
|
doneResp chan struct{} // Channel to respond to Close
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||||
|
func NewWatcher() (*Watcher, error) {
|
||||||
|
// Create inotify fd
|
||||||
|
fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC)
|
||||||
|
if fd == -1 {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
// Create epoll
|
||||||
|
poller, err := newFdPoller(fd)
|
||||||
|
if err != nil {
|
||||||
|
unix.Close(fd)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
w := &Watcher{
|
||||||
|
fd: fd,
|
||||||
|
poller: poller,
|
||||||
|
watches: make(map[string]*watch),
|
||||||
|
paths: make(map[int]string),
|
||||||
|
Events: make(chan Event),
|
||||||
|
Errors: make(chan error),
|
||||||
|
done: make(chan struct{}),
|
||||||
|
doneResp: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
go w.readEvents()
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watcher) isClosed() bool {
|
||||||
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close removes all watches and closes the events channel.
|
||||||
|
func (w *Watcher) Close() error {
|
||||||
|
if w.isClosed() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send 'close' signal to goroutine, and set the Watcher to closed.
|
||||||
|
close(w.done)
|
||||||
|
|
||||||
|
// Wake up goroutine
|
||||||
|
w.poller.wake()
|
||||||
|
|
||||||
|
// Wait for goroutine to close
|
||||||
|
<-w.doneResp
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add starts watching the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Add(name string) error {
|
||||||
|
name = filepath.Clean(name)
|
||||||
|
if w.isClosed() {
|
||||||
|
return errors.New("inotify instance already closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
|
||||||
|
unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
|
||||||
|
unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
|
||||||
|
|
||||||
|
var flags uint32 = agnosticEvents
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
watchEntry := w.watches[name]
|
||||||
|
if watchEntry != nil {
|
||||||
|
flags |= watchEntry.flags | unix.IN_MASK_ADD
|
||||||
|
}
|
||||||
|
wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
|
||||||
|
if wd == -1 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
|
||||||
|
if watchEntry == nil {
|
||||||
|
w.watches[name] = &watch{wd: uint32(wd), flags: flags}
|
||||||
|
w.paths[wd] = name
|
||||||
|
} else {
|
||||||
|
watchEntry.wd = uint32(wd)
|
||||||
|
watchEntry.flags = flags
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove stops watching the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Remove(name string) error {
|
||||||
|
name = filepath.Clean(name)
|
||||||
|
|
||||||
|
// Fetch the watch.
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
watch, ok := w.watches[name]
|
||||||
|
|
||||||
|
// Remove it from inotify.
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We successfully removed the watch if InotifyRmWatch doesn't return an
|
||||||
|
// error, we need to clean up our internal state to ensure it matches
|
||||||
|
// inotify's kernel state.
|
||||||
|
delete(w.paths, int(watch.wd))
|
||||||
|
delete(w.watches, name)
|
||||||
|
|
||||||
|
// inotify_rm_watch will return EINVAL if the file has been deleted;
|
||||||
|
// the inotify will already have been removed.
|
||||||
|
// watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
|
||||||
|
// by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE
|
||||||
|
// so that EINVAL means that the wd is being rm_watch()ed or its file removed
|
||||||
|
// by another thread and we have not received IN_IGNORE event.
|
||||||
|
success, errno := unix.InotifyRmWatch(w.fd, watch.wd)
|
||||||
|
if success == -1 {
|
||||||
|
// TODO: Perhaps it's not helpful to return an error here in every case.
|
||||||
|
// the only two possible errors are:
|
||||||
|
// EBADF, which happens when w.fd is not a valid file descriptor of any kind.
|
||||||
|
// EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
|
||||||
|
// Watch descriptors are invalidated when they are removed explicitly or implicitly;
|
||||||
|
// explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type watch struct {
|
||||||
|
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||||
|
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// readEvents reads from the inotify file descriptor, converts the
|
||||||
|
// received events into Event objects and sends them via the Events channel
|
||||||
|
func (w *Watcher) readEvents() {
|
||||||
|
var (
|
||||||
|
buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
|
||||||
|
n int // Number of bytes read with read()
|
||||||
|
errno error // Syscall errno
|
||||||
|
ok bool // For poller.wait
|
||||||
|
)
|
||||||
|
|
||||||
|
defer close(w.doneResp)
|
||||||
|
defer close(w.Errors)
|
||||||
|
defer close(w.Events)
|
||||||
|
defer unix.Close(w.fd)
|
||||||
|
defer w.poller.close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
// See if we have been closed.
|
||||||
|
if w.isClosed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, errno = w.poller.wait()
|
||||||
|
if errno != nil {
|
||||||
|
select {
|
||||||
|
case w.Errors <- errno:
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
n, errno = unix.Read(w.fd, buf[:])
|
||||||
|
// If a signal interrupted execution, see if we've been asked to close, and try again.
|
||||||
|
// http://man7.org/linux/man-pages/man7/signal.7.html :
|
||||||
|
// "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
|
||||||
|
if errno == unix.EINTR {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// unix.Read might have been woken up by Close. If so, we're done.
|
||||||
|
if w.isClosed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if n < unix.SizeofInotifyEvent {
|
||||||
|
var err error
|
||||||
|
if n == 0 {
|
||||||
|
// If EOF is received. This should really never happen.
|
||||||
|
err = io.EOF
|
||||||
|
} else if n < 0 {
|
||||||
|
// If an error occurred while reading.
|
||||||
|
err = errno
|
||||||
|
} else {
|
||||||
|
// Read was too short.
|
||||||
|
err = errors.New("notify: short read in readEvents()")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case w.Errors <- err:
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset uint32
|
||||||
|
// We don't know how many events we just read into the buffer
|
||||||
|
// While the offset points to at least one whole event...
|
||||||
|
for offset <= uint32(n-unix.SizeofInotifyEvent) {
|
||||||
|
// Point "raw" to the event in the buffer
|
||||||
|
raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
|
||||||
|
|
||||||
|
mask := uint32(raw.Mask)
|
||||||
|
nameLen := uint32(raw.Len)
|
||||||
|
|
||||||
|
if mask&unix.IN_Q_OVERFLOW != 0 {
|
||||||
|
select {
|
||||||
|
case w.Errors <- ErrEventOverflow:
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the event happened to the watched directory or the watched file, the kernel
|
||||||
|
// doesn't append the filename to the event, but we would like to always fill the
|
||||||
|
// the "Name" field with a valid filename. We retrieve the path of the watch from
|
||||||
|
// the "paths" map.
|
||||||
|
w.mu.Lock()
|
||||||
|
name, ok := w.paths[int(raw.Wd)]
|
||||||
|
// IN_DELETE_SELF occurs when the file/directory being watched is removed.
|
||||||
|
// This is a sign to clean up the maps, otherwise we are no longer in sync
|
||||||
|
// with the inotify kernel state which has already deleted the watch
|
||||||
|
// automatically.
|
||||||
|
if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
|
||||||
|
delete(w.paths, int(raw.Wd))
|
||||||
|
delete(w.watches, name)
|
||||||
|
}
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
if nameLen > 0 {
|
||||||
|
// Point "bytes" at the first byte of the filename
|
||||||
|
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]
|
||||||
|
// The filename is padded with NULL bytes. TrimRight() gets rid of those.
|
||||||
|
name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
|
||||||
|
}
|
||||||
|
|
||||||
|
event := newEvent(name, mask)
|
||||||
|
|
||||||
|
// Send the events that are not ignored on the events channel
|
||||||
|
if !event.ignoreLinux(mask) {
|
||||||
|
select {
|
||||||
|
case w.Events <- event:
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next event in the buffer
|
||||||
|
offset += unix.SizeofInotifyEvent + nameLen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Certain types of events can be "ignored" and not sent over the Events
|
||||||
|
// channel. Such as events marked ignore by the kernel, or MODIFY events
|
||||||
|
// against files that do not exist.
|
||||||
|
func (e *Event) ignoreLinux(mask uint32) bool {
|
||||||
|
// Ignore anything the inotify API says to ignore
|
||||||
|
if mask&unix.IN_IGNORED == unix.IN_IGNORED {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the event is not a DELETE or RENAME, the file must exist.
|
||||||
|
// Otherwise the event is ignored.
|
||||||
|
// *Note*: this was put in place because it was seen that a MODIFY
|
||||||
|
// event was sent after the DELETE. This ignores that MODIFY and
|
||||||
|
// assumes a DELETE will come or has come if the file doesn't exist.
|
||||||
|
if !(e.Op&Remove == Remove || e.Op&Rename == Rename) {
|
||||||
|
_, statErr := os.Lstat(e.Name)
|
||||||
|
return os.IsNotExist(statErr)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// newEvent returns an platform-independent Event based on an inotify mask.
|
||||||
|
func newEvent(name string, mask uint32) Event {
|
||||||
|
e := Event{Name: name}
|
||||||
|
if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
|
||||||
|
e.Op |= Create
|
||||||
|
}
|
||||||
|
if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE {
|
||||||
|
e.Op |= Remove
|
||||||
|
}
|
||||||
|
if mask&unix.IN_MODIFY == unix.IN_MODIFY {
|
||||||
|
e.Op |= Write
|
||||||
|
}
|
||||||
|
if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
|
||||||
|
e.Op |= Rename
|
||||||
|
}
|
||||||
|
if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
|
||||||
|
e.Op |= Chmod
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
188
vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
Normal file
188
vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
// Copyright 2015 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 linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fdPoller struct {
|
||||||
|
fd int // File descriptor (as returned by the inotify_init() syscall)
|
||||||
|
epfd int // Epoll file descriptor
|
||||||
|
pipe [2]int // Pipe for waking up
|
||||||
|
}
|
||||||
|
|
||||||
|
func emptyPoller(fd int) *fdPoller {
|
||||||
|
poller := new(fdPoller)
|
||||||
|
poller.fd = fd
|
||||||
|
poller.epfd = -1
|
||||||
|
poller.pipe[0] = -1
|
||||||
|
poller.pipe[1] = -1
|
||||||
|
return poller
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new inotify poller.
|
||||||
|
// This creates an inotify handler, and an epoll handler.
|
||||||
|
func newFdPoller(fd int) (*fdPoller, error) {
|
||||||
|
var errno error
|
||||||
|
poller := emptyPoller(fd)
|
||||||
|
defer func() {
|
||||||
|
if errno != nil {
|
||||||
|
poller.close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
poller.fd = fd
|
||||||
|
|
||||||
|
// Create epoll fd
|
||||||
|
poller.epfd, errno = unix.EpollCreate1(unix.EPOLL_CLOEXEC)
|
||||||
|
if poller.epfd == -1 {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
// Create pipe; pipe[0] is the read end, pipe[1] the write end.
|
||||||
|
errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK|unix.O_CLOEXEC)
|
||||||
|
if errno != nil {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register inotify fd with epoll
|
||||||
|
event := unix.EpollEvent{
|
||||||
|
Fd: int32(poller.fd),
|
||||||
|
Events: unix.EPOLLIN,
|
||||||
|
}
|
||||||
|
errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event)
|
||||||
|
if errno != nil {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register pipe fd with epoll
|
||||||
|
event = unix.EpollEvent{
|
||||||
|
Fd: int32(poller.pipe[0]),
|
||||||
|
Events: unix.EPOLLIN,
|
||||||
|
}
|
||||||
|
errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event)
|
||||||
|
if errno != nil {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
|
||||||
|
return poller, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait using epoll.
|
||||||
|
// Returns true if something is ready to be read,
|
||||||
|
// false if there is not.
|
||||||
|
func (poller *fdPoller) wait() (bool, error) {
|
||||||
|
// 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
|
||||||
|
// I don't know whether epoll_wait returns the number of events returned,
|
||||||
|
// or the total number of events ready.
|
||||||
|
// I decided to catch both by making the buffer one larger than the maximum.
|
||||||
|
events := make([]unix.EpollEvent, 7)
|
||||||
|
for {
|
||||||
|
n, errno := unix.EpollWait(poller.epfd, events, -1)
|
||||||
|
if n == -1 {
|
||||||
|
if errno == unix.EINTR {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return false, errno
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
// If there are no events, try again.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if n > 6 {
|
||||||
|
// This should never happen. More events were returned than should be possible.
|
||||||
|
return false, errors.New("epoll_wait returned more events than I know what to do with")
|
||||||
|
}
|
||||||
|
ready := events[:n]
|
||||||
|
epollhup := false
|
||||||
|
epollerr := false
|
||||||
|
epollin := false
|
||||||
|
for _, event := range ready {
|
||||||
|
if event.Fd == int32(poller.fd) {
|
||||||
|
if event.Events&unix.EPOLLHUP != 0 {
|
||||||
|
// This should not happen, but if it does, treat it as a wakeup.
|
||||||
|
epollhup = true
|
||||||
|
}
|
||||||
|
if event.Events&unix.EPOLLERR != 0 {
|
||||||
|
// If an error is waiting on the file descriptor, we should pretend
|
||||||
|
// something is ready to read, and let unix.Read pick up the error.
|
||||||
|
epollerr = true
|
||||||
|
}
|
||||||
|
if event.Events&unix.EPOLLIN != 0 {
|
||||||
|
// There is data to read.
|
||||||
|
epollin = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if event.Fd == int32(poller.pipe[0]) {
|
||||||
|
if event.Events&unix.EPOLLHUP != 0 {
|
||||||
|
// Write pipe descriptor was closed, by us. This means we're closing down the
|
||||||
|
// watcher, and we should wake up.
|
||||||
|
}
|
||||||
|
if event.Events&unix.EPOLLERR != 0 {
|
||||||
|
// If an error is waiting on the pipe file descriptor.
|
||||||
|
// This is an absolute mystery, and should never ever happen.
|
||||||
|
return false, errors.New("Error on the pipe descriptor.")
|
||||||
|
}
|
||||||
|
if event.Events&unix.EPOLLIN != 0 {
|
||||||
|
// This is a regular wakeup, so we have to clear the buffer.
|
||||||
|
err := poller.clearWake()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if epollhup || epollerr || epollin {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the write end of the poller.
|
||||||
|
func (poller *fdPoller) wake() error {
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
n, errno := unix.Write(poller.pipe[1], buf)
|
||||||
|
if n == -1 {
|
||||||
|
if errno == unix.EAGAIN {
|
||||||
|
// Buffer is full, poller will wake.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (poller *fdPoller) clearWake() error {
|
||||||
|
// You have to be woken up a LOT in order to get to 100!
|
||||||
|
buf := make([]byte, 100)
|
||||||
|
n, errno := unix.Read(poller.pipe[0], buf)
|
||||||
|
if n == -1 {
|
||||||
|
if errno == unix.EAGAIN {
|
||||||
|
// Buffer is empty, someone else cleared our wake.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close all poller file descriptors, but not the one passed to it.
|
||||||
|
func (poller *fdPoller) close() {
|
||||||
|
if poller.pipe[1] != -1 {
|
||||||
|
unix.Close(poller.pipe[1])
|
||||||
|
}
|
||||||
|
if poller.pipe[0] != -1 {
|
||||||
|
unix.Close(poller.pipe[0])
|
||||||
|
}
|
||||||
|
if poller.epfd != -1 {
|
||||||
|
unix.Close(poller.epfd)
|
||||||
|
}
|
||||||
|
}
|
522
vendor/github.com/fsnotify/fsnotify/kqueue.go
generated
vendored
Normal file
522
vendor/github.com/fsnotify/fsnotify/kqueue.go
generated
vendored
Normal file
@ -0,0 +1,522 @@
|
|||||||
|
// Copyright 2010 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 freebsd || openbsd || netbsd || dragonfly || darwin
|
||||||
|
// +build freebsd openbsd netbsd dragonfly darwin
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Watcher watches a set of files, delivering events to a channel.
|
||||||
|
type Watcher struct {
|
||||||
|
Events chan Event
|
||||||
|
Errors chan error
|
||||||
|
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||||
|
|
||||||
|
kq int // File descriptor (as returned by the kqueue() syscall).
|
||||||
|
|
||||||
|
mu sync.Mutex // Protects access to watcher data
|
||||||
|
watches map[string]int // Map of watched file descriptors (key: path).
|
||||||
|
externalWatches map[string]bool // Map of watches added by user of the library.
|
||||||
|
dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue.
|
||||||
|
paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events.
|
||||||
|
fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events).
|
||||||
|
isClosed bool // Set to true when Close() is first called
|
||||||
|
}
|
||||||
|
|
||||||
|
type pathInfo struct {
|
||||||
|
name string
|
||||||
|
isDir bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||||
|
func NewWatcher() (*Watcher, error) {
|
||||||
|
kq, err := kqueue()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &Watcher{
|
||||||
|
kq: kq,
|
||||||
|
watches: make(map[string]int),
|
||||||
|
dirFlags: make(map[string]uint32),
|
||||||
|
paths: make(map[int]pathInfo),
|
||||||
|
fileExists: make(map[string]bool),
|
||||||
|
externalWatches: make(map[string]bool),
|
||||||
|
Events: make(chan Event),
|
||||||
|
Errors: make(chan error),
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
go w.readEvents()
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close removes all watches and closes the events channel.
|
||||||
|
func (w *Watcher) Close() error {
|
||||||
|
w.mu.Lock()
|
||||||
|
if w.isClosed {
|
||||||
|
w.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
w.isClosed = true
|
||||||
|
|
||||||
|
// copy paths to remove while locked
|
||||||
|
var pathsToRemove = make([]string, 0, len(w.watches))
|
||||||
|
for name := range w.watches {
|
||||||
|
pathsToRemove = append(pathsToRemove, name)
|
||||||
|
}
|
||||||
|
w.mu.Unlock()
|
||||||
|
// unlock before calling Remove, which also locks
|
||||||
|
|
||||||
|
for _, name := range pathsToRemove {
|
||||||
|
w.Remove(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a "quit" message to the reader goroutine
|
||||||
|
close(w.done)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add starts watching the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Add(name string) error {
|
||||||
|
w.mu.Lock()
|
||||||
|
w.externalWatches[name] = true
|
||||||
|
w.mu.Unlock()
|
||||||
|
_, err := w.addWatch(name, noteAllEvents)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove stops watching the the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Remove(name string) error {
|
||||||
|
name = filepath.Clean(name)
|
||||||
|
w.mu.Lock()
|
||||||
|
watchfd, ok := w.watches[name]
|
||||||
|
w.mu.Unlock()
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("can't remove non-existent kevent watch for: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
const registerRemove = unix.EV_DELETE
|
||||||
|
if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
unix.Close(watchfd)
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
isDir := w.paths[watchfd].isDir
|
||||||
|
delete(w.watches, name)
|
||||||
|
delete(w.paths, watchfd)
|
||||||
|
delete(w.dirFlags, name)
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
// Find all watched paths that are in this directory that are not external.
|
||||||
|
if isDir {
|
||||||
|
var pathsToRemove []string
|
||||||
|
w.mu.Lock()
|
||||||
|
for _, path := range w.paths {
|
||||||
|
wdir, _ := filepath.Split(path.name)
|
||||||
|
if filepath.Clean(wdir) == name {
|
||||||
|
if !w.externalWatches[path.name] {
|
||||||
|
pathsToRemove = append(pathsToRemove, path.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.mu.Unlock()
|
||||||
|
for _, name := range pathsToRemove {
|
||||||
|
// Since these are internal, not much sense in propagating error
|
||||||
|
// to the user, as that will just confuse them with an error about
|
||||||
|
// a path they did not explicitly watch themselves.
|
||||||
|
w.Remove(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
|
||||||
|
const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME
|
||||||
|
|
||||||
|
// keventWaitTime to block on each read from kevent
|
||||||
|
var keventWaitTime = durationToTimespec(100 * time.Millisecond)
|
||||||
|
|
||||||
|
// addWatch adds name to the watched file set.
|
||||||
|
// The flags are interpreted as described in kevent(2).
|
||||||
|
// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks.
|
||||||
|
func (w *Watcher) addWatch(name string, flags uint32) (string, error) {
|
||||||
|
var isDir bool
|
||||||
|
// Make ./name and name equivalent
|
||||||
|
name = filepath.Clean(name)
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
if w.isClosed {
|
||||||
|
w.mu.Unlock()
|
||||||
|
return "", errors.New("kevent instance already closed")
|
||||||
|
}
|
||||||
|
watchfd, alreadyWatching := w.watches[name]
|
||||||
|
// We already have a watch, but we can still override flags.
|
||||||
|
if alreadyWatching {
|
||||||
|
isDir = w.paths[watchfd].isDir
|
||||||
|
}
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
if !alreadyWatching {
|
||||||
|
fi, err := os.Lstat(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't watch sockets.
|
||||||
|
if fi.Mode()&os.ModeSocket == os.ModeSocket {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't watch named pipes.
|
||||||
|
if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Follow Symlinks
|
||||||
|
// Unfortunately, Linux can add bogus symlinks to watch list without
|
||||||
|
// issue, and Windows can't do symlinks period (AFAIK). To maintain
|
||||||
|
// consistency, we will act like everything is fine. There will simply
|
||||||
|
// be no file events for broken symlinks.
|
||||||
|
// Hence the returns of nil on errors.
|
||||||
|
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||||
|
name, err = filepath.EvalSymlinks(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
_, alreadyWatching = w.watches[name]
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
if alreadyWatching {
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err = os.Lstat(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watchfd, err = unix.Open(name, openMode, 0700)
|
||||||
|
if watchfd == -1 {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
isDir = fi.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE
|
||||||
|
if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil {
|
||||||
|
unix.Close(watchfd)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !alreadyWatching {
|
||||||
|
w.mu.Lock()
|
||||||
|
w.watches[name] = watchfd
|
||||||
|
w.paths[watchfd] = pathInfo{name: name, isDir: isDir}
|
||||||
|
w.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if isDir {
|
||||||
|
// Watch the directory if it has not been watched before,
|
||||||
|
// or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles)
|
||||||
|
w.mu.Lock()
|
||||||
|
|
||||||
|
watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE &&
|
||||||
|
(!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE)
|
||||||
|
// Store flags so this watch can be updated later
|
||||||
|
w.dirFlags[name] = flags
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
if watchDir {
|
||||||
|
if err := w.watchDirectoryFiles(name); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readEvents reads from kqueue and converts the received kevents into
|
||||||
|
// Event values that it sends down the Events channel.
|
||||||
|
func (w *Watcher) readEvents() {
|
||||||
|
eventBuffer := make([]unix.Kevent_t, 10)
|
||||||
|
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
// See if there is a message on the "done" channel
|
||||||
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
break loop
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get new events
|
||||||
|
kevents, err := read(w.kq, eventBuffer, &keventWaitTime)
|
||||||
|
// EINTR is okay, the syscall was interrupted before timeout expired.
|
||||||
|
if err != nil && err != unix.EINTR {
|
||||||
|
select {
|
||||||
|
case w.Errors <- err:
|
||||||
|
case <-w.done:
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the events we received to the Events channel
|
||||||
|
for len(kevents) > 0 {
|
||||||
|
kevent := &kevents[0]
|
||||||
|
watchfd := int(kevent.Ident)
|
||||||
|
mask := uint32(kevent.Fflags)
|
||||||
|
w.mu.Lock()
|
||||||
|
path := w.paths[watchfd]
|
||||||
|
w.mu.Unlock()
|
||||||
|
event := newEvent(path.name, mask)
|
||||||
|
|
||||||
|
if path.isDir && !(event.Op&Remove == Remove) {
|
||||||
|
// Double check to make sure the directory exists. This can happen when
|
||||||
|
// we do a rm -fr on a recursively watched folders and we receive a
|
||||||
|
// modification event first but the folder has been deleted and later
|
||||||
|
// receive the delete event
|
||||||
|
if _, err := os.Lstat(event.Name); os.IsNotExist(err) {
|
||||||
|
// mark is as delete event
|
||||||
|
event.Op |= Remove
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Op&Rename == Rename || event.Op&Remove == Remove {
|
||||||
|
w.Remove(event.Name)
|
||||||
|
w.mu.Lock()
|
||||||
|
delete(w.fileExists, event.Name)
|
||||||
|
w.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) {
|
||||||
|
w.sendDirectoryChangeEvents(event.Name)
|
||||||
|
} else {
|
||||||
|
// Send the event on the Events channel.
|
||||||
|
select {
|
||||||
|
case w.Events <- event:
|
||||||
|
case <-w.done:
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Op&Remove == Remove {
|
||||||
|
// Look for a file that may have overwritten this.
|
||||||
|
// For example, mv f1 f2 will delete f2, then create f2.
|
||||||
|
if path.isDir {
|
||||||
|
fileDir := filepath.Clean(event.Name)
|
||||||
|
w.mu.Lock()
|
||||||
|
_, found := w.watches[fileDir]
|
||||||
|
w.mu.Unlock()
|
||||||
|
if found {
|
||||||
|
// make sure the directory exists before we watch for changes. When we
|
||||||
|
// do a recursive watch and perform rm -fr, the parent directory might
|
||||||
|
// have gone missing, ignore the missing directory and let the
|
||||||
|
// upcoming delete event remove the watch from the parent directory.
|
||||||
|
if _, err := os.Lstat(fileDir); err == nil {
|
||||||
|
w.sendDirectoryChangeEvents(fileDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filePath := filepath.Clean(event.Name)
|
||||||
|
if fileInfo, err := os.Lstat(filePath); err == nil {
|
||||||
|
w.sendFileCreatedEventIfNew(filePath, fileInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to next event
|
||||||
|
kevents = kevents[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
err := unix.Close(w.kq)
|
||||||
|
if err != nil {
|
||||||
|
// only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors.
|
||||||
|
select {
|
||||||
|
case w.Errors <- err:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(w.Events)
|
||||||
|
close(w.Errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newEvent returns an platform-independent Event based on kqueue Fflags.
|
||||||
|
func newEvent(name string, mask uint32) Event {
|
||||||
|
e := Event{Name: name}
|
||||||
|
if mask&unix.NOTE_DELETE == unix.NOTE_DELETE {
|
||||||
|
e.Op |= Remove
|
||||||
|
}
|
||||||
|
if mask&unix.NOTE_WRITE == unix.NOTE_WRITE {
|
||||||
|
e.Op |= Write
|
||||||
|
}
|
||||||
|
if mask&unix.NOTE_RENAME == unix.NOTE_RENAME {
|
||||||
|
e.Op |= Rename
|
||||||
|
}
|
||||||
|
if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB {
|
||||||
|
e.Op |= Chmod
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCreateEvent(name string) Event {
|
||||||
|
return Event{Name: name, Op: Create}
|
||||||
|
}
|
||||||
|
|
||||||
|
// watchDirectoryFiles to mimic inotify when adding a watch on a directory
|
||||||
|
func (w *Watcher) watchDirectoryFiles(dirPath string) error {
|
||||||
|
// Get all files
|
||||||
|
files, err := ioutil.ReadDir(dirPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fileInfo := range files {
|
||||||
|
filePath := filepath.Join(dirPath, fileInfo.Name())
|
||||||
|
filePath, err = w.internalWatch(filePath, fileInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
w.fileExists[filePath] = true
|
||||||
|
w.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendDirectoryEvents searches the directory for newly created files
|
||||||
|
// and sends them over the event channel. This functionality is to have
|
||||||
|
// the BSD version of fsnotify match Linux inotify which provides a
|
||||||
|
// create event for files created in a watched directory.
|
||||||
|
func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
|
||||||
|
// Get all files
|
||||||
|
files, err := ioutil.ReadDir(dirPath)
|
||||||
|
if err != nil {
|
||||||
|
select {
|
||||||
|
case w.Errors <- err:
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for new files
|
||||||
|
for _, fileInfo := range files {
|
||||||
|
filePath := filepath.Join(dirPath, fileInfo.Name())
|
||||||
|
err := w.sendFileCreatedEventIfNew(filePath, fileInfo)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendFileCreatedEvent sends a create event if the file isn't already being tracked.
|
||||||
|
func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) {
|
||||||
|
w.mu.Lock()
|
||||||
|
_, doesExist := w.fileExists[filePath]
|
||||||
|
w.mu.Unlock()
|
||||||
|
if !doesExist {
|
||||||
|
// Send create event
|
||||||
|
select {
|
||||||
|
case w.Events <- newCreateEvent(filePath):
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// like watchDirectoryFiles (but without doing another ReadDir)
|
||||||
|
filePath, err = w.internalWatch(filePath, fileInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
w.fileExists[filePath] = true
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) {
|
||||||
|
if fileInfo.IsDir() {
|
||||||
|
// mimic Linux providing delete events for subdirectories
|
||||||
|
// but preserve the flags used if currently watching subdirectory
|
||||||
|
w.mu.Lock()
|
||||||
|
flags := w.dirFlags[name]
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
flags |= unix.NOTE_DELETE | unix.NOTE_RENAME
|
||||||
|
return w.addWatch(name, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// watch file to mimic Linux inotify
|
||||||
|
return w.addWatch(name, noteAllEvents)
|
||||||
|
}
|
||||||
|
|
||||||
|
// kqueue creates a new kernel event queue and returns a descriptor.
|
||||||
|
func kqueue() (kq int, err error) {
|
||||||
|
kq, err = unix.Kqueue()
|
||||||
|
if kq == -1 {
|
||||||
|
return kq, err
|
||||||
|
}
|
||||||
|
return kq, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// register events with the queue
|
||||||
|
func register(kq int, fds []int, flags int, fflags uint32) error {
|
||||||
|
changes := make([]unix.Kevent_t, len(fds))
|
||||||
|
|
||||||
|
for i, fd := range fds {
|
||||||
|
// SetKevent converts int to the platform-specific types:
|
||||||
|
unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags)
|
||||||
|
changes[i].Fflags = fflags
|
||||||
|
}
|
||||||
|
|
||||||
|
// register the events
|
||||||
|
success, err := unix.Kevent(kq, changes, nil, nil)
|
||||||
|
if success == -1 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// read retrieves pending events, or waits until an event occurs.
|
||||||
|
// A timeout of nil blocks indefinitely, while 0 polls the queue.
|
||||||
|
func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) {
|
||||||
|
n, err := unix.Kevent(kq, nil, events, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return events[0:n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// durationToTimespec prepares a timeout value
|
||||||
|
func durationToTimespec(d time.Duration) unix.Timespec {
|
||||||
|
return unix.NsecToTimespec(d.Nanoseconds())
|
||||||
|
}
|
208
vendor/github.com/fsnotify/fsnotify/mkdoc.zsh
generated
vendored
208
vendor/github.com/fsnotify/fsnotify/mkdoc.zsh
generated
vendored
@ -1,208 +0,0 @@
|
|||||||
#!/usr/bin/env zsh
|
|
||||||
[ "${ZSH_VERSION:-}" = "" ] && echo >&2 "Only works with zsh" && exit 1
|
|
||||||
setopt err_exit no_unset pipefail extended_glob
|
|
||||||
|
|
||||||
# Simple script to update the godoc comments on all watchers. Probably took me
|
|
||||||
# more time to write this than doing it manually, but ah well 🙃
|
|
||||||
|
|
||||||
watcher=$(<<EOF
|
|
||||||
// Watcher watches a set of paths, delivering events on a channel.
|
|
||||||
//
|
|
||||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
|
||||||
// value).
|
|
||||||
//
|
|
||||||
// # Linux notes
|
|
||||||
//
|
|
||||||
// When a file is removed a Remove event won't be emitted until all file
|
|
||||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
|
||||||
//
|
|
||||||
// fp := os.Open("file")
|
|
||||||
// os.Remove("file") // Triggers Chmod
|
|
||||||
// fp.Close() // Triggers Remove
|
|
||||||
//
|
|
||||||
// This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
//
|
|
||||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
|
||||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
|
||||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
|
||||||
// create is an "instance", and every path you add is a "watch".
|
|
||||||
//
|
|
||||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
|
||||||
// /proc/sys/fs/inotify/max_user_instances
|
|
||||||
//
|
|
||||||
// To increase them you can use sysctl or write the value to the /proc file:
|
|
||||||
//
|
|
||||||
// # Default values on Linux 5.18
|
|
||||||
// sysctl fs.inotify.max_user_watches=124983
|
|
||||||
// sysctl fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
|
||||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
|
||||||
// your distro's documentation):
|
|
||||||
//
|
|
||||||
// fs.inotify.max_user_watches=124983
|
|
||||||
// fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
// files" error.
|
|
||||||
//
|
|
||||||
// # kqueue notes (macOS, BSD)
|
|
||||||
//
|
|
||||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
// so if you're watching a directory with five files then that's six file
|
|
||||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
// these platforms.
|
|
||||||
//
|
|
||||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
|
||||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
|
||||||
// systems.
|
|
||||||
//
|
|
||||||
// # macOS notes
|
|
||||||
//
|
|
||||||
// Spotlight indexing on macOS can result in multiple events (see [#15]). A
|
|
||||||
// temporary workaround is to add your folder(s) to the "Spotlight Privacy
|
|
||||||
// Settings" until we have a native FSEvents implementation (see [#11]).
|
|
||||||
//
|
|
||||||
// [#11]: https://github.com/fsnotify/fsnotify/issues/11
|
|
||||||
// [#15]: https://github.com/fsnotify/fsnotify/issues/15
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
new=$(<<EOF
|
|
||||||
// NewWatcher creates a new Watcher.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
add=$(<<EOF
|
|
||||||
// Add starts monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// A path can only be watched once; attempting to watch it more than once will
|
|
||||||
// return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// added. A watch will be automatically removed if the path is deleted.
|
|
||||||
//
|
|
||||||
// A path will remain watched if it gets renamed to somewhere else on the same
|
|
||||||
// filesystem, but the monitor will get removed if the path gets deleted and
|
|
||||||
// re-created, or if it's moved to a different filesystem.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many tools update files atomically. Instead of "just" writing
|
|
||||||
// to the file a temporary file will be written to first, and if successful the
|
|
||||||
// temporary file is moved to to destination removing the original, or some
|
|
||||||
// variant thereof. The watcher on the original file is now lost, as it no
|
|
||||||
// longer exists.
|
|
||||||
//
|
|
||||||
// Instead, watch the parent directory and use Event.Name to filter out files
|
|
||||||
// you're not interested in. There is an example of this in [cmd/fsnotify/file.go].
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
remove=$(<<EOF
|
|
||||||
// Remove stops monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
close=$(<<EOF
|
|
||||||
// Close removes all watches and closes the events channel.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
watchlist=$(<<EOF
|
|
||||||
// WatchList returns all paths added with [Add] (and are not yet removed).
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
events=$(<<EOF
|
|
||||||
// Events sends the filesystem change events.
|
|
||||||
//
|
|
||||||
// fsnotify can send the following events; a "path" here can refer to a
|
|
||||||
// file, directory, symbolic link, or special file like a FIFO.
|
|
||||||
//
|
|
||||||
// fsnotify.Create A new path was created; this may be followed by one
|
|
||||||
// or more Write events if data also gets written to a
|
|
||||||
// file.
|
|
||||||
//
|
|
||||||
// fsnotify.Remove A path was removed.
|
|
||||||
//
|
|
||||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
|
||||||
// old path as Event.Name, and a Create event will be
|
|
||||||
// sent with the new name. Renames are only sent for
|
|
||||||
// paths that are currently watched; e.g. moving an
|
|
||||||
// unmonitored file into a monitored directory will
|
|
||||||
// show up as just a Create. Similarly, renaming a file
|
|
||||||
// to outside a monitored directory will show up as
|
|
||||||
// only a Rename.
|
|
||||||
//
|
|
||||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
|
||||||
// also trigger a Write. A single "write action"
|
|
||||||
// initiated by the user may show up as one or multiple
|
|
||||||
// writes, depending on when the system syncs things to
|
|
||||||
// disk. For example when compiling a large Go program
|
|
||||||
// you may get hundreds of Write events, so you
|
|
||||||
// probably want to wait until you've stopped receiving
|
|
||||||
// them (see the dedup example in cmd/fsnotify).
|
|
||||||
//
|
|
||||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
|
||||||
// when a file is removed (or more accurately, when a
|
|
||||||
// link to an inode is removed). On kqueue it's sent
|
|
||||||
// and on kqueue when a file is truncated. On Windows
|
|
||||||
// it's never sent.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
errors=$(<<EOF
|
|
||||||
// Errors sends any errors.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
set-cmt() {
|
|
||||||
local pat=$1
|
|
||||||
local cmt=$2
|
|
||||||
|
|
||||||
IFS=$'\n' local files=($(grep -n $pat backend_*~*_test.go))
|
|
||||||
for f in $files; do
|
|
||||||
IFS=':' local fields=($=f)
|
|
||||||
local file=$fields[1]
|
|
||||||
local end=$(( $fields[2] - 1 ))
|
|
||||||
|
|
||||||
# Find start of comment.
|
|
||||||
local start=0
|
|
||||||
IFS=$'\n' local lines=($(head -n$end $file))
|
|
||||||
for (( i = 1; i <= $#lines; i++ )); do
|
|
||||||
local line=$lines[-$i]
|
|
||||||
if ! grep -q '^[[:space:]]*//' <<<$line; then
|
|
||||||
start=$(( end - (i - 2) ))
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
head -n $(( start - 1 )) $file >/tmp/x
|
|
||||||
print -r -- $cmt >>/tmp/x
|
|
||||||
tail -n+$(( end + 1 )) $file >>/tmp/x
|
|
||||||
mv /tmp/x $file
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
set-cmt '^type Watcher struct ' $watcher
|
|
||||||
set-cmt '^func NewWatcher(' $new
|
|
||||||
set-cmt '^func (w \*Watcher) Add(' $add
|
|
||||||
set-cmt '^func (w \*Watcher) Remove(' $remove
|
|
||||||
set-cmt '^func (w \*Watcher) Close(' $close
|
|
||||||
set-cmt '^func (w \*Watcher) WatchList(' $watchlist
|
|
||||||
set-cmt '^[[:space:]]*Events *chan Event$' $events
|
|
||||||
set-cmt '^[[:space:]]*Errors *chan error$' $errors
|
|
@ -1,3 +1,7 @@
|
|||||||
|
// Copyright 2013 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 freebsd || openbsd || netbsd || dragonfly
|
//go:build freebsd || openbsd || netbsd || dragonfly
|
||||||
// +build freebsd openbsd netbsd dragonfly
|
// +build freebsd openbsd netbsd dragonfly
|
||||||
|
|
@ -1,3 +1,7 @@
|
|||||||
|
// Copyright 2013 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
|
//go:build darwin
|
||||||
// +build darwin
|
// +build darwin
|
||||||
|
|
562
vendor/github.com/fsnotify/fsnotify/windows.go
generated
vendored
Normal file
562
vendor/github.com/fsnotify/fsnotify/windows.go
generated
vendored
Normal file
@ -0,0 +1,562 @@
|
|||||||
|
// Copyright 2011 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 windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Watcher watches a set of files, delivering events to a channel.
|
||||||
|
type Watcher struct {
|
||||||
|
Events chan Event
|
||||||
|
Errors chan error
|
||||||
|
isClosed bool // Set to true when Close() is first called
|
||||||
|
mu sync.Mutex // Map access
|
||||||
|
port syscall.Handle // Handle to completion port
|
||||||
|
watches watchMap // Map of watches (key: i-number)
|
||||||
|
input chan *input // Inputs to the reader are sent on this channel
|
||||||
|
quit chan chan<- error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||||
|
func NewWatcher() (*Watcher, error) {
|
||||||
|
port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
|
||||||
|
if e != nil {
|
||||||
|
return nil, os.NewSyscallError("CreateIoCompletionPort", e)
|
||||||
|
}
|
||||||
|
w := &Watcher{
|
||||||
|
port: port,
|
||||||
|
watches: make(watchMap),
|
||||||
|
input: make(chan *input, 1),
|
||||||
|
Events: make(chan Event, 50),
|
||||||
|
Errors: make(chan error),
|
||||||
|
quit: make(chan chan<- error, 1),
|
||||||
|
}
|
||||||
|
go w.readEvents()
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close removes all watches and closes the events channel.
|
||||||
|
func (w *Watcher) Close() error {
|
||||||
|
if w.isClosed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
w.isClosed = true
|
||||||
|
|
||||||
|
// Send "quit" message to the reader goroutine
|
||||||
|
ch := make(chan error)
|
||||||
|
w.quit <- ch
|
||||||
|
if err := w.wakeupReader(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return <-ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add starts watching the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Add(name string) error {
|
||||||
|
if w.isClosed {
|
||||||
|
return errors.New("watcher already closed")
|
||||||
|
}
|
||||||
|
in := &input{
|
||||||
|
op: opAddWatch,
|
||||||
|
path: filepath.Clean(name),
|
||||||
|
flags: sysFSALLEVENTS,
|
||||||
|
reply: make(chan error),
|
||||||
|
}
|
||||||
|
w.input <- in
|
||||||
|
if err := w.wakeupReader(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return <-in.reply
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove stops watching the the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Remove(name string) error {
|
||||||
|
in := &input{
|
||||||
|
op: opRemoveWatch,
|
||||||
|
path: filepath.Clean(name),
|
||||||
|
reply: make(chan error),
|
||||||
|
}
|
||||||
|
w.input <- in
|
||||||
|
if err := w.wakeupReader(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return <-in.reply
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Options for AddWatch
|
||||||
|
sysFSONESHOT = 0x80000000
|
||||||
|
sysFSONLYDIR = 0x1000000
|
||||||
|
|
||||||
|
// Events
|
||||||
|
sysFSACCESS = 0x1
|
||||||
|
sysFSALLEVENTS = 0xfff
|
||||||
|
sysFSATTRIB = 0x4
|
||||||
|
sysFSCLOSE = 0x18
|
||||||
|
sysFSCREATE = 0x100
|
||||||
|
sysFSDELETE = 0x200
|
||||||
|
sysFSDELETESELF = 0x400
|
||||||
|
sysFSMODIFY = 0x2
|
||||||
|
sysFSMOVE = 0xc0
|
||||||
|
sysFSMOVEDFROM = 0x40
|
||||||
|
sysFSMOVEDTO = 0x80
|
||||||
|
sysFSMOVESELF = 0x800
|
||||||
|
|
||||||
|
// Special events
|
||||||
|
sysFSIGNORED = 0x8000
|
||||||
|
sysFSQOVERFLOW = 0x4000
|
||||||
|
)
|
||||||
|
|
||||||
|
func newEvent(name string, mask uint32) Event {
|
||||||
|
e := Event{Name: name}
|
||||||
|
if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
|
||||||
|
e.Op |= Create
|
||||||
|
}
|
||||||
|
if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF {
|
||||||
|
e.Op |= Remove
|
||||||
|
}
|
||||||
|
if mask&sysFSMODIFY == sysFSMODIFY {
|
||||||
|
e.Op |= Write
|
||||||
|
}
|
||||||
|
if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM {
|
||||||
|
e.Op |= Rename
|
||||||
|
}
|
||||||
|
if mask&sysFSATTRIB == sysFSATTRIB {
|
||||||
|
e.Op |= Chmod
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
opAddWatch = iota
|
||||||
|
opRemoveWatch
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
provisional uint64 = 1 << (32 + iota)
|
||||||
|
)
|
||||||
|
|
||||||
|
type input struct {
|
||||||
|
op int
|
||||||
|
path string
|
||||||
|
flags uint32
|
||||||
|
reply chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
type inode struct {
|
||||||
|
handle syscall.Handle
|
||||||
|
volume uint32
|
||||||
|
index uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type watch struct {
|
||||||
|
ov syscall.Overlapped
|
||||||
|
ino *inode // i-number
|
||||||
|
path string // Directory path
|
||||||
|
mask uint64 // Directory itself is being watched with these notify flags
|
||||||
|
names map[string]uint64 // Map of names being watched and their notify flags
|
||||||
|
rename string // Remembers the old name while renaming a file
|
||||||
|
buf [4096]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type indexMap map[uint64]*watch
|
||||||
|
type watchMap map[uint32]indexMap
|
||||||
|
|
||||||
|
func (w *Watcher) wakeupReader() error {
|
||||||
|
e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil)
|
||||||
|
if e != nil {
|
||||||
|
return os.NewSyscallError("PostQueuedCompletionStatus", e)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDir(pathname string) (dir string, err error) {
|
||||||
|
attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
|
||||||
|
if e != nil {
|
||||||
|
return "", os.NewSyscallError("GetFileAttributes", e)
|
||||||
|
}
|
||||||
|
if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||||
|
dir = pathname
|
||||||
|
} else {
|
||||||
|
dir, _ = filepath.Split(pathname)
|
||||||
|
dir = filepath.Clean(dir)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIno(path string) (ino *inode, err error) {
|
||||||
|
h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
|
||||||
|
syscall.FILE_LIST_DIRECTORY,
|
||||||
|
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||||
|
nil, syscall.OPEN_EXISTING,
|
||||||
|
syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0)
|
||||||
|
if e != nil {
|
||||||
|
return nil, os.NewSyscallError("CreateFile", e)
|
||||||
|
}
|
||||||
|
var fi syscall.ByHandleFileInformation
|
||||||
|
if e = syscall.GetFileInformationByHandle(h, &fi); e != nil {
|
||||||
|
syscall.CloseHandle(h)
|
||||||
|
return nil, os.NewSyscallError("GetFileInformationByHandle", e)
|
||||||
|
}
|
||||||
|
ino = &inode{
|
||||||
|
handle: h,
|
||||||
|
volume: fi.VolumeSerialNumber,
|
||||||
|
index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
|
||||||
|
}
|
||||||
|
return ino, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (m watchMap) get(ino *inode) *watch {
|
||||||
|
if i := m[ino.volume]; i != nil {
|
||||||
|
return i[ino.index]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (m watchMap) set(ino *inode, watch *watch) {
|
||||||
|
i := m[ino.volume]
|
||||||
|
if i == nil {
|
||||||
|
i = make(indexMap)
|
||||||
|
m[ino.volume] = i
|
||||||
|
}
|
||||||
|
i[ino.index] = watch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (w *Watcher) addWatch(pathname string, flags uint64) error {
|
||||||
|
dir, err := getDir(pathname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if flags&sysFSONLYDIR != 0 && pathname != dir {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ino, err := getIno(dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.mu.Lock()
|
||||||
|
watchEntry := w.watches.get(ino)
|
||||||
|
w.mu.Unlock()
|
||||||
|
if watchEntry == nil {
|
||||||
|
if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil {
|
||||||
|
syscall.CloseHandle(ino.handle)
|
||||||
|
return os.NewSyscallError("CreateIoCompletionPort", e)
|
||||||
|
}
|
||||||
|
watchEntry = &watch{
|
||||||
|
ino: ino,
|
||||||
|
path: dir,
|
||||||
|
names: make(map[string]uint64),
|
||||||
|
}
|
||||||
|
w.mu.Lock()
|
||||||
|
w.watches.set(ino, watchEntry)
|
||||||
|
w.mu.Unlock()
|
||||||
|
flags |= provisional
|
||||||
|
} else {
|
||||||
|
syscall.CloseHandle(ino.handle)
|
||||||
|
}
|
||||||
|
if pathname == dir {
|
||||||
|
watchEntry.mask |= flags
|
||||||
|
} else {
|
||||||
|
watchEntry.names[filepath.Base(pathname)] |= flags
|
||||||
|
}
|
||||||
|
if err = w.startRead(watchEntry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pathname == dir {
|
||||||
|
watchEntry.mask &= ^provisional
|
||||||
|
} else {
|
||||||
|
watchEntry.names[filepath.Base(pathname)] &= ^provisional
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (w *Watcher) remWatch(pathname string) error {
|
||||||
|
dir, err := getDir(pathname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ino, err := getIno(dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.mu.Lock()
|
||||||
|
watch := w.watches.get(ino)
|
||||||
|
w.mu.Unlock()
|
||||||
|
if watch == nil {
|
||||||
|
return fmt.Errorf("can't remove non-existent watch for: %s", pathname)
|
||||||
|
}
|
||||||
|
if pathname == dir {
|
||||||
|
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
||||||
|
watch.mask = 0
|
||||||
|
} else {
|
||||||
|
name := filepath.Base(pathname)
|
||||||
|
w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED)
|
||||||
|
delete(watch.names, name)
|
||||||
|
}
|
||||||
|
return w.startRead(watch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (w *Watcher) deleteWatch(watch *watch) {
|
||||||
|
for name, mask := range watch.names {
|
||||||
|
if mask&provisional == 0 {
|
||||||
|
w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
|
||||||
|
}
|
||||||
|
delete(watch.names, name)
|
||||||
|
}
|
||||||
|
if watch.mask != 0 {
|
||||||
|
if watch.mask&provisional == 0 {
|
||||||
|
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
||||||
|
}
|
||||||
|
watch.mask = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (w *Watcher) startRead(watch *watch) error {
|
||||||
|
if e := syscall.CancelIo(watch.ino.handle); e != nil {
|
||||||
|
w.Errors <- os.NewSyscallError("CancelIo", e)
|
||||||
|
w.deleteWatch(watch)
|
||||||
|
}
|
||||||
|
mask := toWindowsFlags(watch.mask)
|
||||||
|
for _, m := range watch.names {
|
||||||
|
mask |= toWindowsFlags(m)
|
||||||
|
}
|
||||||
|
if mask == 0 {
|
||||||
|
if e := syscall.CloseHandle(watch.ino.handle); e != nil {
|
||||||
|
w.Errors <- os.NewSyscallError("CloseHandle", e)
|
||||||
|
}
|
||||||
|
w.mu.Lock()
|
||||||
|
delete(w.watches[watch.ino.volume], watch.ino.index)
|
||||||
|
w.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
|
||||||
|
uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
|
||||||
|
if e != nil {
|
||||||
|
err := os.NewSyscallError("ReadDirectoryChanges", e)
|
||||||
|
if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
|
||||||
|
// Watched directory was probably removed
|
||||||
|
if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) {
|
||||||
|
if watch.mask&sysFSONESHOT != 0 {
|
||||||
|
watch.mask = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
w.deleteWatch(watch)
|
||||||
|
w.startRead(watch)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readEvents reads from the I/O completion port, converts the
|
||||||
|
// received events into Event objects and sends them via the Events channel.
|
||||||
|
// Entry point to the I/O thread.
|
||||||
|
func (w *Watcher) readEvents() {
|
||||||
|
var (
|
||||||
|
n, key uint32
|
||||||
|
ov *syscall.Overlapped
|
||||||
|
)
|
||||||
|
runtime.LockOSThread()
|
||||||
|
|
||||||
|
for {
|
||||||
|
e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE)
|
||||||
|
watch := (*watch)(unsafe.Pointer(ov))
|
||||||
|
|
||||||
|
if watch == nil {
|
||||||
|
select {
|
||||||
|
case ch := <-w.quit:
|
||||||
|
w.mu.Lock()
|
||||||
|
var indexes []indexMap
|
||||||
|
for _, index := range w.watches {
|
||||||
|
indexes = append(indexes, index)
|
||||||
|
}
|
||||||
|
w.mu.Unlock()
|
||||||
|
for _, index := range indexes {
|
||||||
|
for _, watch := range index {
|
||||||
|
w.deleteWatch(watch)
|
||||||
|
w.startRead(watch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if e := syscall.CloseHandle(w.port); e != nil {
|
||||||
|
err = os.NewSyscallError("CloseHandle", e)
|
||||||
|
}
|
||||||
|
close(w.Events)
|
||||||
|
close(w.Errors)
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
case in := <-w.input:
|
||||||
|
switch in.op {
|
||||||
|
case opAddWatch:
|
||||||
|
in.reply <- w.addWatch(in.path, uint64(in.flags))
|
||||||
|
case opRemoveWatch:
|
||||||
|
in.reply <- w.remWatch(in.path)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e {
|
||||||
|
case syscall.ERROR_MORE_DATA:
|
||||||
|
if watch == nil {
|
||||||
|
w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
|
||||||
|
} else {
|
||||||
|
// The i/o succeeded but the buffer is full.
|
||||||
|
// In theory we should be building up a full packet.
|
||||||
|
// In practice we can get away with just carrying on.
|
||||||
|
n = uint32(unsafe.Sizeof(watch.buf))
|
||||||
|
}
|
||||||
|
case syscall.ERROR_ACCESS_DENIED:
|
||||||
|
// Watched directory was probably removed
|
||||||
|
w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
|
||||||
|
w.deleteWatch(watch)
|
||||||
|
w.startRead(watch)
|
||||||
|
continue
|
||||||
|
case syscall.ERROR_OPERATION_ABORTED:
|
||||||
|
// CancelIo was called on this handle
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e)
|
||||||
|
continue
|
||||||
|
case nil:
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset uint32
|
||||||
|
for {
|
||||||
|
if n == 0 {
|
||||||
|
w.Events <- newEvent("", sysFSQOVERFLOW)
|
||||||
|
w.Errors <- errors.New("short read in readEvents()")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Point "raw" to the event in the buffer
|
||||||
|
raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
|
||||||
|
buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
|
||||||
|
name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
|
||||||
|
fullname := filepath.Join(watch.path, name)
|
||||||
|
|
||||||
|
var mask uint64
|
||||||
|
switch raw.Action {
|
||||||
|
case syscall.FILE_ACTION_REMOVED:
|
||||||
|
mask = sysFSDELETESELF
|
||||||
|
case syscall.FILE_ACTION_MODIFIED:
|
||||||
|
mask = sysFSMODIFY
|
||||||
|
case syscall.FILE_ACTION_RENAMED_OLD_NAME:
|
||||||
|
watch.rename = name
|
||||||
|
case syscall.FILE_ACTION_RENAMED_NEW_NAME:
|
||||||
|
if watch.names[watch.rename] != 0 {
|
||||||
|
watch.names[name] |= watch.names[watch.rename]
|
||||||
|
delete(watch.names, watch.rename)
|
||||||
|
mask = sysFSMOVESELF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendNameEvent := func() {
|
||||||
|
if w.sendEvent(fullname, watch.names[name]&mask) {
|
||||||
|
if watch.names[name]&sysFSONESHOT != 0 {
|
||||||
|
delete(watch.names, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME {
|
||||||
|
sendNameEvent()
|
||||||
|
}
|
||||||
|
if raw.Action == syscall.FILE_ACTION_REMOVED {
|
||||||
|
w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
|
||||||
|
delete(watch.names, name)
|
||||||
|
}
|
||||||
|
if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) {
|
||||||
|
if watch.mask&sysFSONESHOT != 0 {
|
||||||
|
watch.mask = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME {
|
||||||
|
fullname = filepath.Join(watch.path, watch.rename)
|
||||||
|
sendNameEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next event in the buffer
|
||||||
|
if raw.NextEntryOffset == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
offset += raw.NextEntryOffset
|
||||||
|
|
||||||
|
// Error!
|
||||||
|
if offset >= n {
|
||||||
|
w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.startRead(watch); err != nil {
|
||||||
|
w.Errors <- err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watcher) sendEvent(name string, mask uint64) bool {
|
||||||
|
if mask == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
event := newEvent(name, uint32(mask))
|
||||||
|
select {
|
||||||
|
case ch := <-w.quit:
|
||||||
|
w.quit <- ch
|
||||||
|
case w.Events <- event:
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func toWindowsFlags(mask uint64) uint32 {
|
||||||
|
var m uint32
|
||||||
|
if mask&sysFSACCESS != 0 {
|
||||||
|
m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS
|
||||||
|
}
|
||||||
|
if mask&sysFSMODIFY != 0 {
|
||||||
|
m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE
|
||||||
|
}
|
||||||
|
if mask&sysFSATTRIB != 0 {
|
||||||
|
m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES
|
||||||
|
}
|
||||||
|
if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 {
|
||||||
|
m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func toFSnotifyFlags(action uint32) uint64 {
|
||||||
|
switch action {
|
||||||
|
case syscall.FILE_ACTION_ADDED:
|
||||||
|
return sysFSCREATE
|
||||||
|
case syscall.FILE_ACTION_REMOVED:
|
||||||
|
return sysFSDELETE
|
||||||
|
case syscall.FILE_ACTION_MODIFIED:
|
||||||
|
return sysFSMODIFY
|
||||||
|
case syscall.FILE_ACTION_RENAMED_OLD_NAME:
|
||||||
|
return sysFSMOVEDFROM
|
||||||
|
case syscall.FILE_ACTION_RENAMED_NEW_NAME:
|
||||||
|
return sysFSMOVEDTO
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
100
vendor/github.com/hashicorp/mdns/client.go
generated
vendored
100
vendor/github.com/hashicorp/mdns/client.go
generated
vendored
@ -42,8 +42,6 @@ type QueryParam struct {
|
|||||||
Interface *net.Interface // Multicast interface to use
|
Interface *net.Interface // Multicast interface to use
|
||||||
Entries chan<- *ServiceEntry // Entries Channel
|
Entries chan<- *ServiceEntry // Entries Channel
|
||||||
WantUnicastResponse bool // Unicast response desired, as per 5.4 in RFC
|
WantUnicastResponse bool // Unicast response desired, as per 5.4 in RFC
|
||||||
DisableIPv4 bool // Whether to disable usage of IPv4 for MDNS operations. Does not affect discovered addresses.
|
|
||||||
DisableIPv6 bool // Whether to disable usage of IPv6 for MDNS operations. Does not affect discovered addresses.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultParams is used to return a default set of QueryParam's
|
// DefaultParams is used to return a default set of QueryParam's
|
||||||
@ -54,8 +52,6 @@ func DefaultParams(service string) *QueryParam {
|
|||||||
Timeout: time.Second,
|
Timeout: time.Second,
|
||||||
Entries: make(chan *ServiceEntry),
|
Entries: make(chan *ServiceEntry),
|
||||||
WantUnicastResponse: false, // TODO(reddaly): Change this default.
|
WantUnicastResponse: false, // TODO(reddaly): Change this default.
|
||||||
DisableIPv4: false,
|
|
||||||
DisableIPv6: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +61,7 @@ func DefaultParams(service string) *QueryParam {
|
|||||||
// either read or buffer.
|
// either read or buffer.
|
||||||
func Query(params *QueryParam) error {
|
func Query(params *QueryParam) error {
|
||||||
// Create a new client
|
// Create a new client
|
||||||
client, err := newClient(!params.DisableIPv4, !params.DisableIPv6)
|
client, err := newClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -100,9 +96,6 @@ func Lookup(service string, entries chan<- *ServiceEntry) error {
|
|||||||
// Client provides a query interface that can be used to
|
// Client provides a query interface that can be used to
|
||||||
// search for service providers using mDNS
|
// search for service providers using mDNS
|
||||||
type client struct {
|
type client struct {
|
||||||
use_ipv4 bool
|
|
||||||
use_ipv6 bool
|
|
||||||
|
|
||||||
ipv4UnicastConn *net.UDPConn
|
ipv4UnicastConn *net.UDPConn
|
||||||
ipv6UnicastConn *net.UDPConn
|
ipv6UnicastConn *net.UDPConn
|
||||||
|
|
||||||
@ -115,48 +108,29 @@ type client struct {
|
|||||||
|
|
||||||
// NewClient creates a new mdns Client that can be used to query
|
// NewClient creates a new mdns Client that can be used to query
|
||||||
// for records
|
// for records
|
||||||
func newClient(v4 bool, v6 bool) (*client, error) {
|
func newClient() (*client, error) {
|
||||||
if !v4 && !v6 {
|
|
||||||
return nil, fmt.Errorf("Must enable at least one of IPv4 and IPv6 querying")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(reddaly): At least attempt to bind to the port required in the spec.
|
// TODO(reddaly): At least attempt to bind to the port required in the spec.
|
||||||
// Create a IPv4 listener
|
// Create a IPv4 listener
|
||||||
var uconn4 *net.UDPConn
|
uconn4, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||||
var uconn6 *net.UDPConn
|
if err != nil {
|
||||||
var mconn4 *net.UDPConn
|
log.Printf("[ERR] mdns: Failed to bind to udp4 port: %v", err)
|
||||||
var mconn6 *net.UDPConn
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if v4 {
|
|
||||||
uconn4, err = net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("[ERR] mdns: Failed to bind to udp4 port: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
uconn6, err := net.ListenUDP("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0})
|
||||||
if v6 {
|
if err != nil {
|
||||||
uconn6, err = net.ListenUDP("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0})
|
log.Printf("[ERR] mdns: Failed to bind to udp6 port: %v", err)
|
||||||
if err != nil {
|
|
||||||
log.Printf("[ERR] mdns: Failed to bind to udp6 port: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if uconn4 == nil && uconn6 == nil {
|
if uconn4 == nil && uconn6 == nil {
|
||||||
return nil, fmt.Errorf("failed to bind to any unicast udp port")
|
return nil, fmt.Errorf("failed to bind to any unicast udp port")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v4 {
|
mconn4, err := net.ListenMulticastUDP("udp4", nil, ipv4Addr)
|
||||||
mconn4, err = net.ListenMulticastUDP("udp4", nil, ipv4Addr)
|
if err != nil {
|
||||||
if err != nil {
|
log.Printf("[ERR] mdns: Failed to bind to udp4 port: %v", err)
|
||||||
log.Printf("[ERR] mdns: Failed to bind to udp4 port: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if v6 {
|
mconn6, err := net.ListenMulticastUDP("udp6", nil, ipv6Addr)
|
||||||
mconn6, err = net.ListenMulticastUDP("udp6", nil, ipv6Addr)
|
if err != nil {
|
||||||
if err != nil {
|
log.Printf("[ERR] mdns: Failed to bind to udp6 port: %v", err)
|
||||||
log.Printf("[ERR] mdns: Failed to bind to udp6 port: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if mconn4 == nil && mconn6 == nil {
|
if mconn4 == nil && mconn6 == nil {
|
||||||
@ -164,8 +138,6 @@ func newClient(v4 bool, v6 bool) (*client, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c := &client{
|
c := &client{
|
||||||
use_ipv4: v4,
|
|
||||||
use_ipv6: v6,
|
|
||||||
ipv4MulticastConn: mconn4,
|
ipv4MulticastConn: mconn4,
|
||||||
ipv6MulticastConn: mconn6,
|
ipv6MulticastConn: mconn6,
|
||||||
ipv4UnicastConn: uconn4,
|
ipv4UnicastConn: uconn4,
|
||||||
@ -204,25 +176,21 @@ func (c *client) Close() error {
|
|||||||
// setInterface is used to set the query interface, uses system
|
// setInterface is used to set the query interface, uses system
|
||||||
// default if not provided
|
// default if not provided
|
||||||
func (c *client) setInterface(iface *net.Interface) error {
|
func (c *client) setInterface(iface *net.Interface) error {
|
||||||
if c.use_ipv4 {
|
p := ipv4.NewPacketConn(c.ipv4UnicastConn)
|
||||||
p := ipv4.NewPacketConn(c.ipv4UnicastConn)
|
if err := p.SetMulticastInterface(iface); err != nil {
|
||||||
if err := p.SetMulticastInterface(iface); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
p = ipv4.NewPacketConn(c.ipv4MulticastConn)
|
|
||||||
if err := p.SetMulticastInterface(iface); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if c.use_ipv6 {
|
p2 := ipv6.NewPacketConn(c.ipv6UnicastConn)
|
||||||
p2 := ipv6.NewPacketConn(c.ipv6UnicastConn)
|
if err := p2.SetMulticastInterface(iface); err != nil {
|
||||||
if err := p2.SetMulticastInterface(iface); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
p = ipv4.NewPacketConn(c.ipv4MulticastConn)
|
||||||
p2 = ipv6.NewPacketConn(c.ipv6MulticastConn)
|
if err := p.SetMulticastInterface(iface); err != nil {
|
||||||
if err := p2.SetMulticastInterface(iface); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
p2 = ipv6.NewPacketConn(c.ipv6MulticastConn)
|
||||||
|
if err := p2.SetMulticastInterface(iface); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -234,14 +202,10 @@ func (c *client) query(params *QueryParam) error {
|
|||||||
|
|
||||||
// Start listening for response packets
|
// Start listening for response packets
|
||||||
msgCh := make(chan *dns.Msg, 32)
|
msgCh := make(chan *dns.Msg, 32)
|
||||||
if c.use_ipv4 {
|
go c.recv(c.ipv4UnicastConn, msgCh)
|
||||||
go c.recv(c.ipv4UnicastConn, msgCh)
|
go c.recv(c.ipv6UnicastConn, msgCh)
|
||||||
go c.recv(c.ipv4MulticastConn, msgCh)
|
go c.recv(c.ipv4MulticastConn, msgCh)
|
||||||
}
|
go c.recv(c.ipv6MulticastConn, msgCh)
|
||||||
if c.use_ipv6 {
|
|
||||||
go c.recv(c.ipv6UnicastConn, msgCh)
|
|
||||||
go c.recv(c.ipv6MulticastConn, msgCh)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the query
|
// Send the query
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
|
4
vendor/github.com/miekg/dns/README.md
generated
vendored
4
vendor/github.com/miekg/dns/README.md
generated
vendored
@ -73,10 +73,6 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
|||||||
* https://github.com/bodgit/tsig
|
* https://github.com/bodgit/tsig
|
||||||
* https://github.com/v2fly/v2ray-core (test only)
|
* https://github.com/v2fly/v2ray-core (test only)
|
||||||
* https://kuma.io/
|
* https://kuma.io/
|
||||||
* https://www.misaka.io/services/dns
|
|
||||||
* https://ping.sx/dig
|
|
||||||
* https://fleetdeck.io/
|
|
||||||
* https://github.com/markdingo/autoreverse
|
|
||||||
|
|
||||||
|
|
||||||
Send pull request if you want to be listed here.
|
Send pull request if you want to be listed here.
|
||||||
|
2
vendor/github.com/miekg/dns/acceptfunc.go
generated
vendored
2
vendor/github.com/miekg/dns/acceptfunc.go
generated
vendored
@ -12,7 +12,7 @@ type MsgAcceptFunc func(dh Header) MsgAcceptAction
|
|||||||
//
|
//
|
||||||
// * Zero bit isn't zero
|
// * Zero bit isn't zero
|
||||||
//
|
//
|
||||||
// * does not have exactly 1 question in the question section
|
// * has more than 1 question in the question section
|
||||||
//
|
//
|
||||||
// * has more than 1 RR in the Answer section
|
// * has more than 1 RR in the Answer section
|
||||||
//
|
//
|
||||||
|
127
vendor/github.com/miekg/dns/client.go
generated
vendored
127
vendor/github.com/miekg/dns/client.go
generated
vendored
@ -18,18 +18,6 @@ const (
|
|||||||
tcpIdleTimeout time.Duration = 8 * time.Second
|
tcpIdleTimeout time.Duration = 8 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
func isPacketConn(c net.Conn) bool {
|
|
||||||
if _, ok := c.(net.PacketConn); !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ua, ok := c.LocalAddr().(*net.UnixAddr); ok {
|
|
||||||
return ua.Net == "unixgram" || ua.Net == "unixpacket"
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Conn represents a connection to a DNS server.
|
// A Conn represents a connection to a DNS server.
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
net.Conn // a net.Conn holding the connection
|
net.Conn // a net.Conn holding the connection
|
||||||
@ -39,14 +27,6 @@ type Conn struct {
|
|||||||
tsigRequestMAC string
|
tsigRequestMAC string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (co *Conn) tsigProvider() TsigProvider {
|
|
||||||
if co.TsigProvider != nil {
|
|
||||||
return co.TsigProvider
|
|
||||||
}
|
|
||||||
// tsigSecretProvider will return ErrSecret if co.TsigSecret is nil.
|
|
||||||
return tsigSecretProvider(co.TsigSecret)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Client defines parameters for a DNS client.
|
// A Client defines parameters for a DNS client.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
|
Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
|
||||||
@ -102,12 +82,6 @@ func (c *Client) writeTimeout() time.Duration {
|
|||||||
|
|
||||||
// Dial connects to the address on the named network.
|
// Dial connects to the address on the named network.
|
||||||
func (c *Client) Dial(address string) (conn *Conn, err error) {
|
func (c *Client) Dial(address string) (conn *Conn, err error) {
|
||||||
return c.DialContext(context.Background(), address)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DialContext connects to the address on the named network, with a context.Context.
|
|
||||||
// For TLS over TCP (DoT) the context isn't used yet. This will be enabled when Go 1.18 is released.
|
|
||||||
func (c *Client) DialContext(ctx context.Context, address string) (conn *Conn, err error) {
|
|
||||||
// create a new dialer with the appropriate timeout
|
// create a new dialer with the appropriate timeout
|
||||||
var d net.Dialer
|
var d net.Dialer
|
||||||
if c.Dialer == nil {
|
if c.Dialer == nil {
|
||||||
@ -127,17 +101,9 @@ func (c *Client) DialContext(ctx context.Context, address string) (conn *Conn, e
|
|||||||
if useTLS {
|
if useTLS {
|
||||||
network = strings.TrimSuffix(network, "-tls")
|
network = strings.TrimSuffix(network, "-tls")
|
||||||
|
|
||||||
// TODO(miekg): Enable after Go 1.18 is released, to be able to support two prev. releases.
|
|
||||||
/*
|
|
||||||
tlsDialer := tls.Dialer{
|
|
||||||
NetDialer: &d,
|
|
||||||
Config: c.TLSConfig,
|
|
||||||
}
|
|
||||||
conn.Conn, err = tlsDialer.DialContext(ctx, network, address)
|
|
||||||
*/
|
|
||||||
conn.Conn, err = tls.DialWithDialer(&d, network, address, c.TLSConfig)
|
conn.Conn, err = tls.DialWithDialer(&d, network, address, c.TLSConfig)
|
||||||
} else {
|
} else {
|
||||||
conn.Conn, err = d.DialContext(ctx, network, address)
|
conn.Conn, err = d.Dial(network, address)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -173,34 +139,24 @@ func (c *Client) Exchange(m *Msg, address string) (r *Msg, rtt time.Duration, er
|
|||||||
// ExchangeWithConn has the same behavior as Exchange, just with a predetermined connection
|
// ExchangeWithConn has the same behavior as Exchange, just with a predetermined connection
|
||||||
// that will be used instead of creating a new one.
|
// that will be used instead of creating a new one.
|
||||||
// Usage pattern with a *dns.Client:
|
// Usage pattern with a *dns.Client:
|
||||||
//
|
|
||||||
// c := new(dns.Client)
|
// c := new(dns.Client)
|
||||||
// // connection management logic goes here
|
// // connection management logic goes here
|
||||||
//
|
//
|
||||||
// conn := c.Dial(address)
|
// conn := c.Dial(address)
|
||||||
// in, rtt, err := c.ExchangeWithConn(message, conn)
|
// in, rtt, err := c.ExchangeWithConn(message, conn)
|
||||||
//
|
//
|
||||||
// This allows users of the library to implement their own connection management,
|
// This allows users of the library to implement their own connection management,
|
||||||
// as opposed to Exchange, which will always use new connections and incur the added overhead
|
// as opposed to Exchange, which will always use new connections and incur the added overhead
|
||||||
// that entails when using "tcp" and especially "tcp-tls" clients.
|
// that entails when using "tcp" and especially "tcp-tls" clients.
|
||||||
//
|
|
||||||
// When the singleflight is set for this client the context is _not_ forwarded to the (shared) exchange, to
|
|
||||||
// prevent one cancelation from canceling all outstanding requests.
|
|
||||||
func (c *Client) ExchangeWithConn(m *Msg, conn *Conn) (r *Msg, rtt time.Duration, err error) {
|
func (c *Client) ExchangeWithConn(m *Msg, conn *Conn) (r *Msg, rtt time.Duration, err error) {
|
||||||
return c.exchangeWithConnContext(context.Background(), m, conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) exchangeWithConnContext(ctx context.Context, m *Msg, conn *Conn) (r *Msg, rtt time.Duration, err error) {
|
|
||||||
if !c.SingleInflight {
|
if !c.SingleInflight {
|
||||||
return c.exchangeContext(ctx, m, conn)
|
return c.exchange(m, conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
q := m.Question[0]
|
q := m.Question[0]
|
||||||
key := fmt.Sprintf("%s:%d:%d", q.Name, q.Qtype, q.Qclass)
|
key := fmt.Sprintf("%s:%d:%d", q.Name, q.Qtype, q.Qclass)
|
||||||
r, rtt, err, shared := c.group.Do(key, func() (*Msg, time.Duration, error) {
|
r, rtt, err, shared := c.group.Do(key, func() (*Msg, time.Duration, error) {
|
||||||
// When we're doing singleflight we don't want one context cancelation, cancel _all_ outstanding queries.
|
return c.exchange(m, conn)
|
||||||
// Hence we ignore the context and use Background().
|
|
||||||
return c.exchangeContext(context.Background(), m, conn)
|
|
||||||
})
|
})
|
||||||
if r != nil && shared {
|
if r != nil && shared {
|
||||||
r = r.Copy()
|
r = r.Copy()
|
||||||
@ -209,7 +165,8 @@ func (c *Client) exchangeWithConnContext(ctx context.Context, m *Msg, conn *Conn
|
|||||||
return r, rtt, err
|
return r, rtt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) exchangeContext(ctx context.Context, m *Msg, co *Conn) (r *Msg, rtt time.Duration, err error) {
|
func (c *Client) exchange(m *Msg, co *Conn) (r *Msg, rtt time.Duration, err error) {
|
||||||
|
|
||||||
opt := m.IsEdns0()
|
opt := m.IsEdns0()
|
||||||
// If EDNS0 is used use that for size.
|
// If EDNS0 is used use that for size.
|
||||||
if opt != nil && opt.UDPSize() >= MinMsgSize {
|
if opt != nil && opt.UDPSize() >= MinMsgSize {
|
||||||
@ -220,28 +177,16 @@ func (c *Client) exchangeContext(ctx context.Context, m *Msg, co *Conn) (r *Msg,
|
|||||||
co.UDPSize = c.UDPSize
|
co.UDPSize = c.UDPSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// write with the appropriate write timeout
|
|
||||||
t := time.Now()
|
|
||||||
writeDeadline := t.Add(c.getTimeoutForRequest(c.writeTimeout()))
|
|
||||||
readDeadline := t.Add(c.getTimeoutForRequest(c.readTimeout()))
|
|
||||||
if deadline, ok := ctx.Deadline(); ok {
|
|
||||||
if deadline.Before(writeDeadline) {
|
|
||||||
writeDeadline = deadline
|
|
||||||
}
|
|
||||||
if deadline.Before(readDeadline) {
|
|
||||||
readDeadline = deadline
|
|
||||||
}
|
|
||||||
}
|
|
||||||
co.SetWriteDeadline(writeDeadline)
|
|
||||||
co.SetReadDeadline(readDeadline)
|
|
||||||
|
|
||||||
co.TsigSecret, co.TsigProvider = c.TsigSecret, c.TsigProvider
|
co.TsigSecret, co.TsigProvider = c.TsigSecret, c.TsigProvider
|
||||||
|
t := time.Now()
|
||||||
|
// write with the appropriate write timeout
|
||||||
|
co.SetWriteDeadline(t.Add(c.getTimeoutForRequest(c.writeTimeout())))
|
||||||
if err = co.WriteMsg(m); err != nil {
|
if err = co.WriteMsg(m); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPacketConn(co.Conn) {
|
co.SetReadDeadline(time.Now().Add(c.getTimeoutForRequest(c.readTimeout())))
|
||||||
|
if _, ok := co.Conn.(net.PacketConn); ok {
|
||||||
for {
|
for {
|
||||||
r, err = co.ReadMsg()
|
r, err = co.ReadMsg()
|
||||||
// Ignore replies with mismatched IDs because they might be
|
// Ignore replies with mismatched IDs because they might be
|
||||||
@ -279,8 +224,15 @@ func (co *Conn) ReadMsg() (*Msg, error) {
|
|||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
if t := m.IsTsig(); t != nil {
|
if t := m.IsTsig(); t != nil {
|
||||||
// Need to work on the original message p, as that was used to calculate the tsig.
|
if co.TsigProvider != nil {
|
||||||
err = TsigVerifyWithProvider(p, co.tsigProvider(), co.tsigRequestMAC, false)
|
err = tsigVerifyProvider(p, co.TsigProvider, co.tsigRequestMAC, false)
|
||||||
|
} else {
|
||||||
|
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
|
||||||
|
return m, ErrSecret
|
||||||
|
}
|
||||||
|
// Need to work on the original message p, as that was used to calculate the tsig.
|
||||||
|
err = TsigVerify(p, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
@ -295,7 +247,7 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
|
|||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
if isPacketConn(co.Conn) {
|
if _, ok := co.Conn.(net.PacketConn); ok {
|
||||||
if co.UDPSize > MinMsgSize {
|
if co.UDPSize > MinMsgSize {
|
||||||
p = make([]byte, co.UDPSize)
|
p = make([]byte, co.UDPSize)
|
||||||
} else {
|
} else {
|
||||||
@ -335,7 +287,7 @@ func (co *Conn) Read(p []byte) (n int, err error) {
|
|||||||
return 0, ErrConnEmpty
|
return 0, ErrConnEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPacketConn(co.Conn) {
|
if _, ok := co.Conn.(net.PacketConn); ok {
|
||||||
// UDP connection
|
// UDP connection
|
||||||
return co.Conn.Read(p)
|
return co.Conn.Read(p)
|
||||||
}
|
}
|
||||||
@ -357,8 +309,17 @@ func (co *Conn) Read(p []byte) (n int, err error) {
|
|||||||
func (co *Conn) WriteMsg(m *Msg) (err error) {
|
func (co *Conn) WriteMsg(m *Msg) (err error) {
|
||||||
var out []byte
|
var out []byte
|
||||||
if t := m.IsTsig(); t != nil {
|
if t := m.IsTsig(); t != nil {
|
||||||
// Set tsigRequestMAC for the next read, although only used in zone transfers.
|
mac := ""
|
||||||
out, co.tsigRequestMAC, err = TsigGenerateWithProvider(m, co.tsigProvider(), co.tsigRequestMAC, false)
|
if co.TsigProvider != nil {
|
||||||
|
out, mac, err = tsigGenerateProvider(m, co.TsigProvider, co.tsigRequestMAC, false)
|
||||||
|
} else {
|
||||||
|
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
|
||||||
|
return ErrSecret
|
||||||
|
}
|
||||||
|
out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
|
||||||
|
}
|
||||||
|
// Set for the next read, although only used in zone transfers
|
||||||
|
co.tsigRequestMAC = mac
|
||||||
} else {
|
} else {
|
||||||
out, err = m.Pack()
|
out, err = m.Pack()
|
||||||
}
|
}
|
||||||
@ -375,7 +336,7 @@ func (co *Conn) Write(p []byte) (int, error) {
|
|||||||
return 0, &Error{err: "message too large"}
|
return 0, &Error{err: "message too large"}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPacketConn(co.Conn) {
|
if _, ok := co.Conn.(net.PacketConn); ok {
|
||||||
return co.Conn.Write(p)
|
return co.Conn.Write(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,11 +435,15 @@ func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout
|
|||||||
// context, if present. If there is both a context deadline and a configured
|
// context, if present. If there is both a context deadline and a configured
|
||||||
// timeout on the client, the earliest of the two takes effect.
|
// timeout on the client, the earliest of the two takes effect.
|
||||||
func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||||
conn, err := c.DialContext(ctx, a)
|
var timeout time.Duration
|
||||||
if err != nil {
|
if deadline, ok := ctx.Deadline(); !ok {
|
||||||
return nil, 0, err
|
timeout = 0
|
||||||
|
} else {
|
||||||
|
timeout = time.Until(deadline)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
// not passing the context to the underlying calls, as the API does not support
|
||||||
|
// context. For timeouts you should set up Client.Dialer and call Client.Exchange.
|
||||||
return c.exchangeWithConnContext(ctx, m, conn)
|
// TODO(tmthrgd,miekg): this is a race condition.
|
||||||
|
c.Dialer = &net.Dialer{Timeout: timeout}
|
||||||
|
return c.Exchange(m, a)
|
||||||
}
|
}
|
||||||
|
5
vendor/github.com/miekg/dns/defaults.go
generated
vendored
5
vendor/github.com/miekg/dns/defaults.go
generated
vendored
@ -218,11 +218,6 @@ func IsDomainName(s string) (labels int, ok bool) {
|
|||||||
|
|
||||||
wasDot = false
|
wasDot = false
|
||||||
case '.':
|
case '.':
|
||||||
if i == 0 && len(s) > 1 {
|
|
||||||
// leading dots are not legal except for the root zone
|
|
||||||
return labels, false
|
|
||||||
}
|
|
||||||
|
|
||||||
if wasDot {
|
if wasDot {
|
||||||
// two dots back to back is not legal
|
// two dots back to back is not legal
|
||||||
return labels, false
|
return labels, false
|
||||||
|
48
vendor/github.com/miekg/dns/dnssec.go
generated
vendored
48
vendor/github.com/miekg/dns/dnssec.go
generated
vendored
@ -65,9 +65,6 @@ var AlgorithmToString = map[uint8]string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
|
// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
|
||||||
// For newer algorithm that do their own hashing (i.e. ED25519) the returned value
|
|
||||||
// is 0, implying no (external) hashing should occur. The non-exported identityHash is then
|
|
||||||
// used.
|
|
||||||
var AlgorithmToHash = map[uint8]crypto.Hash{
|
var AlgorithmToHash = map[uint8]crypto.Hash{
|
||||||
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
|
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
|
||||||
DSA: crypto.SHA1,
|
DSA: crypto.SHA1,
|
||||||
@ -77,7 +74,7 @@ var AlgorithmToHash = map[uint8]crypto.Hash{
|
|||||||
ECDSAP256SHA256: crypto.SHA256,
|
ECDSAP256SHA256: crypto.SHA256,
|
||||||
ECDSAP384SHA384: crypto.SHA384,
|
ECDSAP384SHA384: crypto.SHA384,
|
||||||
RSASHA512: crypto.SHA512,
|
RSASHA512: crypto.SHA512,
|
||||||
ED25519: 0,
|
ED25519: crypto.Hash(0),
|
||||||
}
|
}
|
||||||
|
|
||||||
// DNSSEC hashing algorithm codes.
|
// DNSSEC hashing algorithm codes.
|
||||||
@ -140,12 +137,12 @@ func (k *DNSKEY) KeyTag() uint16 {
|
|||||||
var keytag int
|
var keytag int
|
||||||
switch k.Algorithm {
|
switch k.Algorithm {
|
||||||
case RSAMD5:
|
case RSAMD5:
|
||||||
|
// Look at the bottom two bytes of the modules, which the last
|
||||||
|
// item in the pubkey.
|
||||||
// This algorithm has been deprecated, but keep this key-tag calculation.
|
// This algorithm has been deprecated, but keep this key-tag calculation.
|
||||||
// Look at the bottom two bytes of the modules, which the last item in the pubkey.
|
|
||||||
// See https://www.rfc-editor.org/errata/eid193 .
|
|
||||||
modulus, _ := fromBase64([]byte(k.PublicKey))
|
modulus, _ := fromBase64([]byte(k.PublicKey))
|
||||||
if len(modulus) > 1 {
|
if len(modulus) > 1 {
|
||||||
x := binary.BigEndian.Uint16(modulus[len(modulus)-3:])
|
x := binary.BigEndian.Uint16(modulus[len(modulus)-2:])
|
||||||
keytag = int(x)
|
keytag = int(x)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -299,20 +296,35 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
|
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||||
if err != nil {
|
if !ok {
|
||||||
return err
|
return ErrAlg
|
||||||
}
|
}
|
||||||
|
|
||||||
switch rr.Algorithm {
|
switch rr.Algorithm {
|
||||||
|
case ED25519:
|
||||||
|
// ed25519 signs the raw message and performs hashing internally.
|
||||||
|
// All other supported signature schemes operate over the pre-hashed
|
||||||
|
// message, and thus ed25519 must be handled separately here.
|
||||||
|
//
|
||||||
|
// The raw message is passed directly into sign and crypto.Hash(0) is
|
||||||
|
// used to signal to the crypto.Signer that the data has not been hashed.
|
||||||
|
signature, err := sign(k, append(signdata, wire...), crypto.Hash(0), rr.Algorithm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rr.Signature = toBase64(signature)
|
||||||
|
return nil
|
||||||
case RSAMD5, DSA, DSANSEC3SHA1:
|
case RSAMD5, DSA, DSANSEC3SHA1:
|
||||||
// See RFC 6944.
|
// See RFC 6944.
|
||||||
return ErrAlg
|
return ErrAlg
|
||||||
default:
|
default:
|
||||||
|
h := hash.New()
|
||||||
h.Write(signdata)
|
h.Write(signdata)
|
||||||
h.Write(wire)
|
h.Write(wire)
|
||||||
|
|
||||||
signature, err := sign(k, h.Sum(nil), cryptohash, rr.Algorithm)
|
signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -329,7 +341,7 @@ func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch alg {
|
switch alg {
|
||||||
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, ED25519:
|
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
|
||||||
return signature, nil
|
return signature, nil
|
||||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||||
ecdsaSignature := &struct {
|
ecdsaSignature := &struct {
|
||||||
@ -350,6 +362,8 @@ func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte,
|
|||||||
signature := intToBytes(ecdsaSignature.R, intlen)
|
signature := intToBytes(ecdsaSignature.R, intlen)
|
||||||
signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
|
signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
|
||||||
return signature, nil
|
return signature, nil
|
||||||
|
case ED25519:
|
||||||
|
return signature, nil
|
||||||
default:
|
default:
|
||||||
return nil, ErrAlg
|
return nil, ErrAlg
|
||||||
}
|
}
|
||||||
@ -423,9 +437,9 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
|||||||
// remove the domain name and assume its ours?
|
// remove the domain name and assume its ours?
|
||||||
}
|
}
|
||||||
|
|
||||||
h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
|
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||||
if err != nil {
|
if !ok {
|
||||||
return err
|
return ErrAlg
|
||||||
}
|
}
|
||||||
|
|
||||||
switch rr.Algorithm {
|
switch rr.Algorithm {
|
||||||
@ -436,9 +450,10 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
|||||||
return ErrKey
|
return ErrKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h := hash.New()
|
||||||
h.Write(signeddata)
|
h.Write(signeddata)
|
||||||
h.Write(wire)
|
h.Write(wire)
|
||||||
return rsa.VerifyPKCS1v15(pubkey, cryptohash, h.Sum(nil), sigbuf)
|
return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
|
||||||
|
|
||||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||||
pubkey := k.publicKeyECDSA()
|
pubkey := k.publicKeyECDSA()
|
||||||
@ -450,6 +465,7 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
|||||||
r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
|
r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
|
||||||
s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
|
s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
|
||||||
|
|
||||||
|
h := hash.New()
|
||||||
h.Write(signeddata)
|
h.Write(signeddata)
|
||||||
h.Write(wire)
|
h.Write(wire)
|
||||||
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
|
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
|
||||||
|
2
vendor/github.com/miekg/dns/doc.go
generated
vendored
2
vendor/github.com/miekg/dns/doc.go
generated
vendored
@ -251,7 +251,7 @@ information.
|
|||||||
EDNS0
|
EDNS0
|
||||||
|
|
||||||
EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated by
|
EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated by
|
||||||
RFC 6891. It defines a new RR type, the OPT RR, which is then completely
|
RFC 6891. It defines an new RR type, the OPT RR, which is then completely
|
||||||
abused.
|
abused.
|
||||||
|
|
||||||
Basic use pattern for creating an (empty) OPT RR:
|
Basic use pattern for creating an (empty) OPT RR:
|
||||||
|
98
vendor/github.com/miekg/dns/edns.go
generated
vendored
98
vendor/github.com/miekg/dns/edns.go
generated
vendored
@ -14,7 +14,6 @@ const (
|
|||||||
EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
||||||
EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
||||||
EDNS0NSID = 0x3 // nsid (See RFC 5001)
|
EDNS0NSID = 0x3 // nsid (See RFC 5001)
|
||||||
EDNS0ESU = 0x4 // ENUM Source-URI draft: https://datatracker.ietf.org/doc/html/draft-kaplan-enum-source-uri-00
|
|
||||||
EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
|
EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
|
||||||
EDNS0DHU = 0x6 // DS Hash Understood
|
EDNS0DHU = 0x6 // DS Hash Understood
|
||||||
EDNS0N3U = 0x7 // NSEC3 Hash Understood
|
EDNS0N3U = 0x7 // NSEC3 Hash Understood
|
||||||
@ -57,8 +56,6 @@ func makeDataOpt(code uint16) EDNS0 {
|
|||||||
return new(EDNS0_PADDING)
|
return new(EDNS0_PADDING)
|
||||||
case EDNS0EDE:
|
case EDNS0EDE:
|
||||||
return new(EDNS0_EDE)
|
return new(EDNS0_EDE)
|
||||||
case EDNS0ESU:
|
|
||||||
return &EDNS0_ESU{Code: EDNS0ESU}
|
|
||||||
default:
|
default:
|
||||||
e := new(EDNS0_LOCAL)
|
e := new(EDNS0_LOCAL)
|
||||||
e.Code = code
|
e.Code = code
|
||||||
@ -98,8 +95,6 @@ func (rr *OPT) String() string {
|
|||||||
s += "\n; SUBNET: " + o.String()
|
s += "\n; SUBNET: " + o.String()
|
||||||
case *EDNS0_COOKIE:
|
case *EDNS0_COOKIE:
|
||||||
s += "\n; COOKIE: " + o.String()
|
s += "\n; COOKIE: " + o.String()
|
||||||
case *EDNS0_TCP_KEEPALIVE:
|
|
||||||
s += "\n; KEEPALIVE: " + o.String()
|
|
||||||
case *EDNS0_UL:
|
case *EDNS0_UL:
|
||||||
s += "\n; UPDATE LEASE: " + o.String()
|
s += "\n; UPDATE LEASE: " + o.String()
|
||||||
case *EDNS0_LLQ:
|
case *EDNS0_LLQ:
|
||||||
@ -116,8 +111,6 @@ func (rr *OPT) String() string {
|
|||||||
s += "\n; PADDING: " + o.String()
|
s += "\n; PADDING: " + o.String()
|
||||||
case *EDNS0_EDE:
|
case *EDNS0_EDE:
|
||||||
s += "\n; EDE: " + o.String()
|
s += "\n; EDE: " + o.String()
|
||||||
case *EDNS0_ESU:
|
|
||||||
s += "\n; ESU: " + o.String()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
@ -584,17 +577,14 @@ func (e *EDNS0_N3U) copy() EDNS0 { return &EDNS0_N3U{e.Code, e.AlgCode} }
|
|||||||
type EDNS0_EXPIRE struct {
|
type EDNS0_EXPIRE struct {
|
||||||
Code uint16 // Always EDNS0EXPIRE
|
Code uint16 // Always EDNS0EXPIRE
|
||||||
Expire uint32
|
Expire uint32
|
||||||
Empty bool // Empty is used to signal an empty Expire option in a backwards compatible way, it's not used on the wire.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option implements the EDNS0 interface.
|
// Option implements the EDNS0 interface.
|
||||||
func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
|
func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
|
||||||
func (e *EDNS0_EXPIRE) copy() EDNS0 { return &EDNS0_EXPIRE{e.Code, e.Expire, e.Empty} }
|
func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) }
|
||||||
|
func (e *EDNS0_EXPIRE) copy() EDNS0 { return &EDNS0_EXPIRE{e.Code, e.Expire} }
|
||||||
|
|
||||||
func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
|
func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
|
||||||
if e.Empty {
|
|
||||||
return []byte{}, nil
|
|
||||||
}
|
|
||||||
b := make([]byte, 4)
|
b := make([]byte, 4)
|
||||||
binary.BigEndian.PutUint32(b, e.Expire)
|
binary.BigEndian.PutUint32(b, e.Expire)
|
||||||
return b, nil
|
return b, nil
|
||||||
@ -603,24 +593,15 @@ func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
|
|||||||
func (e *EDNS0_EXPIRE) unpack(b []byte) error {
|
func (e *EDNS0_EXPIRE) unpack(b []byte) error {
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
// zero-length EXPIRE query, see RFC 7314 Section 2
|
// zero-length EXPIRE query, see RFC 7314 Section 2
|
||||||
e.Empty = true
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if len(b) < 4 {
|
if len(b) < 4 {
|
||||||
return ErrBuf
|
return ErrBuf
|
||||||
}
|
}
|
||||||
e.Expire = binary.BigEndian.Uint32(b)
|
e.Expire = binary.BigEndian.Uint32(b)
|
||||||
e.Empty = false
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EDNS0_EXPIRE) String() (s string) {
|
|
||||||
if e.Empty {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return strconv.FormatUint(uint64(e.Expire), 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The EDNS0_LOCAL option is used for local/experimental purposes. The option
|
// The EDNS0_LOCAL option is used for local/experimental purposes. The option
|
||||||
// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
|
// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
|
||||||
// (RFC6891), although any unassigned code can actually be used. The content of
|
// (RFC6891), although any unassigned code can actually be used. The content of
|
||||||
@ -671,52 +652,57 @@ func (e *EDNS0_LOCAL) unpack(b []byte) error {
|
|||||||
// EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep
|
// EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep
|
||||||
// the TCP connection alive. See RFC 7828.
|
// the TCP connection alive. See RFC 7828.
|
||||||
type EDNS0_TCP_KEEPALIVE struct {
|
type EDNS0_TCP_KEEPALIVE struct {
|
||||||
Code uint16 // Always EDNSTCPKEEPALIVE
|
Code uint16 // Always EDNSTCPKEEPALIVE
|
||||||
|
Length uint16 // the value 0 if the TIMEOUT is omitted, the value 2 if it is present;
|
||||||
// Timeout is an idle timeout value for the TCP connection, specified in
|
Timeout uint16 // an idle timeout value for the TCP connection, specified in units of 100 milliseconds, encoded in network byte order.
|
||||||
// units of 100 milliseconds, encoded in network byte order. If set to 0,
|
|
||||||
// pack will return a nil slice.
|
|
||||||
Timeout uint16
|
|
||||||
|
|
||||||
// Length is the option's length.
|
|
||||||
// Deprecated: this field is deprecated and is always equal to 0.
|
|
||||||
Length uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option implements the EDNS0 interface.
|
// Option implements the EDNS0 interface.
|
||||||
func (e *EDNS0_TCP_KEEPALIVE) Option() uint16 { return EDNS0TCPKEEPALIVE }
|
func (e *EDNS0_TCP_KEEPALIVE) Option() uint16 { return EDNS0TCPKEEPALIVE }
|
||||||
|
|
||||||
func (e *EDNS0_TCP_KEEPALIVE) pack() ([]byte, error) {
|
func (e *EDNS0_TCP_KEEPALIVE) pack() ([]byte, error) {
|
||||||
if e.Timeout > 0 {
|
if e.Timeout != 0 && e.Length != 2 {
|
||||||
b := make([]byte, 2)
|
return nil, errors.New("dns: timeout specified but length is not 2")
|
||||||
binary.BigEndian.PutUint16(b, e.Timeout)
|
|
||||||
return b, nil
|
|
||||||
}
|
}
|
||||||
return nil, nil
|
if e.Timeout == 0 && e.Length != 0 {
|
||||||
|
return nil, errors.New("dns: timeout not specified but length is not 0")
|
||||||
|
}
|
||||||
|
b := make([]byte, 4+e.Length)
|
||||||
|
binary.BigEndian.PutUint16(b[0:], e.Code)
|
||||||
|
binary.BigEndian.PutUint16(b[2:], e.Length)
|
||||||
|
if e.Length == 2 {
|
||||||
|
binary.BigEndian.PutUint16(b[4:], e.Timeout)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EDNS0_TCP_KEEPALIVE) unpack(b []byte) error {
|
func (e *EDNS0_TCP_KEEPALIVE) unpack(b []byte) error {
|
||||||
switch len(b) {
|
if len(b) < 4 {
|
||||||
case 0:
|
return ErrBuf
|
||||||
case 2:
|
}
|
||||||
e.Timeout = binary.BigEndian.Uint16(b)
|
e.Length = binary.BigEndian.Uint16(b[2:4])
|
||||||
default:
|
if e.Length != 0 && e.Length != 2 {
|
||||||
return fmt.Errorf("dns: length mismatch, want 0/2 but got %d", len(b))
|
return errors.New("dns: length mismatch, want 0/2 but got " + strconv.FormatUint(uint64(e.Length), 10))
|
||||||
|
}
|
||||||
|
if e.Length == 2 {
|
||||||
|
if len(b) < 6 {
|
||||||
|
return ErrBuf
|
||||||
|
}
|
||||||
|
e.Timeout = binary.BigEndian.Uint16(b[4:6])
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EDNS0_TCP_KEEPALIVE) String() string {
|
func (e *EDNS0_TCP_KEEPALIVE) String() (s string) {
|
||||||
s := "use tcp keep-alive"
|
s = "use tcp keep-alive"
|
||||||
if e.Timeout == 0 {
|
if e.Length == 0 {
|
||||||
s += ", timeout omitted"
|
s += ", timeout omitted"
|
||||||
} else {
|
} else {
|
||||||
s += fmt.Sprintf(", timeout %dms", e.Timeout*100)
|
s += fmt.Sprintf(", timeout %dms", e.Timeout*100)
|
||||||
}
|
}
|
||||||
return s
|
return
|
||||||
}
|
}
|
||||||
|
func (e *EDNS0_TCP_KEEPALIVE) copy() EDNS0 { return &EDNS0_TCP_KEEPALIVE{e.Code, e.Length, e.Timeout} }
|
||||||
func (e *EDNS0_TCP_KEEPALIVE) copy() EDNS0 { return &EDNS0_TCP_KEEPALIVE{e.Code, e.Timeout, e.Length} }
|
|
||||||
|
|
||||||
// EDNS0_PADDING option is used to add padding to a request/response. The default
|
// EDNS0_PADDING option is used to add padding to a request/response. The default
|
||||||
// value of padding SHOULD be 0x0 but other values MAY be used, for instance if
|
// value of padding SHOULD be 0x0 but other values MAY be used, for instance if
|
||||||
@ -833,19 +819,3 @@ func (e *EDNS0_EDE) unpack(b []byte) error {
|
|||||||
e.ExtraText = string(b[2:])
|
e.ExtraText = string(b[2:])
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// The EDNS0_ESU option for ENUM Source-URI Extension
|
|
||||||
type EDNS0_ESU struct {
|
|
||||||
Code uint16
|
|
||||||
Uri string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Option implements the EDNS0 interface.
|
|
||||||
func (e *EDNS0_ESU) Option() uint16 { return EDNS0ESU }
|
|
||||||
func (e *EDNS0_ESU) String() string { return e.Uri }
|
|
||||||
func (e *EDNS0_ESU) copy() EDNS0 { return &EDNS0_ESU{e.Code, e.Uri} }
|
|
||||||
func (e *EDNS0_ESU) pack() ([]byte, error) { return []byte(e.Uri), nil }
|
|
||||||
func (e *EDNS0_ESU) unpack(b []byte) error {
|
|
||||||
e.Uri = string(b)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
31
vendor/github.com/miekg/dns/hash.go
generated
vendored
31
vendor/github.com/miekg/dns/hash.go
generated
vendored
@ -1,31 +0,0 @@
|
|||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto"
|
|
||||||
"hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
// identityHash will not hash, it only buffers the data written into it and returns it as-is.
|
|
||||||
type identityHash struct {
|
|
||||||
b *bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement the hash.Hash interface.
|
|
||||||
|
|
||||||
func (i identityHash) Write(b []byte) (int, error) { return i.b.Write(b) }
|
|
||||||
func (i identityHash) Size() int { return i.b.Len() }
|
|
||||||
func (i identityHash) BlockSize() int { return 1024 }
|
|
||||||
func (i identityHash) Reset() { i.b.Reset() }
|
|
||||||
func (i identityHash) Sum(b []byte) []byte { return append(b, i.b.Bytes()...) }
|
|
||||||
|
|
||||||
func hashFromAlgorithm(alg uint8) (hash.Hash, crypto.Hash, error) {
|
|
||||||
hashnumber, ok := AlgorithmToHash[alg]
|
|
||||||
if !ok {
|
|
||||||
return nil, 0, ErrAlg
|
|
||||||
}
|
|
||||||
if hashnumber == 0 {
|
|
||||||
return identityHash{b: &bytes.Buffer{}}, hashnumber, nil
|
|
||||||
}
|
|
||||||
return hashnumber.New(), hashnumber, nil
|
|
||||||
}
|
|
14
vendor/github.com/miekg/dns/msg.go
generated
vendored
14
vendor/github.com/miekg/dns/msg.go
generated
vendored
@ -265,11 +265,6 @@ loop:
|
|||||||
|
|
||||||
wasDot = false
|
wasDot = false
|
||||||
case '.':
|
case '.':
|
||||||
if i == 0 && len(s) > 1 {
|
|
||||||
// leading dots are not legal except for the root zone
|
|
||||||
return len(msg), ErrRdata
|
|
||||||
}
|
|
||||||
|
|
||||||
if wasDot {
|
if wasDot {
|
||||||
// two dots back to back is not legal
|
// two dots back to back is not legal
|
||||||
return len(msg), ErrRdata
|
return len(msg), ErrRdata
|
||||||
@ -906,11 +901,6 @@ func (dns *Msg) String() string {
|
|||||||
s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", "
|
s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", "
|
||||||
s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", "
|
s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", "
|
||||||
s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n"
|
s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n"
|
||||||
opt := dns.IsEdns0()
|
|
||||||
if opt != nil {
|
|
||||||
// OPT PSEUDOSECTION
|
|
||||||
s += opt.String() + "\n"
|
|
||||||
}
|
|
||||||
if len(dns.Question) > 0 {
|
if len(dns.Question) > 0 {
|
||||||
s += "\n;; QUESTION SECTION:\n"
|
s += "\n;; QUESTION SECTION:\n"
|
||||||
for _, r := range dns.Question {
|
for _, r := range dns.Question {
|
||||||
@ -933,10 +923,10 @@ func (dns *Msg) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(dns.Extra) > 0 && (opt == nil || len(dns.Extra) > 1) {
|
if len(dns.Extra) > 0 {
|
||||||
s += "\n;; ADDITIONAL SECTION:\n"
|
s += "\n;; ADDITIONAL SECTION:\n"
|
||||||
for _, r := range dns.Extra {
|
for _, r := range dns.Extra {
|
||||||
if r != nil && r.Header().Rrtype != TypeOPT {
|
if r != nil {
|
||||||
s += r.String() + "\n"
|
s += r.String() + "\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
vendor/github.com/miekg/dns/msg_helpers.go
generated
vendored
26
vendor/github.com/miekg/dns/msg_helpers.go
generated
vendored
@ -476,7 +476,7 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
|
|||||||
length, window, lastwindow := 0, 0, -1
|
length, window, lastwindow := 0, 0, -1
|
||||||
for off < len(msg) {
|
for off < len(msg) {
|
||||||
if off+2 > len(msg) {
|
if off+2 > len(msg) {
|
||||||
return nsec, len(msg), &Error{err: "overflow unpacking NSEC(3)"}
|
return nsec, len(msg), &Error{err: "overflow unpacking nsecx"}
|
||||||
}
|
}
|
||||||
window = int(msg[off])
|
window = int(msg[off])
|
||||||
length = int(msg[off+1])
|
length = int(msg[off+1])
|
||||||
@ -484,17 +484,17 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
|
|||||||
if window <= lastwindow {
|
if window <= lastwindow {
|
||||||
// RFC 4034: Blocks are present in the NSEC RR RDATA in
|
// RFC 4034: Blocks are present in the NSEC RR RDATA in
|
||||||
// increasing numerical order.
|
// increasing numerical order.
|
||||||
return nsec, len(msg), &Error{err: "out of order NSEC(3) block in type bitmap"}
|
return nsec, len(msg), &Error{err: "out of order NSEC block"}
|
||||||
}
|
}
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
// RFC 4034: Blocks with no types present MUST NOT be included.
|
// RFC 4034: Blocks with no types present MUST NOT be included.
|
||||||
return nsec, len(msg), &Error{err: "empty NSEC(3) block in type bitmap"}
|
return nsec, len(msg), &Error{err: "empty NSEC block"}
|
||||||
}
|
}
|
||||||
if length > 32 {
|
if length > 32 {
|
||||||
return nsec, len(msg), &Error{err: "NSEC(3) block too long in type bitmap"}
|
return nsec, len(msg), &Error{err: "NSEC block too long"}
|
||||||
}
|
}
|
||||||
if off+length > len(msg) {
|
if off+length > len(msg) {
|
||||||
return nsec, len(msg), &Error{err: "overflowing NSEC(3) block in type bitmap"}
|
return nsec, len(msg), &Error{err: "overflowing NSEC block"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk the bytes in the window and extract the type bits
|
// Walk the bytes in the window and extract the type bits
|
||||||
@ -558,16 +558,6 @@ func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
|
|||||||
if len(bitmap) == 0 {
|
if len(bitmap) == 0 {
|
||||||
return off, nil
|
return off, nil
|
||||||
}
|
}
|
||||||
if off > len(msg) {
|
|
||||||
return off, &Error{err: "overflow packing nsec"}
|
|
||||||
}
|
|
||||||
toZero := msg[off:]
|
|
||||||
if maxLen := typeBitMapLen(bitmap); maxLen < len(toZero) {
|
|
||||||
toZero = toZero[:maxLen]
|
|
||||||
}
|
|
||||||
for i := range toZero {
|
|
||||||
toZero[i] = 0
|
|
||||||
}
|
|
||||||
var lastwindow, lastlength uint16
|
var lastwindow, lastlength uint16
|
||||||
for _, t := range bitmap {
|
for _, t := range bitmap {
|
||||||
window := t / 256
|
window := t / 256
|
||||||
@ -791,8 +781,6 @@ func unpackDataAplPrefix(msg []byte, off int) (APLPrefix, int, error) {
|
|||||||
if off+afdlen > len(msg) {
|
if off+afdlen > len(msg) {
|
||||||
return APLPrefix{}, len(msg), &Error{err: "overflow unpacking APL address"}
|
return APLPrefix{}, len(msg), &Error{err: "overflow unpacking APL address"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address MUST NOT contain trailing zero bytes per RFC3123 Sections 4.1 and 4.2.
|
|
||||||
off += copy(ip, msg[off:off+afdlen])
|
off += copy(ip, msg[off:off+afdlen])
|
||||||
if afdlen > 0 {
|
if afdlen > 0 {
|
||||||
last := ip[afdlen-1]
|
last := ip[afdlen-1]
|
||||||
@ -804,6 +792,10 @@ func unpackDataAplPrefix(msg []byte, off int) (APLPrefix, int, error) {
|
|||||||
IP: ip,
|
IP: ip,
|
||||||
Mask: net.CIDRMask(int(prefix), 8*len(ip)),
|
Mask: net.CIDRMask(int(prefix), 8*len(ip)),
|
||||||
}
|
}
|
||||||
|
network := ipnet.IP.Mask(ipnet.Mask)
|
||||||
|
if !network.Equal(ipnet.IP) {
|
||||||
|
return APLPrefix{}, len(msg), &Error{err: "invalid APL address length"}
|
||||||
|
}
|
||||||
|
|
||||||
return APLPrefix{
|
return APLPrefix{
|
||||||
Negation: (nlen & 0x80) != 0,
|
Negation: (nlen & 0x80) != 0,
|
||||||
|
42
vendor/github.com/miekg/dns/server.go
generated
vendored
42
vendor/github.com/miekg/dns/server.go
generated
vendored
@ -71,12 +71,12 @@ type response struct {
|
|||||||
tsigTimersOnly bool
|
tsigTimersOnly bool
|
||||||
tsigStatus error
|
tsigStatus error
|
||||||
tsigRequestMAC string
|
tsigRequestMAC string
|
||||||
tsigProvider TsigProvider
|
tsigSecret map[string]string // the tsig secrets
|
||||||
udp net.PacketConn // i/o connection if UDP was used
|
udp net.PacketConn // i/o connection if UDP was used
|
||||||
tcp net.Conn // i/o connection if TCP was used
|
tcp net.Conn // i/o connection if TCP was used
|
||||||
udpSession *SessionUDP // oob data to get egress interface right
|
udpSession *SessionUDP // oob data to get egress interface right
|
||||||
pcSession net.Addr // address to use when writing to a generic net.PacketConn
|
pcSession net.Addr // address to use when writing to a generic net.PacketConn
|
||||||
writer Writer // writer to output the raw DNS bits
|
writer Writer // writer to output the raw DNS bits
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleRefused returns a HandlerFunc that returns REFUSED for every request it gets.
|
// handleRefused returns a HandlerFunc that returns REFUSED for every request it gets.
|
||||||
@ -211,8 +211,6 @@ type Server struct {
|
|||||||
WriteTimeout time.Duration
|
WriteTimeout time.Duration
|
||||||
// TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966).
|
// TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966).
|
||||||
IdleTimeout func() time.Duration
|
IdleTimeout func() time.Duration
|
||||||
// An implementation of the TsigProvider interface. If defined it replaces TsigSecret and is used for all TSIG operations.
|
|
||||||
TsigProvider TsigProvider
|
|
||||||
// Secret(s) for Tsig map[<zonename>]<base64 secret>. The zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2).
|
// Secret(s) for Tsig map[<zonename>]<base64 secret>. The zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2).
|
||||||
TsigSecret map[string]string
|
TsigSecret map[string]string
|
||||||
// If NotifyStartedFunc is set it is called once the server has started listening.
|
// If NotifyStartedFunc is set it is called once the server has started listening.
|
||||||
@ -240,16 +238,6 @@ type Server struct {
|
|||||||
udpPool sync.Pool
|
udpPool sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) tsigProvider() TsigProvider {
|
|
||||||
if srv.TsigProvider != nil {
|
|
||||||
return srv.TsigProvider
|
|
||||||
}
|
|
||||||
if srv.TsigSecret != nil {
|
|
||||||
return tsigSecretProvider(srv.TsigSecret)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (srv *Server) isStarted() bool {
|
func (srv *Server) isStarted() bool {
|
||||||
srv.lock.RLock()
|
srv.lock.RLock()
|
||||||
started := srv.started
|
started := srv.started
|
||||||
@ -538,7 +526,7 @@ func (srv *Server) serveUDP(l net.PacketConn) error {
|
|||||||
|
|
||||||
// Serve a new TCP connection.
|
// Serve a new TCP connection.
|
||||||
func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
|
func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
|
||||||
w := &response{tsigProvider: srv.tsigProvider(), tcp: rw}
|
w := &response{tsigSecret: srv.TsigSecret, tcp: rw}
|
||||||
if srv.DecorateWriter != nil {
|
if srv.DecorateWriter != nil {
|
||||||
w.writer = srv.DecorateWriter(w)
|
w.writer = srv.DecorateWriter(w)
|
||||||
} else {
|
} else {
|
||||||
@ -593,7 +581,7 @@ func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
|
|||||||
|
|
||||||
// Serve a new UDP request.
|
// Serve a new UDP request.
|
||||||
func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u net.PacketConn, udpSession *SessionUDP, pcSession net.Addr) {
|
func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u net.PacketConn, udpSession *SessionUDP, pcSession net.Addr) {
|
||||||
w := &response{tsigProvider: srv.tsigProvider(), udp: u, udpSession: udpSession, pcSession: pcSession}
|
w := &response{tsigSecret: srv.TsigSecret, udp: u, udpSession: udpSession, pcSession: pcSession}
|
||||||
if srv.DecorateWriter != nil {
|
if srv.DecorateWriter != nil {
|
||||||
w.writer = srv.DecorateWriter(w)
|
w.writer = srv.DecorateWriter(w)
|
||||||
} else {
|
} else {
|
||||||
@ -644,11 +632,15 @@ func (srv *Server) serveDNS(m []byte, w *response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.tsigStatus = nil
|
w.tsigStatus = nil
|
||||||
if w.tsigProvider != nil {
|
if w.tsigSecret != nil {
|
||||||
if t := req.IsTsig(); t != nil {
|
if t := req.IsTsig(); t != nil {
|
||||||
w.tsigStatus = TsigVerifyWithProvider(m, w.tsigProvider, "", false)
|
if secret, ok := w.tsigSecret[t.Hdr.Name]; ok {
|
||||||
|
w.tsigStatus = TsigVerify(m, secret, "", false)
|
||||||
|
} else {
|
||||||
|
w.tsigStatus = ErrSecret
|
||||||
|
}
|
||||||
w.tsigTimersOnly = false
|
w.tsigTimersOnly = false
|
||||||
w.tsigRequestMAC = t.MAC
|
w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -726,9 +718,9 @@ func (w *response) WriteMsg(m *Msg) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var data []byte
|
var data []byte
|
||||||
if w.tsigProvider != nil { // if no provider, dont check for the tsig (which is a longer check)
|
if w.tsigSecret != nil { // if no secrets, dont check for the tsig (which is a longer check)
|
||||||
if t := m.IsTsig(); t != nil {
|
if t := m.IsTsig(); t != nil {
|
||||||
data, w.tsigRequestMAC, err = TsigGenerateWithProvider(m, w.tsigProvider, w.tsigRequestMAC, w.tsigTimersOnly)
|
data, w.tsigRequestMAC, err = TsigGenerate(m, w.tsigSecret[t.Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
51
vendor/github.com/miekg/dns/sig0.go
generated
vendored
51
vendor/github.com/miekg/dns/sig0.go
generated
vendored
@ -3,7 +3,6 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/ed25519"
|
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -39,17 +38,18 @@ func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
buf = buf[:off:cap(buf)]
|
buf = buf[:off:cap(buf)]
|
||||||
|
|
||||||
h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
|
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||||
if err != nil {
|
if !ok {
|
||||||
return nil, err
|
return nil, ErrAlg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasher := hash.New()
|
||||||
// Write SIG rdata
|
// Write SIG rdata
|
||||||
h.Write(buf[len(mbuf)+1+2+2+4+2:])
|
hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
|
||||||
// Write message
|
// Write message
|
||||||
h.Write(buf[:len(mbuf)])
|
hasher.Write(buf[:len(mbuf)])
|
||||||
|
|
||||||
signature, err := sign(k, h.Sum(nil), cryptohash, rr.Algorithm)
|
signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -82,10 +82,20 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
|||||||
return ErrKey
|
return ErrKey
|
||||||
}
|
}
|
||||||
|
|
||||||
h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
|
var hash crypto.Hash
|
||||||
if err != nil {
|
switch rr.Algorithm {
|
||||||
return err
|
case RSASHA1:
|
||||||
|
hash = crypto.SHA1
|
||||||
|
case RSASHA256, ECDSAP256SHA256:
|
||||||
|
hash = crypto.SHA256
|
||||||
|
case ECDSAP384SHA384:
|
||||||
|
hash = crypto.SHA384
|
||||||
|
case RSASHA512:
|
||||||
|
hash = crypto.SHA512
|
||||||
|
default:
|
||||||
|
return ErrAlg
|
||||||
}
|
}
|
||||||
|
hasher := hash.New()
|
||||||
|
|
||||||
buflen := len(buf)
|
buflen := len(buf)
|
||||||
qdc := binary.BigEndian.Uint16(buf[4:])
|
qdc := binary.BigEndian.Uint16(buf[4:])
|
||||||
@ -93,6 +103,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
|||||||
auc := binary.BigEndian.Uint16(buf[8:])
|
auc := binary.BigEndian.Uint16(buf[8:])
|
||||||
adc := binary.BigEndian.Uint16(buf[10:])
|
adc := binary.BigEndian.Uint16(buf[10:])
|
||||||
offset := headerSize
|
offset := headerSize
|
||||||
|
var err error
|
||||||
for i := uint16(0); i < qdc && offset < buflen; i++ {
|
for i := uint16(0); i < qdc && offset < buflen; i++ {
|
||||||
_, offset, err = UnpackDomainName(buf, offset)
|
_, offset, err = UnpackDomainName(buf, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -155,21 +166,21 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
|||||||
return &Error{err: "signer name doesn't match key name"}
|
return &Error{err: "signer name doesn't match key name"}
|
||||||
}
|
}
|
||||||
sigend := offset
|
sigend := offset
|
||||||
h.Write(buf[sigstart:sigend])
|
hasher.Write(buf[sigstart:sigend])
|
||||||
h.Write(buf[:10])
|
hasher.Write(buf[:10])
|
||||||
h.Write([]byte{
|
hasher.Write([]byte{
|
||||||
byte((adc - 1) << 8),
|
byte((adc - 1) << 8),
|
||||||
byte(adc - 1),
|
byte(adc - 1),
|
||||||
})
|
})
|
||||||
h.Write(buf[12:bodyend])
|
hasher.Write(buf[12:bodyend])
|
||||||
|
|
||||||
hashed := h.Sum(nil)
|
hashed := hasher.Sum(nil)
|
||||||
sig := buf[sigend:]
|
sig := buf[sigend:]
|
||||||
switch k.Algorithm {
|
switch k.Algorithm {
|
||||||
case RSASHA1, RSASHA256, RSASHA512:
|
case RSASHA1, RSASHA256, RSASHA512:
|
||||||
pk := k.publicKeyRSA()
|
pk := k.publicKeyRSA()
|
||||||
if pk != nil {
|
if pk != nil {
|
||||||
return rsa.VerifyPKCS1v15(pk, cryptohash, hashed, sig)
|
return rsa.VerifyPKCS1v15(pk, hash, hashed, sig)
|
||||||
}
|
}
|
||||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||||
pk := k.publicKeyECDSA()
|
pk := k.publicKeyECDSA()
|
||||||
@ -181,14 +192,6 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
|||||||
}
|
}
|
||||||
return ErrSig
|
return ErrSig
|
||||||
}
|
}
|
||||||
case ED25519:
|
|
||||||
pk := k.publicKeyED25519()
|
|
||||||
if pk != nil {
|
|
||||||
if ed25519.Verify(pk, hashed, sig) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return ErrSig
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ErrKeyAlg
|
return ErrKeyAlg
|
||||||
}
|
}
|
||||||
|
330
vendor/github.com/miekg/dns/svcb.go
generated
vendored
330
vendor/github.com/miekg/dns/svcb.go
generated
vendored
@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -14,18 +13,16 @@ import (
|
|||||||
// SVCBKey is the type of the keys used in the SVCB RR.
|
// SVCBKey is the type of the keys used in the SVCB RR.
|
||||||
type SVCBKey uint16
|
type SVCBKey uint16
|
||||||
|
|
||||||
// Keys defined in draft-ietf-dnsop-svcb-https-08 Section 14.3.2.
|
// Keys defined in draft-ietf-dnsop-svcb-https-01 Section 12.3.2.
|
||||||
const (
|
const (
|
||||||
SVCB_MANDATORY SVCBKey = iota
|
SVCB_MANDATORY SVCBKey = 0
|
||||||
SVCB_ALPN
|
SVCB_ALPN SVCBKey = 1
|
||||||
SVCB_NO_DEFAULT_ALPN
|
SVCB_NO_DEFAULT_ALPN SVCBKey = 2
|
||||||
SVCB_PORT
|
SVCB_PORT SVCBKey = 3
|
||||||
SVCB_IPV4HINT
|
SVCB_IPV4HINT SVCBKey = 4
|
||||||
SVCB_ECHCONFIG
|
SVCB_ECHCONFIG SVCBKey = 5
|
||||||
SVCB_IPV6HINT
|
SVCB_IPV6HINT SVCBKey = 6
|
||||||
SVCB_DOHPATH // draft-ietf-add-svcb-dns-02 Section 9
|
svcb_RESERVED SVCBKey = 65535
|
||||||
|
|
||||||
svcb_RESERVED SVCBKey = 65535
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var svcbKeyToStringMap = map[SVCBKey]string{
|
var svcbKeyToStringMap = map[SVCBKey]string{
|
||||||
@ -34,9 +31,8 @@ var svcbKeyToStringMap = map[SVCBKey]string{
|
|||||||
SVCB_NO_DEFAULT_ALPN: "no-default-alpn",
|
SVCB_NO_DEFAULT_ALPN: "no-default-alpn",
|
||||||
SVCB_PORT: "port",
|
SVCB_PORT: "port",
|
||||||
SVCB_IPV4HINT: "ipv4hint",
|
SVCB_IPV4HINT: "ipv4hint",
|
||||||
SVCB_ECHCONFIG: "ech",
|
SVCB_ECHCONFIG: "echconfig",
|
||||||
SVCB_IPV6HINT: "ipv6hint",
|
SVCB_IPV6HINT: "ipv6hint",
|
||||||
SVCB_DOHPATH: "dohpath",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var svcbStringToKeyMap = reverseSVCBKeyMap(svcbKeyToStringMap)
|
var svcbStringToKeyMap = reverseSVCBKeyMap(svcbKeyToStringMap)
|
||||||
@ -171,14 +167,10 @@ func (rr *SVCB) parse(c *zlexer, o string) *ParseError {
|
|||||||
}
|
}
|
||||||
l, _ = c.Next()
|
l, _ = c.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// "In AliasMode, records SHOULD NOT include any SvcParams, and recipients MUST
|
|
||||||
// ignore any SvcParams that are present."
|
|
||||||
// However, we don't check rr.Priority == 0 && len(xs) > 0 here
|
|
||||||
// It is the responsibility of the user of the library to check this.
|
|
||||||
// This is to encourage the fixing of the source of this error.
|
|
||||||
|
|
||||||
rr.Value = xs
|
rr.Value = xs
|
||||||
|
if rr.Priority == 0 && len(xs) > 0 {
|
||||||
|
return &ParseError{l.token, "SVCB aliasform can't have values", l}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,8 +191,6 @@ func makeSVCBKeyValue(key SVCBKey) SVCBKeyValue {
|
|||||||
return new(SVCBECHConfig)
|
return new(SVCBECHConfig)
|
||||||
case SVCB_IPV6HINT:
|
case SVCB_IPV6HINT:
|
||||||
return new(SVCBIPv6Hint)
|
return new(SVCBIPv6Hint)
|
||||||
case SVCB_DOHPATH:
|
|
||||||
return new(SVCBDoHPath)
|
|
||||||
case svcb_RESERVED:
|
case svcb_RESERVED:
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
@ -210,24 +200,16 @@ func makeSVCBKeyValue(key SVCBKey) SVCBKeyValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SVCB RR. See RFC xxxx (https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-08).
|
// SVCB RR. See RFC xxxx (https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-01).
|
||||||
//
|
|
||||||
// NOTE: The HTTPS/SVCB RFCs are in the draft stage.
|
|
||||||
// The API, including constants and types related to SVCBKeyValues, may
|
|
||||||
// change in future versions in accordance with the latest drafts.
|
|
||||||
type SVCB struct {
|
type SVCB struct {
|
||||||
Hdr RR_Header
|
Hdr RR_Header
|
||||||
Priority uint16 // If zero, Value must be empty or discarded by the user of this library
|
Priority uint16
|
||||||
Target string `dns:"domain-name"`
|
Target string `dns:"domain-name"`
|
||||||
Value []SVCBKeyValue `dns:"pairs"`
|
Value []SVCBKeyValue `dns:"pairs"` // Value must be empty if Priority is zero.
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPS RR. Everything valid for SVCB applies to HTTPS as well.
|
// HTTPS RR. Everything valid for SVCB applies to HTTPS as well.
|
||||||
// Except that the HTTPS record is intended for use with the HTTP and HTTPS protocols.
|
// Except that the HTTPS record is intended for use with the HTTP and HTTPS protocols.
|
||||||
//
|
|
||||||
// NOTE: The HTTPS/SVCB RFCs are in the draft stage.
|
|
||||||
// The API, including constants and types related to SVCBKeyValues, may
|
|
||||||
// change in future versions in accordance with the latest drafts.
|
|
||||||
type HTTPS struct {
|
type HTTPS struct {
|
||||||
SVCB
|
SVCB
|
||||||
}
|
}
|
||||||
@ -253,29 +235,15 @@ type SVCBKeyValue interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SVCBMandatory pair adds to required keys that must be interpreted for the RR
|
// SVCBMandatory pair adds to required keys that must be interpreted for the RR
|
||||||
// to be functional. If ignored, the whole RRSet must be ignored.
|
// to be functional.
|
||||||
// "port" and "no-default-alpn" are mandatory by default if present,
|
|
||||||
// so they shouldn't be included here.
|
|
||||||
//
|
|
||||||
// It is incumbent upon the user of this library to reject the RRSet if
|
|
||||||
// or avoid constructing such an RRSet that:
|
|
||||||
// - "mandatory" is included as one of the keys of mandatory
|
|
||||||
// - no key is listed multiple times in mandatory
|
|
||||||
// - all keys listed in mandatory are present
|
|
||||||
// - escape sequences are not used in mandatory
|
|
||||||
// - mandatory, when present, lists at least one key
|
|
||||||
//
|
|
||||||
// Basic use pattern for creating a mandatory option:
|
// Basic use pattern for creating a mandatory option:
|
||||||
//
|
//
|
||||||
// s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
|
// s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
|
||||||
// e := new(dns.SVCBMandatory)
|
// e := new(dns.SVCBMandatory)
|
||||||
// e.Code = []uint16{dns.SVCB_ALPN}
|
// e.Code = []uint16{65403}
|
||||||
// s.Value = append(s.Value, e)
|
// s.Value = append(s.Value, e)
|
||||||
// t := new(dns.SVCBAlpn)
|
|
||||||
// t.Alpn = []string{"xmpp-client"}
|
|
||||||
// s.Value = append(s.Value, t)
|
|
||||||
type SVCBMandatory struct {
|
type SVCBMandatory struct {
|
||||||
Code []SVCBKey
|
Code []SVCBKey // Must not include mandatory
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*SVCBMandatory) Key() SVCBKey { return SVCB_MANDATORY }
|
func (*SVCBMandatory) Key() SVCBKey { return SVCB_MANDATORY }
|
||||||
@ -334,8 +302,7 @@ func (s *SVCBMandatory) copy() SVCBKeyValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SVCBAlpn pair is used to list supported connection protocols.
|
// SVCBAlpn pair is used to list supported connection protocols.
|
||||||
// The user of this library must ensure that at least one protocol is listed when alpn is present.
|
// Protocol ids can be found at:
|
||||||
// Protocol IDs can be found at:
|
|
||||||
// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
|
// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
|
||||||
// Basic use pattern for creating an alpn option:
|
// Basic use pattern for creating an alpn option:
|
||||||
//
|
//
|
||||||
@ -343,57 +310,13 @@ func (s *SVCBMandatory) copy() SVCBKeyValue {
|
|||||||
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
|
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
|
||||||
// e := new(dns.SVCBAlpn)
|
// e := new(dns.SVCBAlpn)
|
||||||
// e.Alpn = []string{"h2", "http/1.1"}
|
// e.Alpn = []string{"h2", "http/1.1"}
|
||||||
// h.Value = append(h.Value, e)
|
// h.Value = append(o.Value, e)
|
||||||
type SVCBAlpn struct {
|
type SVCBAlpn struct {
|
||||||
Alpn []string
|
Alpn []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*SVCBAlpn) Key() SVCBKey { return SVCB_ALPN }
|
func (*SVCBAlpn) Key() SVCBKey { return SVCB_ALPN }
|
||||||
|
func (s *SVCBAlpn) String() string { return strings.Join(s.Alpn, ",") }
|
||||||
func (s *SVCBAlpn) String() string {
|
|
||||||
// An ALPN value is a comma-separated list of values, each of which can be
|
|
||||||
// an arbitrary binary value. In order to allow parsing, the comma and
|
|
||||||
// backslash characters are themselves excaped.
|
|
||||||
//
|
|
||||||
// However, this escaping is done in addition to the normal escaping which
|
|
||||||
// happens in zone files, meaning that these values must be
|
|
||||||
// double-escaped. This looks terrible, so if you see a never-ending
|
|
||||||
// sequence of backslash in a zone file this may be why.
|
|
||||||
//
|
|
||||||
// https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-08#appendix-A.1
|
|
||||||
var str strings.Builder
|
|
||||||
for i, alpn := range s.Alpn {
|
|
||||||
// 4*len(alpn) is the worst case where we escape every character in the alpn as \123, plus 1 byte for the ',' separating the alpn from others
|
|
||||||
str.Grow(4*len(alpn) + 1)
|
|
||||||
if i > 0 {
|
|
||||||
str.WriteByte(',')
|
|
||||||
}
|
|
||||||
for j := 0; j < len(alpn); j++ {
|
|
||||||
e := alpn[j]
|
|
||||||
if ' ' > e || e > '~' {
|
|
||||||
str.WriteString(escapeByte(e))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch e {
|
|
||||||
// We escape a few characters which may confuse humans or parsers.
|
|
||||||
case '"', ';', ' ':
|
|
||||||
str.WriteByte('\\')
|
|
||||||
str.WriteByte(e)
|
|
||||||
// The comma and backslash characters themselves must be
|
|
||||||
// doubly-escaped. We use `\\` for the first backslash and
|
|
||||||
// the escaped numeric value for the other value. We especially
|
|
||||||
// don't want a comma in the output.
|
|
||||||
case ',':
|
|
||||||
str.WriteString(`\\\044`)
|
|
||||||
case '\\':
|
|
||||||
str.WriteString(`\\\092`)
|
|
||||||
default:
|
|
||||||
str.WriteByte(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SVCBAlpn) pack() ([]byte, error) {
|
func (s *SVCBAlpn) pack() ([]byte, error) {
|
||||||
// Liberally estimate the size of an alpn as 10 octets
|
// Liberally estimate the size of an alpn as 10 octets
|
||||||
@ -428,47 +351,7 @@ func (s *SVCBAlpn) unpack(b []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SVCBAlpn) parse(b string) error {
|
func (s *SVCBAlpn) parse(b string) error {
|
||||||
if len(b) == 0 {
|
s.Alpn = strings.Split(b, ",")
|
||||||
s.Alpn = []string{}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
alpn := []string{}
|
|
||||||
a := []byte{}
|
|
||||||
for p := 0; p < len(b); {
|
|
||||||
c, q := nextByte(b, p)
|
|
||||||
if q == 0 {
|
|
||||||
return errors.New("dns: svcbalpn: unterminated escape")
|
|
||||||
}
|
|
||||||
p += q
|
|
||||||
// If we find a comma, we have finished reading an alpn.
|
|
||||||
if c == ',' {
|
|
||||||
if len(a) == 0 {
|
|
||||||
return errors.New("dns: svcbalpn: empty protocol identifier")
|
|
||||||
}
|
|
||||||
alpn = append(alpn, string(a))
|
|
||||||
a = []byte{}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// If it's a backslash, we need to handle a comma-separated list.
|
|
||||||
if c == '\\' {
|
|
||||||
dc, dq := nextByte(b, p)
|
|
||||||
if dq == 0 {
|
|
||||||
return errors.New("dns: svcbalpn: unterminated escape decoding comma-separated list")
|
|
||||||
}
|
|
||||||
if dc != '\\' && dc != ',' {
|
|
||||||
return errors.New("dns: svcbalpn: bad escaped character decoding comma-separated list")
|
|
||||||
}
|
|
||||||
p += dq
|
|
||||||
c = dc
|
|
||||||
}
|
|
||||||
a = append(a, c)
|
|
||||||
}
|
|
||||||
// Add the final alpn.
|
|
||||||
if len(a) == 0 {
|
|
||||||
return errors.New("dns: svcbalpn: last protocol identifier empty")
|
|
||||||
}
|
|
||||||
s.Alpn = append(alpn, string(a))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,13 +370,9 @@ func (s *SVCBAlpn) copy() SVCBKeyValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SVCBNoDefaultAlpn pair signifies no support for default connection protocols.
|
// SVCBNoDefaultAlpn pair signifies no support for default connection protocols.
|
||||||
// Should be used in conjunction with alpn.
|
|
||||||
// Basic use pattern for creating a no-default-alpn option:
|
// Basic use pattern for creating a no-default-alpn option:
|
||||||
//
|
//
|
||||||
// s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
|
// s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
|
||||||
// t := new(dns.SVCBAlpn)
|
|
||||||
// t.Alpn = []string{"xmpp-client"}
|
|
||||||
// s.Value = append(s.Value, t)
|
|
||||||
// e := new(dns.SVCBNoDefaultAlpn)
|
// e := new(dns.SVCBNoDefaultAlpn)
|
||||||
// s.Value = append(s.Value, e)
|
// s.Value = append(s.Value, e)
|
||||||
type SVCBNoDefaultAlpn struct{}
|
type SVCBNoDefaultAlpn struct{}
|
||||||
@ -506,14 +385,14 @@ func (*SVCBNoDefaultAlpn) len() int { return 0 }
|
|||||||
|
|
||||||
func (*SVCBNoDefaultAlpn) unpack(b []byte) error {
|
func (*SVCBNoDefaultAlpn) unpack(b []byte) error {
|
||||||
if len(b) != 0 {
|
if len(b) != 0 {
|
||||||
return errors.New("dns: svcbnodefaultalpn: no-default-alpn must have no value")
|
return errors.New("dns: svcbnodefaultalpn: no_default_alpn must have no value")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*SVCBNoDefaultAlpn) parse(b string) error {
|
func (*SVCBNoDefaultAlpn) parse(b string) error {
|
||||||
if b != "" {
|
if b != "" {
|
||||||
return errors.New("dns: svcbnodefaultalpn: no-default-alpn must have no value")
|
return errors.New("dns: svcbnodefaultalpn: no_default_alpn must have no value")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -644,7 +523,7 @@ func (s *SVCBIPv4Hint) copy() SVCBKeyValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SVCBECHConfig pair contains the ECHConfig structure defined in draft-ietf-tls-esni [RFC xxxx].
|
// SVCBECHConfig pair contains the ECHConfig structure defined in draft-ietf-tls-esni [RFC xxxx].
|
||||||
// Basic use pattern for creating an ech option:
|
// Basic use pattern for creating an echconfig option:
|
||||||
//
|
//
|
||||||
// h := new(dns.HTTPS)
|
// h := new(dns.HTTPS)
|
||||||
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
|
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
|
||||||
@ -652,7 +531,7 @@ func (s *SVCBIPv4Hint) copy() SVCBKeyValue {
|
|||||||
// e.ECH = []byte{0xfe, 0x08, ...}
|
// e.ECH = []byte{0xfe, 0x08, ...}
|
||||||
// h.Value = append(h.Value, e)
|
// h.Value = append(h.Value, e)
|
||||||
type SVCBECHConfig struct {
|
type SVCBECHConfig struct {
|
||||||
ECH []byte // Specifically ECHConfigList including the redundant length prefix
|
ECH []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*SVCBECHConfig) Key() SVCBKey { return SVCB_ECHCONFIG }
|
func (*SVCBECHConfig) Key() SVCBKey { return SVCB_ECHCONFIG }
|
||||||
@ -676,7 +555,7 @@ func (s *SVCBECHConfig) unpack(b []byte) error {
|
|||||||
func (s *SVCBECHConfig) parse(b string) error {
|
func (s *SVCBECHConfig) parse(b string) error {
|
||||||
x, err := fromBase64([]byte(b))
|
x, err := fromBase64([]byte(b))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("dns: svcbech: bad base64 ech")
|
return errors.New("dns: svcbechconfig: bad base64 echconfig")
|
||||||
}
|
}
|
||||||
s.ECH = x
|
s.ECH = x
|
||||||
return nil
|
return nil
|
||||||
@ -739,6 +618,9 @@ func (s *SVCBIPv6Hint) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SVCBIPv6Hint) parse(b string) error {
|
func (s *SVCBIPv6Hint) parse(b string) error {
|
||||||
|
if strings.Contains(b, ".") {
|
||||||
|
return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4")
|
||||||
|
}
|
||||||
str := strings.Split(b, ",")
|
str := strings.Split(b, ",")
|
||||||
dst := make([]net.IP, len(str))
|
dst := make([]net.IP, len(str))
|
||||||
for i, e := range str {
|
for i, e := range str {
|
||||||
@ -746,9 +628,6 @@ func (s *SVCBIPv6Hint) parse(b string) error {
|
|||||||
if ip == nil {
|
if ip == nil {
|
||||||
return errors.New("dns: svcbipv6hint: bad ip")
|
return errors.New("dns: svcbipv6hint: bad ip")
|
||||||
}
|
}
|
||||||
if ip.To4() != nil {
|
|
||||||
return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4-mapped-ipv6")
|
|
||||||
}
|
|
||||||
dst[i] = ip
|
dst[i] = ip
|
||||||
}
|
}
|
||||||
s.Hint = dst
|
s.Hint = dst
|
||||||
@ -766,54 +645,6 @@ func (s *SVCBIPv6Hint) copy() SVCBKeyValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SVCBDoHPath pair is used to indicate the URI template that the
|
|
||||||
// clients may use to construct a DNS over HTTPS URI.
|
|
||||||
//
|
|
||||||
// See RFC xxxx (https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02)
|
|
||||||
// and RFC yyyy (https://datatracker.ietf.org/doc/html/draft-ietf-add-ddr-06).
|
|
||||||
//
|
|
||||||
// A basic example of using the dohpath option together with the alpn
|
|
||||||
// option to indicate support for DNS over HTTPS on a certain path:
|
|
||||||
//
|
|
||||||
// s := new(dns.SVCB)
|
|
||||||
// s.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}
|
|
||||||
// e := new(dns.SVCBAlpn)
|
|
||||||
// e.Alpn = []string{"h2", "h3"}
|
|
||||||
// p := new(dns.SVCBDoHPath)
|
|
||||||
// p.Template = "/dns-query{?dns}"
|
|
||||||
// s.Value = append(s.Value, e, p)
|
|
||||||
//
|
|
||||||
// The parsing currently doesn't validate that Template is a valid
|
|
||||||
// RFC 6570 URI template.
|
|
||||||
type SVCBDoHPath struct {
|
|
||||||
Template string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*SVCBDoHPath) Key() SVCBKey { return SVCB_DOHPATH }
|
|
||||||
func (s *SVCBDoHPath) String() string { return svcbParamToStr([]byte(s.Template)) }
|
|
||||||
func (s *SVCBDoHPath) len() int { return len(s.Template) }
|
|
||||||
func (s *SVCBDoHPath) pack() ([]byte, error) { return []byte(s.Template), nil }
|
|
||||||
|
|
||||||
func (s *SVCBDoHPath) unpack(b []byte) error {
|
|
||||||
s.Template = string(b)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SVCBDoHPath) parse(b string) error {
|
|
||||||
template, err := svcbParseParam(b)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("dns: svcbdohpath: %w", err)
|
|
||||||
}
|
|
||||||
s.Template = string(template)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SVCBDoHPath) copy() SVCBKeyValue {
|
|
||||||
return &SVCBDoHPath{
|
|
||||||
Template: s.Template,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SVCBLocal pair is intended for experimental/private use. The key is recommended
|
// SVCBLocal pair is intended for experimental/private use. The key is recommended
|
||||||
// to be in the range [SVCB_PRIVATE_LOWER, SVCB_PRIVATE_UPPER].
|
// to be in the range [SVCB_PRIVATE_LOWER, SVCB_PRIVATE_UPPER].
|
||||||
// Basic use pattern for creating a keyNNNNN option:
|
// Basic use pattern for creating a keyNNNNN option:
|
||||||
@ -830,7 +661,6 @@ type SVCBLocal struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SVCBLocal) Key() SVCBKey { return s.KeyCode }
|
func (s *SVCBLocal) Key() SVCBKey { return s.KeyCode }
|
||||||
func (s *SVCBLocal) String() string { return svcbParamToStr(s.Data) }
|
|
||||||
func (s *SVCBLocal) pack() ([]byte, error) { return append([]byte(nil), s.Data...), nil }
|
func (s *SVCBLocal) pack() ([]byte, error) { return append([]byte(nil), s.Data...), nil }
|
||||||
func (s *SVCBLocal) len() int { return len(s.Data) }
|
func (s *SVCBLocal) len() int { return len(s.Data) }
|
||||||
|
|
||||||
@ -839,10 +669,50 @@ func (s *SVCBLocal) unpack(b []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SVCBLocal) String() string {
|
||||||
|
var str strings.Builder
|
||||||
|
str.Grow(4 * len(s.Data))
|
||||||
|
for _, e := range s.Data {
|
||||||
|
if ' ' <= e && e <= '~' {
|
||||||
|
switch e {
|
||||||
|
case '"', ';', ' ', '\\':
|
||||||
|
str.WriteByte('\\')
|
||||||
|
str.WriteByte(e)
|
||||||
|
default:
|
||||||
|
str.WriteByte(e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
str.WriteString(escapeByte(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str.String()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SVCBLocal) parse(b string) error {
|
func (s *SVCBLocal) parse(b string) error {
|
||||||
data, err := svcbParseParam(b)
|
data := make([]byte, 0, len(b))
|
||||||
if err != nil {
|
for i := 0; i < len(b); {
|
||||||
return fmt.Errorf("dns: svcblocal: svcb private/experimental key %w", err)
|
if b[i] != '\\' {
|
||||||
|
data = append(data, b[i])
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if i+1 == len(b) {
|
||||||
|
return errors.New("dns: svcblocal: svcb private/experimental key escape unterminated")
|
||||||
|
}
|
||||||
|
if isDigit(b[i+1]) {
|
||||||
|
if i+3 < len(b) && isDigit(b[i+2]) && isDigit(b[i+3]) {
|
||||||
|
a, err := strconv.ParseUint(b[i+1:i+4], 10, 8)
|
||||||
|
if err == nil {
|
||||||
|
i += 4
|
||||||
|
data = append(data, byte(a))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors.New("dns: svcblocal: svcb private/experimental key bad escaped octet")
|
||||||
|
} else {
|
||||||
|
data = append(data, b[i+1])
|
||||||
|
i += 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.Data = data
|
s.Data = data
|
||||||
return nil
|
return nil
|
||||||
@ -883,53 +753,3 @@ func areSVCBPairArraysEqual(a []SVCBKeyValue, b []SVCBKeyValue) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// svcbParamStr converts the value of an SVCB parameter into a DNS presentation-format string.
|
|
||||||
func svcbParamToStr(s []byte) string {
|
|
||||||
var str strings.Builder
|
|
||||||
str.Grow(4 * len(s))
|
|
||||||
for _, e := range s {
|
|
||||||
if ' ' <= e && e <= '~' {
|
|
||||||
switch e {
|
|
||||||
case '"', ';', ' ', '\\':
|
|
||||||
str.WriteByte('\\')
|
|
||||||
str.WriteByte(e)
|
|
||||||
default:
|
|
||||||
str.WriteByte(e)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
str.WriteString(escapeByte(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// svcbParseParam parses a DNS presentation-format string into an SVCB parameter value.
|
|
||||||
func svcbParseParam(b string) ([]byte, error) {
|
|
||||||
data := make([]byte, 0, len(b))
|
|
||||||
for i := 0; i < len(b); {
|
|
||||||
if b[i] != '\\' {
|
|
||||||
data = append(data, b[i])
|
|
||||||
i++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if i+1 == len(b) {
|
|
||||||
return nil, errors.New("escape unterminated")
|
|
||||||
}
|
|
||||||
if isDigit(b[i+1]) {
|
|
||||||
if i+3 < len(b) && isDigit(b[i+2]) && isDigit(b[i+3]) {
|
|
||||||
a, err := strconv.ParseUint(b[i+1:i+4], 10, 8)
|
|
||||||
if err == nil {
|
|
||||||
i += 4
|
|
||||||
data = append(data, byte(a))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, errors.New("bad escaped octet")
|
|
||||||
} else {
|
|
||||||
data = append(data, b[i+1])
|
|
||||||
i += 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
|
9
vendor/github.com/miekg/dns/tools.go
generated
vendored
9
vendor/github.com/miekg/dns/tools.go
generated
vendored
@ -1,9 +0,0 @@
|
|||||||
// +build tools
|
|
||||||
|
|
||||||
// We include our tool dependencies for `go generate` here to ensure they're
|
|
||||||
// properly tracked by the go tool. See the Go Wiki for the rationale behind this:
|
|
||||||
// https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module.
|
|
||||||
|
|
||||||
package dns
|
|
||||||
|
|
||||||
import _ "golang.org/x/tools/go/packages"
|
|
65
vendor/github.com/miekg/dns/tsig.go
generated
vendored
65
vendor/github.com/miekg/dns/tsig.go
generated
vendored
@ -74,24 +74,6 @@ func (key tsigHMACProvider) Verify(msg []byte, t *TSIG) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type tsigSecretProvider map[string]string
|
|
||||||
|
|
||||||
func (ts tsigSecretProvider) Generate(msg []byte, t *TSIG) ([]byte, error) {
|
|
||||||
key, ok := ts[t.Hdr.Name]
|
|
||||||
if !ok {
|
|
||||||
return nil, ErrSecret
|
|
||||||
}
|
|
||||||
return tsigHMACProvider(key).Generate(msg, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts tsigSecretProvider) Verify(msg []byte, t *TSIG) error {
|
|
||||||
key, ok := ts[t.Hdr.Name]
|
|
||||||
if !ok {
|
|
||||||
return ErrSecret
|
|
||||||
}
|
|
||||||
return tsigHMACProvider(key).Verify(msg, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TSIG is the RR the holds the transaction signature of a message.
|
// TSIG is the RR the holds the transaction signature of a message.
|
||||||
// See RFC 2845 and RFC 4635.
|
// See RFC 2845 and RFC 4635.
|
||||||
type TSIG struct {
|
type TSIG struct {
|
||||||
@ -158,17 +140,18 @@ type timerWireFmt struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TsigGenerate fills out the TSIG record attached to the message.
|
// TsigGenerate fills out the TSIG record attached to the message.
|
||||||
// The message should contain a "stub" TSIG RR with the algorithm, key name
|
// The message should contain
|
||||||
// (owner name of the RR), time fudge (defaults to 300 seconds) and the current
|
// a "stub" TSIG RR with the algorithm, key name (owner name of the RR),
|
||||||
// time The TSIG MAC is saved in that Tsig RR. When TsigGenerate is called for
|
// time fudge (defaults to 300 seconds) and the current time
|
||||||
// the first time requestMAC should be set to the empty string and timersOnly to
|
// The TSIG MAC is saved in that Tsig RR.
|
||||||
// false.
|
// When TsigGenerate is called for the first time requestMAC is set to the empty string and
|
||||||
|
// timersOnly is false.
|
||||||
|
// If something goes wrong an error is returned, otherwise it is nil.
|
||||||
func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
|
func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
|
||||||
return TsigGenerateWithProvider(m, tsigHMACProvider(secret), requestMAC, timersOnly)
|
return tsigGenerateProvider(m, tsigHMACProvider(secret), requestMAC, timersOnly)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TsigGenerateWithProvider is similar to TsigGenerate, but allows for a custom TsigProvider.
|
func tsigGenerateProvider(m *Msg, provider TsigProvider, requestMAC string, timersOnly bool) ([]byte, string, error) {
|
||||||
func TsigGenerateWithProvider(m *Msg, provider TsigProvider, requestMAC string, timersOnly bool) ([]byte, string, error) {
|
|
||||||
if m.IsTsig() == nil {
|
if m.IsTsig() == nil {
|
||||||
panic("dns: TSIG not last RR in additional")
|
panic("dns: TSIG not last RR in additional")
|
||||||
}
|
}
|
||||||
@ -179,29 +162,20 @@ func TsigGenerateWithProvider(m *Msg, provider TsigProvider, requestMAC string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf, err := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
|
buf, err := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
t := new(TSIG)
|
t := new(TSIG)
|
||||||
// Copy all TSIG fields except MAC, its size, and time signed which are filled when signing.
|
// Copy all TSIG fields except MAC and its size, which are filled using the computed digest.
|
||||||
*t = *rr
|
*t = *rr
|
||||||
t.TimeSigned = 0
|
mac, err := provider.Generate(buf, rr)
|
||||||
t.MAC = ""
|
if err != nil {
|
||||||
t.MACSize = 0
|
return nil, "", err
|
||||||
|
|
||||||
// Sign unless there is a key or MAC validation error (RFC 8945 5.3.2)
|
|
||||||
if rr.Error != RcodeBadKey && rr.Error != RcodeBadSig {
|
|
||||||
mac, err := provider.Generate(buf, rr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
t.TimeSigned = rr.TimeSigned
|
|
||||||
t.MAC = hex.EncodeToString(mac)
|
|
||||||
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
|
|
||||||
}
|
}
|
||||||
|
t.MAC = hex.EncodeToString(mac)
|
||||||
|
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
|
||||||
|
|
||||||
tbuf := make([]byte, Len(t))
|
tbuf := make([]byte, Len(t))
|
||||||
off, err := PackRR(t, tbuf, 0, nil, false)
|
off, err := PackRR(t, tbuf, 0, nil, false)
|
||||||
@ -215,15 +189,14 @@ func TsigGenerateWithProvider(m *Msg, provider TsigProvider, requestMAC string,
|
|||||||
return mbuf, t.MAC, nil
|
return mbuf, t.MAC, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TsigVerify verifies the TSIG on a message. If the signature does not
|
// TsigVerify verifies the TSIG on a message.
|
||||||
// validate the returned error contains the cause. If the signature is OK, the
|
// If the signature does not validate err contains the
|
||||||
// error is nil.
|
// error, otherwise it is nil.
|
||||||
func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
|
func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
|
||||||
return tsigVerify(msg, tsigHMACProvider(secret), requestMAC, timersOnly, uint64(time.Now().Unix()))
|
return tsigVerify(msg, tsigHMACProvider(secret), requestMAC, timersOnly, uint64(time.Now().Unix()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TsigVerifyWithProvider is similar to TsigVerify, but allows for a custom TsigProvider.
|
func tsigVerifyProvider(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool) error {
|
||||||
func TsigVerifyWithProvider(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool) error {
|
|
||||||
return tsigVerify(msg, provider, requestMAC, timersOnly, uint64(time.Now().Unix()))
|
return tsigVerify(msg, provider, requestMAC, timersOnly, uint64(time.Now().Unix()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
vendor/github.com/miekg/dns/update.go
generated
vendored
4
vendor/github.com/miekg/dns/update.go
generated
vendored
@ -32,9 +32,7 @@ func (u *Msg) Used(rr []RR) {
|
|||||||
u.Answer = make([]RR, 0, len(rr))
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
}
|
}
|
||||||
for _, r := range rr {
|
for _, r := range rr {
|
||||||
hdr := r.Header()
|
r.Header().Class = u.Question[0].Qclass
|
||||||
hdr.Class = u.Question[0].Qclass
|
|
||||||
hdr.Ttl = 0
|
|
||||||
u.Answer = append(u.Answer, r)
|
u.Answer = append(u.Answer, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
vendor/github.com/miekg/dns/version.go
generated
vendored
2
vendor/github.com/miekg/dns/version.go
generated
vendored
@ -3,7 +3,7 @@ package dns
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
// Version is current version of this library.
|
// Version is current version of this library.
|
||||||
var Version = v{1, 1, 50}
|
var Version = v{1, 1, 43}
|
||||||
|
|
||||||
// v holds the version of this library.
|
// v holds the version of this library.
|
||||||
type v struct {
|
type v struct {
|
||||||
|
27
vendor/github.com/miekg/dns/xfr.go
generated
vendored
27
vendor/github.com/miekg/dns/xfr.go
generated
vendored
@ -17,22 +17,11 @@ type Transfer struct {
|
|||||||
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
|
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
|
||||||
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
|
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
|
||||||
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
|
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
|
||||||
TsigProvider TsigProvider // An implementation of the TsigProvider interface. If defined it replaces TsigSecret and is used for all TSIG operations.
|
|
||||||
TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
|
TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
|
||||||
tsigTimersOnly bool
|
tsigTimersOnly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transfer) tsigProvider() TsigProvider {
|
// Think we need to away to stop the transfer
|
||||||
if t.TsigProvider != nil {
|
|
||||||
return t.TsigProvider
|
|
||||||
}
|
|
||||||
if t.TsigSecret != nil {
|
|
||||||
return tsigSecretProvider(t.TsigSecret)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Think we need to away to stop the transfer
|
|
||||||
|
|
||||||
// In performs an incoming transfer with the server in a.
|
// In performs an incoming transfer with the server in a.
|
||||||
// If you would like to set the source IP, or some other attribute
|
// If you would like to set the source IP, or some other attribute
|
||||||
@ -235,9 +224,12 @@ func (t *Transfer) ReadMsg() (*Msg, error) {
|
|||||||
if err := m.Unpack(p); err != nil {
|
if err := m.Unpack(p); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if ts, tp := m.IsTsig(), t.tsigProvider(); ts != nil && tp != nil {
|
if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
|
||||||
|
if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
|
||||||
|
return m, ErrSecret
|
||||||
|
}
|
||||||
// Need to work on the original message p, as that was used to calculate the tsig.
|
// Need to work on the original message p, as that was used to calculate the tsig.
|
||||||
err = TsigVerifyWithProvider(p, tp, t.tsigRequestMAC, t.tsigTimersOnly)
|
err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
|
||||||
t.tsigRequestMAC = ts.MAC
|
t.tsigRequestMAC = ts.MAC
|
||||||
}
|
}
|
||||||
return m, err
|
return m, err
|
||||||
@ -246,8 +238,11 @@ func (t *Transfer) ReadMsg() (*Msg, error) {
|
|||||||
// WriteMsg writes a message through the transfer connection t.
|
// WriteMsg writes a message through the transfer connection t.
|
||||||
func (t *Transfer) WriteMsg(m *Msg) (err error) {
|
func (t *Transfer) WriteMsg(m *Msg) (err error) {
|
||||||
var out []byte
|
var out []byte
|
||||||
if ts, tp := m.IsTsig(), t.tsigProvider(); ts != nil && tp != nil {
|
if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
|
||||||
out, t.tsigRequestMAC, err = TsigGenerateWithProvider(m, tp, t.tsigRequestMAC, t.tsigTimersOnly)
|
if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
|
||||||
|
return ErrSecret
|
||||||
|
}
|
||||||
|
out, t.tsigRequestMAC, err = TsigGenerate(m, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
|
||||||
} else {
|
} else {
|
||||||
out, err = m.Pack()
|
out, err = m.Pack()
|
||||||
}
|
}
|
||||||
|
27
vendor/golang.org/x/mod/LICENSE
generated
vendored
27
vendor/golang.org/x/mod/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
22
vendor/golang.org/x/mod/PATENTS
generated
vendored
22
vendor/golang.org/x/mod/PATENTS
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
401
vendor/golang.org/x/mod/semver/semver.go
generated
vendored
401
vendor/golang.org/x/mod/semver/semver.go
generated
vendored
@ -1,401 +0,0 @@
|
|||||||
// Copyright 2018 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 semver implements comparison of semantic version strings.
|
|
||||||
// In this package, semantic version strings must begin with a leading "v",
|
|
||||||
// as in "v1.0.0".
|
|
||||||
//
|
|
||||||
// The general form of a semantic version string accepted by this package is
|
|
||||||
//
|
|
||||||
// vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]]
|
|
||||||
//
|
|
||||||
// where square brackets indicate optional parts of the syntax;
|
|
||||||
// MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros;
|
|
||||||
// PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers
|
|
||||||
// using only alphanumeric characters and hyphens; and
|
|
||||||
// all-numeric PRERELEASE identifiers must not have leading zeros.
|
|
||||||
//
|
|
||||||
// This package follows Semantic Versioning 2.0.0 (see semver.org)
|
|
||||||
// with two exceptions. First, it requires the "v" prefix. Second, it recognizes
|
|
||||||
// vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes)
|
|
||||||
// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
|
|
||||||
package semver
|
|
||||||
|
|
||||||
import "sort"
|
|
||||||
|
|
||||||
// parsed returns the parsed form of a semantic version string.
|
|
||||||
type parsed struct {
|
|
||||||
major string
|
|
||||||
minor string
|
|
||||||
patch string
|
|
||||||
short string
|
|
||||||
prerelease string
|
|
||||||
build string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsValid reports whether v is a valid semantic version string.
|
|
||||||
func IsValid(v string) bool {
|
|
||||||
_, ok := parse(v)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canonical returns the canonical formatting of the semantic version v.
|
|
||||||
// It fills in any missing .MINOR or .PATCH and discards build metadata.
|
|
||||||
// Two semantic versions compare equal only if their canonical formattings
|
|
||||||
// are identical strings.
|
|
||||||
// The canonical invalid semantic version is the empty string.
|
|
||||||
func Canonical(v string) string {
|
|
||||||
p, ok := parse(v)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if p.build != "" {
|
|
||||||
return v[:len(v)-len(p.build)]
|
|
||||||
}
|
|
||||||
if p.short != "" {
|
|
||||||
return v + p.short
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// Major returns the major version prefix of the semantic version v.
|
|
||||||
// For example, Major("v2.1.0") == "v2".
|
|
||||||
// If v is an invalid semantic version string, Major returns the empty string.
|
|
||||||
func Major(v string) string {
|
|
||||||
pv, ok := parse(v)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return v[:1+len(pv.major)]
|
|
||||||
}
|
|
||||||
|
|
||||||
// MajorMinor returns the major.minor version prefix of the semantic version v.
|
|
||||||
// For example, MajorMinor("v2.1.0") == "v2.1".
|
|
||||||
// If v is an invalid semantic version string, MajorMinor returns the empty string.
|
|
||||||
func MajorMinor(v string) string {
|
|
||||||
pv, ok := parse(v)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
i := 1 + len(pv.major)
|
|
||||||
if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor {
|
|
||||||
return v[:j]
|
|
||||||
}
|
|
||||||
return v[:i] + "." + pv.minor
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prerelease returns the prerelease suffix of the semantic version v.
|
|
||||||
// For example, Prerelease("v2.1.0-pre+meta") == "-pre".
|
|
||||||
// If v is an invalid semantic version string, Prerelease returns the empty string.
|
|
||||||
func Prerelease(v string) string {
|
|
||||||
pv, ok := parse(v)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return pv.prerelease
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build returns the build suffix of the semantic version v.
|
|
||||||
// For example, Build("v2.1.0+meta") == "+meta".
|
|
||||||
// If v is an invalid semantic version string, Build returns the empty string.
|
|
||||||
func Build(v string) string {
|
|
||||||
pv, ok := parse(v)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return pv.build
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare returns an integer comparing two versions according to
|
|
||||||
// semantic version precedence.
|
|
||||||
// The result will be 0 if v == w, -1 if v < w, or +1 if v > w.
|
|
||||||
//
|
|
||||||
// An invalid semantic version string is considered less than a valid one.
|
|
||||||
// All invalid semantic version strings compare equal to each other.
|
|
||||||
func Compare(v, w string) int {
|
|
||||||
pv, ok1 := parse(v)
|
|
||||||
pw, ok2 := parse(w)
|
|
||||||
if !ok1 && !ok2 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if !ok1 {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if !ok2 {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
if c := compareInt(pv.major, pw.major); c != 0 {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
if c := compareInt(pv.minor, pw.minor); c != 0 {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
if c := compareInt(pv.patch, pw.patch); c != 0 {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
return comparePrerelease(pv.prerelease, pw.prerelease)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max canonicalizes its arguments and then returns the version string
|
|
||||||
// that compares greater.
|
|
||||||
//
|
|
||||||
// Deprecated: use Compare instead. In most cases, returning a canonicalized
|
|
||||||
// version is not expected or desired.
|
|
||||||
func Max(v, w string) string {
|
|
||||||
v = Canonical(v)
|
|
||||||
w = Canonical(w)
|
|
||||||
if Compare(v, w) > 0 {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByVersion implements sort.Interface for sorting semantic version strings.
|
|
||||||
type ByVersion []string
|
|
||||||
|
|
||||||
func (vs ByVersion) Len() int { return len(vs) }
|
|
||||||
func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
|
|
||||||
func (vs ByVersion) Less(i, j int) bool {
|
|
||||||
cmp := Compare(vs[i], vs[j])
|
|
||||||
if cmp != 0 {
|
|
||||||
return cmp < 0
|
|
||||||
}
|
|
||||||
return vs[i] < vs[j]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort sorts a list of semantic version strings using ByVersion.
|
|
||||||
func Sort(list []string) {
|
|
||||||
sort.Sort(ByVersion(list))
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(v string) (p parsed, ok bool) {
|
|
||||||
if v == "" || v[0] != 'v' {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.major, v, ok = parseInt(v[1:])
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v == "" {
|
|
||||||
p.minor = "0"
|
|
||||||
p.patch = "0"
|
|
||||||
p.short = ".0.0"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[0] != '.' {
|
|
||||||
ok = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.minor, v, ok = parseInt(v[1:])
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v == "" {
|
|
||||||
p.patch = "0"
|
|
||||||
p.short = ".0"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[0] != '.' {
|
|
||||||
ok = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.patch, v, ok = parseInt(v[1:])
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(v) > 0 && v[0] == '-' {
|
|
||||||
p.prerelease, v, ok = parsePrerelease(v)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(v) > 0 && v[0] == '+' {
|
|
||||||
p.build, v, ok = parseBuild(v)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v != "" {
|
|
||||||
ok = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ok = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseInt(v string) (t, rest string, ok bool) {
|
|
||||||
if v == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[0] < '0' || '9' < v[0] {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
i := 1
|
|
||||||
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if v[0] == '0' && i != 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return v[:i], v[i:], true
|
|
||||||
}
|
|
||||||
|
|
||||||
func parsePrerelease(v string) (t, rest string, ok bool) {
|
|
||||||
// "A pre-release version MAY be denoted by appending a hyphen and
|
|
||||||
// a series of dot separated identifiers immediately following the patch version.
|
|
||||||
// Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-].
|
|
||||||
// Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes."
|
|
||||||
if v == "" || v[0] != '-' {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
i := 1
|
|
||||||
start := 1
|
|
||||||
for i < len(v) && v[i] != '+' {
|
|
||||||
if !isIdentChar(v[i]) && v[i] != '.' {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[i] == '.' {
|
|
||||||
if start == i || isBadNum(v[start:i]) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
start = i + 1
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if start == i || isBadNum(v[start:i]) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return v[:i], v[i:], true
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseBuild(v string) (t, rest string, ok bool) {
|
|
||||||
if v == "" || v[0] != '+' {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
i := 1
|
|
||||||
start := 1
|
|
||||||
for i < len(v) {
|
|
||||||
if !isIdentChar(v[i]) && v[i] != '.' {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[i] == '.' {
|
|
||||||
if start == i {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
start = i + 1
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if start == i {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return v[:i], v[i:], true
|
|
||||||
}
|
|
||||||
|
|
||||||
func isIdentChar(c byte) bool {
|
|
||||||
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-'
|
|
||||||
}
|
|
||||||
|
|
||||||
func isBadNum(v string) bool {
|
|
||||||
i := 0
|
|
||||||
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return i == len(v) && i > 1 && v[0] == '0'
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNum(v string) bool {
|
|
||||||
i := 0
|
|
||||||
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return i == len(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func compareInt(x, y string) int {
|
|
||||||
if x == y {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if len(x) < len(y) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if len(x) > len(y) {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
if x < y {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func comparePrerelease(x, y string) int {
|
|
||||||
// "When major, minor, and patch are equal, a pre-release version has
|
|
||||||
// lower precedence than a normal version.
|
|
||||||
// Example: 1.0.0-alpha < 1.0.0.
|
|
||||||
// Precedence for two pre-release versions with the same major, minor,
|
|
||||||
// and patch version MUST be determined by comparing each dot separated
|
|
||||||
// identifier from left to right until a difference is found as follows:
|
|
||||||
// identifiers consisting of only digits are compared numerically and
|
|
||||||
// identifiers with letters or hyphens are compared lexically in ASCII
|
|
||||||
// sort order. Numeric identifiers always have lower precedence than
|
|
||||||
// non-numeric identifiers. A larger set of pre-release fields has a
|
|
||||||
// higher precedence than a smaller set, if all of the preceding
|
|
||||||
// identifiers are equal.
|
|
||||||
// Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta <
|
|
||||||
// 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0."
|
|
||||||
if x == y {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if x == "" {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
if y == "" {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
for x != "" && y != "" {
|
|
||||||
x = x[1:] // skip - or .
|
|
||||||
y = y[1:] // skip - or .
|
|
||||||
var dx, dy string
|
|
||||||
dx, x = nextIdent(x)
|
|
||||||
dy, y = nextIdent(y)
|
|
||||||
if dx != dy {
|
|
||||||
ix := isNum(dx)
|
|
||||||
iy := isNum(dy)
|
|
||||||
if ix != iy {
|
|
||||||
if ix {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ix {
|
|
||||||
if len(dx) < len(dy) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if len(dx) > len(dy) {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if dx < dy {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x == "" {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func nextIdent(x string) (dx, rest string) {
|
|
||||||
i := 0
|
|
||||||
for i < len(x) && x[i] != '.' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return x[:i], x[i:]
|
|
||||||
}
|
|
3
vendor/golang.org/x/net/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/net/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# This source code refers to The Go Authors for copyright purposes.
|
||||||
|
# The master list of authors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/AUTHORS.
|
3
vendor/golang.org/x/net/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/net/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# This source code was written by the Go contributors.
|
||||||
|
# The master list of contributors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/CONTRIBUTORS.
|
6
vendor/golang.org/x/net/bpf/doc.go
generated
vendored
6
vendor/golang.org/x/net/bpf/doc.go
generated
vendored
@ -3,6 +3,7 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Package bpf implements marshaling and unmarshaling of programs for the
|
Package bpf implements marshaling and unmarshaling of programs for the
|
||||||
Berkeley Packet Filter virtual machine, and provides a Go implementation
|
Berkeley Packet Filter virtual machine, and provides a Go implementation
|
||||||
of the virtual machine.
|
of the virtual machine.
|
||||||
@ -20,7 +21,7 @@ access to kernel functions, and while conditional branches are
|
|||||||
allowed, they can only jump forwards, to guarantee that there are no
|
allowed, they can only jump forwards, to guarantee that there are no
|
||||||
infinite loops.
|
infinite loops.
|
||||||
|
|
||||||
# The virtual machine
|
The virtual machine
|
||||||
|
|
||||||
The BPF VM is an accumulator machine. Its main register, called
|
The BPF VM is an accumulator machine. Its main register, called
|
||||||
register A, is an implicit source and destination in all arithmetic
|
register A, is an implicit source and destination in all arithmetic
|
||||||
@ -49,7 +50,7 @@ to extensions, which are essentially calls to kernel utility
|
|||||||
functions. Currently, the only extensions supported by this package
|
functions. Currently, the only extensions supported by this package
|
||||||
are the Linux packet filter extensions.
|
are the Linux packet filter extensions.
|
||||||
|
|
||||||
# Examples
|
Examples
|
||||||
|
|
||||||
This packet filter selects all ARP packets.
|
This packet filter selects all ARP packets.
|
||||||
|
|
||||||
@ -76,5 +77,6 @@ This packet filter captures a random 1% sample of traffic.
|
|||||||
// Ignore.
|
// Ignore.
|
||||||
bpf.RetConstant{Val: 0},
|
bpf.RetConstant{Val: 0},
|
||||||
})
|
})
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package bpf // import "golang.org/x/net/bpf"
|
package bpf // import "golang.org/x/net/bpf"
|
||||||
|
4
vendor/golang.org/x/net/bpf/vm_instructions.go
generated
vendored
4
vendor/golang.org/x/net/bpf/vm_instructions.go
generated
vendored
@ -94,7 +94,7 @@ func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value u
|
|||||||
|
|
||||||
func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
|
func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
|
||||||
offset := int(ins.Off)
|
offset := int(ins.Off)
|
||||||
size := ins.Size
|
size := int(ins.Size)
|
||||||
|
|
||||||
return loadCommon(in, offset, size)
|
return loadCommon(in, offset, size)
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ func loadExtension(ins LoadExtension, in []byte) uint32 {
|
|||||||
|
|
||||||
func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
|
func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
|
||||||
offset := int(ins.Off) + int(regX)
|
offset := int(ins.Off) + int(regX)
|
||||||
size := ins.Size
|
size := int(ins.Size)
|
||||||
|
|
||||||
return loadCommon(in, offset, size)
|
return loadCommon(in, offset, size)
|
||||||
}
|
}
|
||||||
|
4
vendor/golang.org/x/net/internal/socket/cmsghdr_linux_64bit.go
generated
vendored
4
vendor/golang.org/x/net/internal/socket/cmsghdr_linux_64bit.go
generated
vendored
@ -2,8 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
|
//go:build (arm64 || amd64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
|
||||||
// +build arm64 amd64 loong64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||||
// +build linux
|
// +build linux
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
4
vendor/golang.org/x/net/internal/socket/cmsghdr_unix.go
generated
vendored
4
vendor/golang.org/x/net/internal/socket/cmsghdr_unix.go
generated
vendored
@ -2,8 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
|
14
vendor/golang.org/x/net/internal/socket/cmsghdr_zos_s390x.go
generated
vendored
14
vendor/golang.org/x/net/internal/socket/cmsghdr_zos_s390x.go
generated
vendored
@ -4,8 +4,22 @@
|
|||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
func (h *cmsghdr) set(l, lvl, typ int) {
|
func (h *cmsghdr) set(l, lvl, typ int) {
|
||||||
h.Len = int32(l)
|
h.Len = int32(l)
|
||||||
h.Level = int32(lvl)
|
h.Level = int32(lvl)
|
||||||
h.Type = int32(typ)
|
h.Type = int32(typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func controlHeaderLen() int {
|
||||||
|
return syscall.CmsgLen(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func controlMessageLen(dataLen int) int {
|
||||||
|
return syscall.CmsgLen(dataLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func controlMessageSpace(dataLen int) int {
|
||||||
|
return syscall.CmsgSpace(dataLen)
|
||||||
|
}
|
||||||
|
4
vendor/golang.org/x/net/internal/socket/iovec_64bit.go
generated
vendored
4
vendor/golang.org/x/net/internal/socket/iovec_64bit.go
generated
vendored
@ -2,8 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || zos)
|
//go:build (arm64 || amd64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || zos)
|
||||||
// +build arm64 amd64 loong64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd zos
|
// +build aix darwin dragonfly freebsd linux netbsd openbsd zos
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
96
vendor/golang.org/x/net/internal/socket/mmsghdr_unix.go
generated
vendored
96
vendor/golang.org/x/net/internal/socket/mmsghdr_unix.go
generated
vendored
@ -9,9 +9,7 @@ package socket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type mmsghdrs []mmsghdr
|
type mmsghdrs []mmsghdr
|
||||||
@ -95,102 +93,22 @@ func (p *mmsghdrsPacker) pack(ms []Message, parseFn func([]byte, string) (net.Ad
|
|||||||
return hs
|
return hs
|
||||||
}
|
}
|
||||||
|
|
||||||
// syscaller is a helper to invoke recvmmsg and sendmmsg via the RawConn.Read/Write interface.
|
var defaultMmsghdrsPool = mmsghdrsPool{
|
||||||
// It is reusable, to amortize the overhead of allocating a closure for the function passed to
|
|
||||||
// RawConn.Read/Write.
|
|
||||||
type syscaller struct {
|
|
||||||
n int
|
|
||||||
operr error
|
|
||||||
hs mmsghdrs
|
|
||||||
flags int
|
|
||||||
|
|
||||||
boundRecvmmsgF func(uintptr) bool
|
|
||||||
boundSendmmsgF func(uintptr) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *syscaller) init() {
|
|
||||||
r.boundRecvmmsgF = r.recvmmsgF
|
|
||||||
r.boundSendmmsgF = r.sendmmsgF
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *syscaller) recvmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
|
|
||||||
r.n = 0
|
|
||||||
r.operr = nil
|
|
||||||
r.hs = hs
|
|
||||||
r.flags = flags
|
|
||||||
if err := c.Read(r.boundRecvmmsgF); err != nil {
|
|
||||||
return r.n, err
|
|
||||||
}
|
|
||||||
if r.operr != nil {
|
|
||||||
return r.n, os.NewSyscallError("recvmmsg", r.operr)
|
|
||||||
}
|
|
||||||
return r.n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *syscaller) recvmmsgF(s uintptr) bool {
|
|
||||||
r.n, r.operr = recvmmsg(s, r.hs, r.flags)
|
|
||||||
return ioComplete(r.flags, r.operr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *syscaller) sendmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
|
|
||||||
r.n = 0
|
|
||||||
r.operr = nil
|
|
||||||
r.hs = hs
|
|
||||||
r.flags = flags
|
|
||||||
if err := c.Write(r.boundSendmmsgF); err != nil {
|
|
||||||
return r.n, err
|
|
||||||
}
|
|
||||||
if r.operr != nil {
|
|
||||||
return r.n, os.NewSyscallError("sendmmsg", r.operr)
|
|
||||||
}
|
|
||||||
return r.n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *syscaller) sendmmsgF(s uintptr) bool {
|
|
||||||
r.n, r.operr = sendmmsg(s, r.hs, r.flags)
|
|
||||||
return ioComplete(r.flags, r.operr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// mmsgTmps holds reusable temporary helpers for recvmmsg and sendmmsg.
|
|
||||||
type mmsgTmps struct {
|
|
||||||
packer mmsghdrsPacker
|
|
||||||
syscaller syscaller
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultMmsgTmpsPool = mmsgTmpsPool{
|
|
||||||
p: sync.Pool{
|
p: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
tmps := new(mmsgTmps)
|
return new(mmsghdrsPacker)
|
||||||
tmps.syscaller.init()
|
|
||||||
return tmps
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type mmsgTmpsPool struct {
|
type mmsghdrsPool struct {
|
||||||
p sync.Pool
|
p sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *mmsgTmpsPool) Get() *mmsgTmps {
|
func (p *mmsghdrsPool) Get() *mmsghdrsPacker {
|
||||||
m := p.p.Get().(*mmsgTmps)
|
return p.p.Get().(*mmsghdrsPacker)
|
||||||
// Clear fields up to the len (not the cap) of the slice,
|
|
||||||
// assuming that the previous caller only used that many elements.
|
|
||||||
for i := range m.packer.sockaddrs {
|
|
||||||
m.packer.sockaddrs[i] = 0
|
|
||||||
}
|
|
||||||
m.packer.sockaddrs = m.packer.sockaddrs[:0]
|
|
||||||
for i := range m.packer.vs {
|
|
||||||
m.packer.vs[i] = iovec{}
|
|
||||||
}
|
|
||||||
m.packer.vs = m.packer.vs[:0]
|
|
||||||
for i := range m.packer.hs {
|
|
||||||
m.packer.hs[i].Len = 0
|
|
||||||
m.packer.hs[i].Hdr = msghdr{}
|
|
||||||
}
|
|
||||||
m.packer.hs = m.packer.hs[:0]
|
|
||||||
return m
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *mmsgTmpsPool) Put(tmps *mmsgTmps) {
|
func (p *mmsghdrsPool) Put(packer *mmsghdrsPacker) {
|
||||||
p.p.Put(tmps)
|
p.p.Put(packer)
|
||||||
}
|
}
|
||||||
|
3
vendor/golang.org/x/net/internal/socket/msghdr_linux.go
generated
vendored
3
vendor/golang.org/x/net/internal/socket/msghdr_linux.go
generated
vendored
@ -17,6 +17,9 @@ func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
|
|||||||
if sa != nil {
|
if sa != nil {
|
||||||
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
|
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
|
||||||
h.Namelen = uint32(len(sa))
|
h.Namelen = uint32(len(sa))
|
||||||
|
} else {
|
||||||
|
h.Name = nil
|
||||||
|
h.Namelen = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
vendor/golang.org/x/net/internal/socket/msghdr_linux_64bit.go
generated
vendored
4
vendor/golang.org/x/net/internal/socket/msghdr_linux_64bit.go
generated
vendored
@ -2,8 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
|
//go:build (arm64 || amd64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
|
||||||
// +build arm64 amd64 loong64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||||
// +build linux
|
// +build linux
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
37
vendor/golang.org/x/net/internal/socket/rawconn_mmsg.go
generated
vendored
37
vendor/golang.org/x/net/internal/socket/rawconn_mmsg.go
generated
vendored
@ -9,23 +9,32 @@ package socket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
|
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
|
||||||
for i := range ms {
|
for i := range ms {
|
||||||
ms[i].raceWrite()
|
ms[i].raceWrite()
|
||||||
}
|
}
|
||||||
tmps := defaultMmsgTmpsPool.Get()
|
packer := defaultMmsghdrsPool.Get()
|
||||||
defer defaultMmsgTmpsPool.Put(tmps)
|
defer defaultMmsghdrsPool.Put(packer)
|
||||||
var parseFn func([]byte, string) (net.Addr, error)
|
var parseFn func([]byte, string) (net.Addr, error)
|
||||||
if c.network != "tcp" {
|
if c.network != "tcp" {
|
||||||
parseFn = parseInetAddr
|
parseFn = parseInetAddr
|
||||||
}
|
}
|
||||||
hs := tmps.packer.pack(ms, parseFn, nil)
|
hs := packer.pack(ms, parseFn, nil)
|
||||||
n, err := tmps.syscaller.recvmmsg(c.c, hs, flags)
|
var operr error
|
||||||
if err != nil {
|
var n int
|
||||||
|
fn := func(s uintptr) bool {
|
||||||
|
n, operr = recvmmsg(s, hs, flags)
|
||||||
|
return ioComplete(flags, operr)
|
||||||
|
}
|
||||||
|
if err := c.c.Read(fn); err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
if operr != nil {
|
||||||
|
return n, os.NewSyscallError("recvmmsg", operr)
|
||||||
|
}
|
||||||
if err := hs[:n].unpack(ms[:n], parseFn, c.network); err != nil {
|
if err := hs[:n].unpack(ms[:n], parseFn, c.network); err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
@ -36,17 +45,25 @@ func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
|
|||||||
for i := range ms {
|
for i := range ms {
|
||||||
ms[i].raceRead()
|
ms[i].raceRead()
|
||||||
}
|
}
|
||||||
tmps := defaultMmsgTmpsPool.Get()
|
packer := defaultMmsghdrsPool.Get()
|
||||||
defer defaultMmsgTmpsPool.Put(tmps)
|
defer defaultMmsghdrsPool.Put(packer)
|
||||||
var marshalFn func(net.Addr, []byte) int
|
var marshalFn func(net.Addr, []byte) int
|
||||||
if c.network != "tcp" {
|
if c.network != "tcp" {
|
||||||
marshalFn = marshalInetAddr
|
marshalFn = marshalInetAddr
|
||||||
}
|
}
|
||||||
hs := tmps.packer.pack(ms, nil, marshalFn)
|
hs := packer.pack(ms, nil, marshalFn)
|
||||||
n, err := tmps.syscaller.sendmmsg(c.c, hs, flags)
|
var operr error
|
||||||
if err != nil {
|
var n int
|
||||||
|
fn := func(s uintptr) bool {
|
||||||
|
n, operr = sendmmsg(s, hs, flags)
|
||||||
|
return ioComplete(flags, operr)
|
||||||
|
}
|
||||||
|
if err := c.c.Write(fn); err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
if operr != nil {
|
||||||
|
return n, os.NewSyscallError("sendmmsg", operr)
|
||||||
|
}
|
||||||
if err := hs[:n].unpack(ms[:n], nil, ""); err != nil {
|
if err := hs[:n].unpack(ms[:n], nil, ""); err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
48
vendor/golang.org/x/net/internal/socket/rawconn_msg.go
generated
vendored
48
vendor/golang.org/x/net/internal/socket/rawconn_msg.go
generated
vendored
@ -8,21 +8,22 @@
|
|||||||
package socket
|
package socket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Conn) recvMsg(m *Message, flags int) error {
|
func (c *Conn) recvMsg(m *Message, flags int) error {
|
||||||
m.raceWrite()
|
m.raceWrite()
|
||||||
var (
|
var h msghdr
|
||||||
operr error
|
vs := make([]iovec, len(m.Buffers))
|
||||||
n int
|
var sa []byte
|
||||||
oobn int
|
if c.network != "tcp" {
|
||||||
recvflags int
|
sa = make([]byte, sizeofSockaddrInet6)
|
||||||
from net.Addr
|
}
|
||||||
)
|
h.pack(vs, m.Buffers, m.OOB, sa)
|
||||||
|
var operr error
|
||||||
|
var n int
|
||||||
fn := func(s uintptr) bool {
|
fn := func(s uintptr) bool {
|
||||||
n, oobn, recvflags, from, operr = recvmsg(s, m.Buffers, m.OOB, flags, c.network)
|
n, operr = recvmsg(s, &h, flags)
|
||||||
return ioComplete(flags, operr)
|
return ioComplete(flags, operr)
|
||||||
}
|
}
|
||||||
if err := c.c.Read(fn); err != nil {
|
if err := c.c.Read(fn); err != nil {
|
||||||
@ -31,21 +32,34 @@ func (c *Conn) recvMsg(m *Message, flags int) error {
|
|||||||
if operr != nil {
|
if operr != nil {
|
||||||
return os.NewSyscallError("recvmsg", operr)
|
return os.NewSyscallError("recvmsg", operr)
|
||||||
}
|
}
|
||||||
m.Addr = from
|
if c.network != "tcp" {
|
||||||
|
var err error
|
||||||
|
m.Addr, err = parseInetAddr(sa[:], c.network)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
m.N = n
|
m.N = n
|
||||||
m.NN = oobn
|
m.NN = h.controllen()
|
||||||
m.Flags = recvflags
|
m.Flags = h.flags()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) sendMsg(m *Message, flags int) error {
|
func (c *Conn) sendMsg(m *Message, flags int) error {
|
||||||
m.raceRead()
|
m.raceRead()
|
||||||
var (
|
var h msghdr
|
||||||
operr error
|
vs := make([]iovec, len(m.Buffers))
|
||||||
n int
|
var sa []byte
|
||||||
)
|
if m.Addr != nil {
|
||||||
|
var a [sizeofSockaddrInet6]byte
|
||||||
|
n := marshalInetAddr(m.Addr, a[:])
|
||||||
|
sa = a[:n]
|
||||||
|
}
|
||||||
|
h.pack(vs, m.Buffers, m.OOB, sa)
|
||||||
|
var operr error
|
||||||
|
var n int
|
||||||
fn := func(s uintptr) bool {
|
fn := func(s uintptr) bool {
|
||||||
n, operr = sendmsg(s, m.Buffers, m.OOB, m.Addr, flags)
|
n, operr = sendmsg(s, &h, flags)
|
||||||
return ioComplete(flags, operr)
|
return ioComplete(flags, operr)
|
||||||
}
|
}
|
||||||
if err := c.c.Write(fn); err != nil {
|
if err := c.c.Write(fn); err != nil {
|
||||||
|
13
vendor/golang.org/x/net/internal/socket/sys_linux_loong64.go
generated
vendored
13
vendor/golang.org/x/net/internal/socket/sys_linux_loong64.go
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
// Copyright 2021 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 loong64
|
|
||||||
// +build loong64
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysRECVMMSG = 0xf3
|
|
||||||
sysSENDMMSG = 0x10d
|
|
||||||
)
|
|
6
vendor/golang.org/x/net/internal/socket/sys_stub.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/sys_stub.go
generated
vendored
@ -36,11 +36,11 @@ func setsockopt(s uintptr, level, name int, b []byte) error {
|
|||||||
return errNotImplemented
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvmsg(s uintptr, buffers [][]byte, oob []byte, flags int, network string) (n, oobn int, recvflags int, from net.Addr, err error) {
|
func recvmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
return 0, 0, 0, nil, errNotImplemented
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendmsg(s uintptr, buffers [][]byte, oob []byte, to net.Addr, flags int) (int, error) {
|
func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
return 0, errNotImplemented
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
101
vendor/golang.org/x/net/internal/socket/sys_unix.go
generated
vendored
101
vendor/golang.org/x/net/internal/socket/sys_unix.go
generated
vendored
@ -8,10 +8,8 @@
|
|||||||
package socket
|
package socket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:linkname syscall_getsockopt syscall.getsockopt
|
//go:linkname syscall_getsockopt syscall.getsockopt
|
||||||
@ -20,6 +18,12 @@ func syscall_getsockopt(s, level, name int, val unsafe.Pointer, vallen *uint32)
|
|||||||
//go:linkname syscall_setsockopt syscall.setsockopt
|
//go:linkname syscall_setsockopt syscall.setsockopt
|
||||||
func syscall_setsockopt(s, level, name int, val unsafe.Pointer, vallen uintptr) error
|
func syscall_setsockopt(s, level, name int, val unsafe.Pointer, vallen uintptr) error
|
||||||
|
|
||||||
|
//go:linkname syscall_recvmsg syscall.recvmsg
|
||||||
|
func syscall_recvmsg(s int, msg *syscall.Msghdr, flags int) (int, error)
|
||||||
|
|
||||||
|
//go:linkname syscall_sendmsg syscall.sendmsg
|
||||||
|
func syscall_sendmsg(s int, msg *syscall.Msghdr, flags int) (int, error)
|
||||||
|
|
||||||
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
|
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
|
||||||
l := uint32(len(b))
|
l := uint32(len(b))
|
||||||
err := syscall_getsockopt(int(s), level, name, unsafe.Pointer(&b[0]), &l)
|
err := syscall_getsockopt(int(s), level, name, unsafe.Pointer(&b[0]), &l)
|
||||||
@ -30,93 +34,10 @@ func setsockopt(s uintptr, level, name int, b []byte) error {
|
|||||||
return syscall_setsockopt(int(s), level, name, unsafe.Pointer(&b[0]), uintptr(len(b)))
|
return syscall_setsockopt(int(s), level, name, unsafe.Pointer(&b[0]), uintptr(len(b)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvmsg(s uintptr, buffers [][]byte, oob []byte, flags int, network string) (n, oobn int, recvflags int, from net.Addr, err error) {
|
func recvmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
var unixFrom unix.Sockaddr
|
return syscall_recvmsg(int(s), (*syscall.Msghdr)(unsafe.Pointer(h)), flags)
|
||||||
n, oobn, recvflags, unixFrom, err = unix.RecvmsgBuffers(int(s), buffers, oob, flags)
|
|
||||||
if unixFrom != nil {
|
|
||||||
from = sockaddrToAddr(unixFrom, network)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendmsg(s uintptr, buffers [][]byte, oob []byte, to net.Addr, flags int) (int, error) {
|
func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
var unixTo unix.Sockaddr
|
return syscall_sendmsg(int(s), (*syscall.Msghdr)(unsafe.Pointer(h)), flags)
|
||||||
if to != nil {
|
|
||||||
unixTo = addrToSockaddr(to)
|
|
||||||
}
|
|
||||||
return unix.SendmsgBuffers(int(s), buffers, oob, unixTo, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// addrToSockaddr converts a net.Addr to a unix.Sockaddr.
|
|
||||||
func addrToSockaddr(a net.Addr) unix.Sockaddr {
|
|
||||||
var (
|
|
||||||
ip net.IP
|
|
||||||
port int
|
|
||||||
zone string
|
|
||||||
)
|
|
||||||
switch a := a.(type) {
|
|
||||||
case *net.TCPAddr:
|
|
||||||
ip = a.IP
|
|
||||||
port = a.Port
|
|
||||||
zone = a.Zone
|
|
||||||
case *net.UDPAddr:
|
|
||||||
ip = a.IP
|
|
||||||
port = a.Port
|
|
||||||
zone = a.Zone
|
|
||||||
case *net.IPAddr:
|
|
||||||
ip = a.IP
|
|
||||||
zone = a.Zone
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if ip4 := ip.To4(); ip4 != nil {
|
|
||||||
sa := unix.SockaddrInet4{Port: port}
|
|
||||||
copy(sa.Addr[:], ip4)
|
|
||||||
return &sa
|
|
||||||
}
|
|
||||||
|
|
||||||
if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil {
|
|
||||||
sa := unix.SockaddrInet6{Port: port}
|
|
||||||
copy(sa.Addr[:], ip6)
|
|
||||||
if zone != "" {
|
|
||||||
sa.ZoneId = uint32(zoneCache.index(zone))
|
|
||||||
}
|
|
||||||
return &sa
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// sockaddrToAddr converts a unix.Sockaddr to a net.Addr.
|
|
||||||
func sockaddrToAddr(sa unix.Sockaddr, network string) net.Addr {
|
|
||||||
var (
|
|
||||||
ip net.IP
|
|
||||||
port int
|
|
||||||
zone string
|
|
||||||
)
|
|
||||||
switch sa := sa.(type) {
|
|
||||||
case *unix.SockaddrInet4:
|
|
||||||
ip = make(net.IP, net.IPv4len)
|
|
||||||
copy(ip, sa.Addr[:])
|
|
||||||
port = sa.Port
|
|
||||||
case *unix.SockaddrInet6:
|
|
||||||
ip = make(net.IP, net.IPv6len)
|
|
||||||
copy(ip, sa.Addr[:])
|
|
||||||
port = sa.Port
|
|
||||||
if sa.ZoneId > 0 {
|
|
||||||
zone = zoneCache.name(int(sa.ZoneId))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch network {
|
|
||||||
case "tcp", "tcp4", "tcp6":
|
|
||||||
return &net.TCPAddr{IP: ip, Port: port, Zone: zone}
|
|
||||||
case "udp", "udp4", "udp6":
|
|
||||||
return &net.UDPAddr{IP: ip, Port: port, Zone: zone}
|
|
||||||
default:
|
|
||||||
return &net.IPAddr{IP: ip, Zone: zone}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
7
vendor/golang.org/x/net/internal/socket/sys_windows.go
generated
vendored
7
vendor/golang.org/x/net/internal/socket/sys_windows.go
generated
vendored
@ -5,7 +5,6 @@
|
|||||||
package socket
|
package socket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
@ -38,11 +37,11 @@ func setsockopt(s uintptr, level, name int, b []byte) error {
|
|||||||
return syscall.Setsockopt(syscall.Handle(s), int32(level), int32(name), (*byte)(unsafe.Pointer(&b[0])), int32(len(b)))
|
return syscall.Setsockopt(syscall.Handle(s), int32(level), int32(name), (*byte)(unsafe.Pointer(&b[0])), int32(len(b)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvmsg(s uintptr, buffers [][]byte, oob []byte, flags int, network string) (n, oobn int, recvflags int, from net.Addr, err error) {
|
func recvmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
return 0, 0, 0, nil, errNotImplemented
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendmsg(s uintptr, buffers [][]byte, oob []byte, to net.Addr, flags int) (int, error) {
|
func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
return 0, errNotImplemented
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
vendor/golang.org/x/net/internal/socket/sys_zos_s390x.go
generated
vendored
42
vendor/golang.org/x/net/internal/socket/sys_zos_s390x.go
generated
vendored
@ -5,7 +5,6 @@
|
|||||||
package socket
|
package socket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -28,39 +27,12 @@ func setsockopt(s uintptr, level, name int, b []byte) error {
|
|||||||
return errnoErr(errno)
|
return errnoErr(errno)
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvmsg(s uintptr, buffers [][]byte, oob []byte, flags int, network string) (n, oobn int, recvflags int, from net.Addr, err error) {
|
func recvmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
var h msghdr
|
n, _, errno := syscall_syscall(syscall.SYS___RECVMSG_A, s, uintptr(unsafe.Pointer(h)), uintptr(flags))
|
||||||
vs := make([]iovec, len(buffers))
|
return int(n), errnoErr(errno)
|
||||||
var sa []byte
|
}
|
||||||
if network != "tcp" {
|
|
||||||
sa = make([]byte, sizeofSockaddrInet6)
|
func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
}
|
n, _, errno := syscall_syscall(syscall.SYS___SENDMSG_A, s, uintptr(unsafe.Pointer(h)), uintptr(flags))
|
||||||
h.pack(vs, buffers, oob, sa)
|
|
||||||
sn, _, errno := syscall_syscall(syscall.SYS___RECVMSG_A, s, uintptr(unsafe.Pointer(&h)), uintptr(flags))
|
|
||||||
n = int(sn)
|
|
||||||
oobn = h.controllen()
|
|
||||||
recvflags = h.flags()
|
|
||||||
err = errnoErr(errno)
|
|
||||||
if network != "tcp" {
|
|
||||||
var err2 error
|
|
||||||
from, err2 = parseInetAddr(sa, network)
|
|
||||||
if err2 != nil && err == nil {
|
|
||||||
err = err2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendmsg(s uintptr, buffers [][]byte, oob []byte, to net.Addr, flags int) (int, error) {
|
|
||||||
var h msghdr
|
|
||||||
vs := make([]iovec, len(buffers))
|
|
||||||
var sa []byte
|
|
||||||
if to != nil {
|
|
||||||
var a [sizeofSockaddrInet6]byte
|
|
||||||
n := marshalInetAddr(to, a[:])
|
|
||||||
sa = a[:n]
|
|
||||||
}
|
|
||||||
h.pack(vs, buffers, oob, sa)
|
|
||||||
n, _, errno := syscall_syscall(syscall.SYS___SENDMSG_A, s, uintptr(unsafe.Pointer(&h)), uintptr(flags))
|
|
||||||
return int(n), errnoErr(errno)
|
return int(n), errnoErr(errno)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs defs_freebsd.go
|
// cgo -godefs defs_darwin.go
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
type iovec struct {
|
type iovec struct {
|
||||||
Base *byte
|
Base *byte
|
||||||
Len uint64
|
Len uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type msghdr struct {
|
type msghdr struct {
|
||||||
@ -25,6 +25,6 @@ type cmsghdr struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sizeofIovec = 0x10
|
sizeofIovec = 0x8
|
||||||
sizeofMsghdr = 0x30
|
sizeofMsghdr = 0x1c
|
||||||
)
|
)
|
@ -1,40 +1,30 @@
|
|||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs defs_linux.go
|
// cgo -godefs defs_darwin.go
|
||||||
|
|
||||||
//go:build loong64
|
|
||||||
// +build loong64
|
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
type iovec struct {
|
type iovec struct {
|
||||||
Base *byte
|
Base *byte
|
||||||
Len uint64
|
Len uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type msghdr struct {
|
type msghdr struct {
|
||||||
Name *byte
|
Name *byte
|
||||||
Namelen uint32
|
Namelen uint32
|
||||||
Iov *iovec
|
Iov *iovec
|
||||||
Iovlen uint64
|
Iovlen int32
|
||||||
Control *byte
|
Control *byte
|
||||||
Controllen uint64
|
Controllen uint32
|
||||||
Flags int32
|
Flags int32
|
||||||
Pad_cgo_0 [4]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type mmsghdr struct {
|
|
||||||
Hdr msghdr
|
|
||||||
Len uint32
|
|
||||||
Pad_cgo_0 [4]byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type cmsghdr struct {
|
type cmsghdr struct {
|
||||||
Len uint64
|
Len uint32
|
||||||
Level int32
|
Level int32
|
||||||
Type int32
|
Type int32
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sizeofIovec = 0x10
|
sizeofIovec = 0x8
|
||||||
sizeofMsghdr = 0x38
|
sizeofMsghdr = 0x1c
|
||||||
)
|
)
|
32
vendor/golang.org/x/net/internal/socket/zsys_linux_ppc.go
generated
vendored
32
vendor/golang.org/x/net/internal/socket/zsys_linux_ppc.go
generated
vendored
@ -4,32 +4,32 @@
|
|||||||
package socket
|
package socket
|
||||||
|
|
||||||
type iovec struct {
|
type iovec struct {
|
||||||
Base *byte
|
Base *byte
|
||||||
Len uint32
|
Len uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type msghdr struct {
|
type msghdr struct {
|
||||||
Name *byte
|
Name *byte
|
||||||
Namelen uint32
|
Namelen uint32
|
||||||
Iov *iovec
|
Iov *iovec
|
||||||
Iovlen uint32
|
Iovlen uint32
|
||||||
Control *byte
|
Control *byte
|
||||||
Controllen uint32
|
Controllen uint32
|
||||||
Flags int32
|
Flags int32
|
||||||
}
|
}
|
||||||
|
|
||||||
type mmsghdr struct {
|
type mmsghdr struct {
|
||||||
Hdr msghdr
|
Hdr msghdr
|
||||||
Len uint32
|
Len uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type cmsghdr struct {
|
type cmsghdr struct {
|
||||||
Len uint32
|
Len uint32
|
||||||
Level int32
|
Level int32
|
||||||
Type int32
|
Type int32
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sizeofIovec = 0x8
|
sizeofIovec = 0x8
|
||||||
sizeofMsghdr = 0x1c
|
sizeofMsghdr = 0x1c
|
||||||
)
|
)
|
||||||
|
30
vendor/golang.org/x/net/internal/socket/zsys_openbsd_ppc64.go
generated
vendored
30
vendor/golang.org/x/net/internal/socket/zsys_openbsd_ppc64.go
generated
vendored
@ -1,30 +0,0 @@
|
|||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
|
||||||
// cgo -godefs defs_openbsd.go
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
type iovec struct {
|
|
||||||
Base *byte
|
|
||||||
Len uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type msghdr struct {
|
|
||||||
Name *byte
|
|
||||||
Namelen uint32
|
|
||||||
Iov *iovec
|
|
||||||
Iovlen uint32
|
|
||||||
Control *byte
|
|
||||||
Controllen uint32
|
|
||||||
Flags int32
|
|
||||||
}
|
|
||||||
|
|
||||||
type cmsghdr struct {
|
|
||||||
Len uint32
|
|
||||||
Level int32
|
|
||||||
Type int32
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofIovec = 0x10
|
|
||||||
sizeofMsghdr = 0x30
|
|
||||||
)
|
|
30
vendor/golang.org/x/net/internal/socket/zsys_openbsd_riscv64.go
generated
vendored
30
vendor/golang.org/x/net/internal/socket/zsys_openbsd_riscv64.go
generated
vendored
@ -1,30 +0,0 @@
|
|||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
|
||||||
// cgo -godefs defs_openbsd.go
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
type iovec struct {
|
|
||||||
Base *byte
|
|
||||||
Len uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type msghdr struct {
|
|
||||||
Name *byte
|
|
||||||
Namelen uint32
|
|
||||||
Iov *iovec
|
|
||||||
Iovlen uint32
|
|
||||||
Control *byte
|
|
||||||
Controllen uint32
|
|
||||||
Flags int32
|
|
||||||
}
|
|
||||||
|
|
||||||
type cmsghdr struct {
|
|
||||||
Len uint32
|
|
||||||
Level int32
|
|
||||||
Type int32
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofIovec = 0x10
|
|
||||||
sizeofMsghdr = 0x30
|
|
||||||
)
|
|
12
vendor/golang.org/x/net/ipv4/doc.go
generated
vendored
12
vendor/golang.org/x/net/ipv4/doc.go
generated
vendored
@ -16,7 +16,8 @@
|
|||||||
// 3376.
|
// 3376.
|
||||||
// Source-specific multicast is defined in RFC 4607.
|
// Source-specific multicast is defined in RFC 4607.
|
||||||
//
|
//
|
||||||
// # Unicasting
|
//
|
||||||
|
// Unicasting
|
||||||
//
|
//
|
||||||
// The options for unicasting are available for net.TCPConn,
|
// The options for unicasting are available for net.TCPConn,
|
||||||
// net.UDPConn and net.IPConn which are created as network connections
|
// net.UDPConn and net.IPConn which are created as network connections
|
||||||
@ -50,7 +51,8 @@
|
|||||||
// }(c)
|
// }(c)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// # Multicasting
|
//
|
||||||
|
// Multicasting
|
||||||
//
|
//
|
||||||
// The options for multicasting are available for net.UDPConn and
|
// The options for multicasting are available for net.UDPConn and
|
||||||
// net.IPConn which are created as network connections that use the
|
// net.IPConn which are created as network connections that use the
|
||||||
@ -139,7 +141,8 @@
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// # More multicasting
|
//
|
||||||
|
// More multicasting
|
||||||
//
|
//
|
||||||
// An application that uses PacketConn or RawConn may join multiple
|
// An application that uses PacketConn or RawConn may join multiple
|
||||||
// multicast groups. For example, a UDP listener with port 1024 might
|
// multicast groups. For example, a UDP listener with port 1024 might
|
||||||
@ -197,7 +200,8 @@
|
|||||||
// // error handling
|
// // error handling
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// # Source-specific multicasting
|
//
|
||||||
|
// Source-specific multicasting
|
||||||
//
|
//
|
||||||
// An application that uses PacketConn or RawConn on IGMPv3 supported
|
// An application that uses PacketConn or RawConn on IGMPv3 supported
|
||||||
// platform is able to join source-specific multicast groups.
|
// platform is able to join source-specific multicast groups.
|
||||||
|
52
vendor/golang.org/x/net/ipv4/zsys_freebsd_riscv64.go
generated
vendored
52
vendor/golang.org/x/net/ipv4/zsys_freebsd_riscv64.go
generated
vendored
@ -1,52 +0,0 @@
|
|||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
|
||||||
// cgo -godefs defs_freebsd.go
|
|
||||||
|
|
||||||
package ipv4
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofSockaddrStorage = 0x80
|
|
||||||
sizeofSockaddrInet = 0x10
|
|
||||||
|
|
||||||
sizeofIPMreq = 0x8
|
|
||||||
sizeofIPMreqSource = 0xc
|
|
||||||
sizeofGroupReq = 0x88
|
|
||||||
sizeofGroupSourceReq = 0x108
|
|
||||||
)
|
|
||||||
|
|
||||||
type sockaddrStorage struct {
|
|
||||||
Len uint8
|
|
||||||
Family uint8
|
|
||||||
X__ss_pad1 [6]uint8
|
|
||||||
X__ss_align int64
|
|
||||||
X__ss_pad2 [112]uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
type sockaddrInet struct {
|
|
||||||
Len uint8
|
|
||||||
Family uint8
|
|
||||||
Port uint16
|
|
||||||
Addr [4]byte /* in_addr */
|
|
||||||
Zero [8]uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipMreq struct {
|
|
||||||
Multiaddr [4]byte /* in_addr */
|
|
||||||
Interface [4]byte /* in_addr */
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipMreqSource struct {
|
|
||||||
Multiaddr [4]byte /* in_addr */
|
|
||||||
Sourceaddr [4]byte /* in_addr */
|
|
||||||
Interface [4]byte /* in_addr */
|
|
||||||
}
|
|
||||||
|
|
||||||
type groupReq struct {
|
|
||||||
Interface uint32
|
|
||||||
Group sockaddrStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
type groupSourceReq struct {
|
|
||||||
Interface uint32
|
|
||||||
Group sockaddrStorage
|
|
||||||
Source sockaddrStorage
|
|
||||||
}
|
|
77
vendor/golang.org/x/net/ipv4/zsys_linux_loong64.go
generated
vendored
77
vendor/golang.org/x/net/ipv4/zsys_linux_loong64.go
generated
vendored
@ -1,77 +0,0 @@
|
|||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
|
||||||
// cgo -godefs defs_linux.go
|
|
||||||
|
|
||||||
//go:build loong64
|
|
||||||
// +build loong64
|
|
||||||
|
|
||||||
package ipv4
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofKernelSockaddrStorage = 0x80
|
|
||||||
sizeofSockaddrInet = 0x10
|
|
||||||
sizeofInetPktinfo = 0xc
|
|
||||||
sizeofSockExtendedErr = 0x10
|
|
||||||
|
|
||||||
sizeofIPMreq = 0x8
|
|
||||||
sizeofIPMreqSource = 0xc
|
|
||||||
sizeofGroupReq = 0x88
|
|
||||||
sizeofGroupSourceReq = 0x108
|
|
||||||
|
|
||||||
sizeofICMPFilter = 0x4
|
|
||||||
)
|
|
||||||
|
|
||||||
type kernelSockaddrStorage struct {
|
|
||||||
Family uint16
|
|
||||||
X__data [126]int8
|
|
||||||
}
|
|
||||||
|
|
||||||
type sockaddrInet struct {
|
|
||||||
Family uint16
|
|
||||||
Port uint16
|
|
||||||
Addr [4]byte /* in_addr */
|
|
||||||
X__pad [8]uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
type inetPktinfo struct {
|
|
||||||
Ifindex int32
|
|
||||||
Spec_dst [4]byte /* in_addr */
|
|
||||||
Addr [4]byte /* in_addr */
|
|
||||||
}
|
|
||||||
|
|
||||||
type sockExtendedErr struct {
|
|
||||||
Errno uint32
|
|
||||||
Origin uint8
|
|
||||||
Type uint8
|
|
||||||
Code uint8
|
|
||||||
Pad uint8
|
|
||||||
Info uint32
|
|
||||||
Data uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipMreq struct {
|
|
||||||
Multiaddr [4]byte /* in_addr */
|
|
||||||
Interface [4]byte /* in_addr */
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipMreqSource struct {
|
|
||||||
Multiaddr uint32
|
|
||||||
Interface uint32
|
|
||||||
Sourceaddr uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type groupReq struct {
|
|
||||||
Interface uint32
|
|
||||||
Pad_cgo_0 [4]byte
|
|
||||||
Group kernelSockaddrStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
type groupSourceReq struct {
|
|
||||||
Interface uint32
|
|
||||||
Pad_cgo_0 [4]byte
|
|
||||||
Group kernelSockaddrStorage
|
|
||||||
Source kernelSockaddrStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
type icmpFilter struct {
|
|
||||||
Data uint32
|
|
||||||
}
|
|
12
vendor/golang.org/x/net/ipv6/doc.go
generated
vendored
12
vendor/golang.org/x/net/ipv6/doc.go
generated
vendored
@ -17,7 +17,8 @@
|
|||||||
// On Darwin, this package requires OS X Mavericks version 10.9 or
|
// On Darwin, this package requires OS X Mavericks version 10.9 or
|
||||||
// above, or equivalent.
|
// above, or equivalent.
|
||||||
//
|
//
|
||||||
// # Unicasting
|
//
|
||||||
|
// Unicasting
|
||||||
//
|
//
|
||||||
// The options for unicasting are available for net.TCPConn,
|
// The options for unicasting are available for net.TCPConn,
|
||||||
// net.UDPConn and net.IPConn which are created as network connections
|
// net.UDPConn and net.IPConn which are created as network connections
|
||||||
@ -51,7 +52,8 @@
|
|||||||
// }(c)
|
// }(c)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// # Multicasting
|
//
|
||||||
|
// Multicasting
|
||||||
//
|
//
|
||||||
// The options for multicasting are available for net.UDPConn and
|
// The options for multicasting are available for net.UDPConn and
|
||||||
// net.IPConn which are created as network connections that use the
|
// net.IPConn which are created as network connections that use the
|
||||||
@ -138,7 +140,8 @@
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// # More multicasting
|
//
|
||||||
|
// More multicasting
|
||||||
//
|
//
|
||||||
// An application that uses PacketConn may join multiple multicast
|
// An application that uses PacketConn may join multiple multicast
|
||||||
// groups. For example, a UDP listener with port 1024 might join two
|
// groups. For example, a UDP listener with port 1024 might join two
|
||||||
@ -196,7 +199,8 @@
|
|||||||
// // error handling
|
// // error handling
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// # Source-specific multicasting
|
//
|
||||||
|
// Source-specific multicasting
|
||||||
//
|
//
|
||||||
// An application that uses PacketConn on MLDv2 supported platform is
|
// An application that uses PacketConn on MLDv2 supported platform is
|
||||||
// able to join source-specific multicast groups.
|
// able to join source-specific multicast groups.
|
||||||
|
64
vendor/golang.org/x/net/ipv6/zsys_freebsd_riscv64.go
generated
vendored
64
vendor/golang.org/x/net/ipv6/zsys_freebsd_riscv64.go
generated
vendored
@ -1,64 +0,0 @@
|
|||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
|
||||||
// cgo -godefs defs_freebsd.go
|
|
||||||
|
|
||||||
package ipv6
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofSockaddrStorage = 0x80
|
|
||||||
sizeofSockaddrInet6 = 0x1c
|
|
||||||
sizeofInet6Pktinfo = 0x14
|
|
||||||
sizeofIPv6Mtuinfo = 0x20
|
|
||||||
|
|
||||||
sizeofIPv6Mreq = 0x14
|
|
||||||
sizeofGroupReq = 0x88
|
|
||||||
sizeofGroupSourceReq = 0x108
|
|
||||||
|
|
||||||
sizeofICMPv6Filter = 0x20
|
|
||||||
)
|
|
||||||
|
|
||||||
type sockaddrStorage struct {
|
|
||||||
Len uint8
|
|
||||||
Family uint8
|
|
||||||
X__ss_pad1 [6]uint8
|
|
||||||
X__ss_align int64
|
|
||||||
X__ss_pad2 [112]uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
type sockaddrInet6 struct {
|
|
||||||
Len uint8
|
|
||||||
Family uint8
|
|
||||||
Port uint16
|
|
||||||
Flowinfo uint32
|
|
||||||
Addr [16]byte /* in6_addr */
|
|
||||||
Scope_id uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type inet6Pktinfo struct {
|
|
||||||
Addr [16]byte /* in6_addr */
|
|
||||||
Ifindex uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipv6Mtuinfo struct {
|
|
||||||
Addr sockaddrInet6
|
|
||||||
Mtu uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipv6Mreq struct {
|
|
||||||
Multiaddr [16]byte /* in6_addr */
|
|
||||||
Interface uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type groupReq struct {
|
|
||||||
Interface uint32
|
|
||||||
Group sockaddrStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
type groupSourceReq struct {
|
|
||||||
Interface uint32
|
|
||||||
Group sockaddrStorage
|
|
||||||
Source sockaddrStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
type icmpv6Filter struct {
|
|
||||||
Filt [8]uint32
|
|
||||||
}
|
|
77
vendor/golang.org/x/net/ipv6/zsys_linux_loong64.go
generated
vendored
77
vendor/golang.org/x/net/ipv6/zsys_linux_loong64.go
generated
vendored
@ -1,77 +0,0 @@
|
|||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
|
||||||
// cgo -godefs defs_linux.go
|
|
||||||
|
|
||||||
//go:build loong64
|
|
||||||
// +build loong64
|
|
||||||
|
|
||||||
package ipv6
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofKernelSockaddrStorage = 0x80
|
|
||||||
sizeofSockaddrInet6 = 0x1c
|
|
||||||
sizeofInet6Pktinfo = 0x14
|
|
||||||
sizeofIPv6Mtuinfo = 0x20
|
|
||||||
sizeofIPv6FlowlabelReq = 0x20
|
|
||||||
|
|
||||||
sizeofIPv6Mreq = 0x14
|
|
||||||
sizeofGroupReq = 0x88
|
|
||||||
sizeofGroupSourceReq = 0x108
|
|
||||||
|
|
||||||
sizeofICMPv6Filter = 0x20
|
|
||||||
)
|
|
||||||
|
|
||||||
type kernelSockaddrStorage struct {
|
|
||||||
Family uint16
|
|
||||||
X__data [126]int8
|
|
||||||
}
|
|
||||||
|
|
||||||
type sockaddrInet6 struct {
|
|
||||||
Family uint16
|
|
||||||
Port uint16
|
|
||||||
Flowinfo uint32
|
|
||||||
Addr [16]byte /* in6_addr */
|
|
||||||
Scope_id uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type inet6Pktinfo struct {
|
|
||||||
Addr [16]byte /* in6_addr */
|
|
||||||
Ifindex int32
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipv6Mtuinfo struct {
|
|
||||||
Addr sockaddrInet6
|
|
||||||
Mtu uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipv6FlowlabelReq struct {
|
|
||||||
Dst [16]byte /* in6_addr */
|
|
||||||
Label uint32
|
|
||||||
Action uint8
|
|
||||||
Share uint8
|
|
||||||
Flags uint16
|
|
||||||
Expires uint16
|
|
||||||
Linger uint16
|
|
||||||
X__flr_pad uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipv6Mreq struct {
|
|
||||||
Multiaddr [16]byte /* in6_addr */
|
|
||||||
Ifindex int32
|
|
||||||
}
|
|
||||||
|
|
||||||
type groupReq struct {
|
|
||||||
Interface uint32
|
|
||||||
Pad_cgo_0 [4]byte
|
|
||||||
Group kernelSockaddrStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
type groupSourceReq struct {
|
|
||||||
Interface uint32
|
|
||||||
Pad_cgo_0 [4]byte
|
|
||||||
Group kernelSockaddrStorage
|
|
||||||
Source kernelSockaddrStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
type icmpv6Filter struct {
|
|
||||||
Data [8]uint32
|
|
||||||
}
|
|
3
vendor/golang.org/x/sys/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/sys/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# This source code refers to The Go Authors for copyright purposes.
|
||||||
|
# The master list of authors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/AUTHORS.
|
3
vendor/golang.org/x/sys/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/sys/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# This source code was written by the Go contributors.
|
||||||
|
# The master list of contributors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/CONTRIBUTORS.
|
102
vendor/golang.org/x/sys/execabs/execabs.go
generated
vendored
102
vendor/golang.org/x/sys/execabs/execabs.go
generated
vendored
@ -1,102 +0,0 @@
|
|||||||
// Copyright 2020 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 execabs is a drop-in replacement for os/exec
|
|
||||||
// that requires PATH lookups to find absolute paths.
|
|
||||||
// That is, execabs.Command("cmd") runs the same PATH lookup
|
|
||||||
// as exec.Command("cmd"), but if the result is a path
|
|
||||||
// which is relative, the Run and Start methods will report
|
|
||||||
// an error instead of running the executable.
|
|
||||||
//
|
|
||||||
// See https://blog.golang.org/path-security for more information
|
|
||||||
// about when it may be necessary or appropriate to use this package.
|
|
||||||
package execabs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrNotFound is the error resulting if a path search failed to find an executable file.
|
|
||||||
// It is an alias for exec.ErrNotFound.
|
|
||||||
var ErrNotFound = exec.ErrNotFound
|
|
||||||
|
|
||||||
// Cmd represents an external command being prepared or run.
|
|
||||||
// It is an alias for exec.Cmd.
|
|
||||||
type Cmd = exec.Cmd
|
|
||||||
|
|
||||||
// Error is returned by LookPath when it fails to classify a file as an executable.
|
|
||||||
// It is an alias for exec.Error.
|
|
||||||
type Error = exec.Error
|
|
||||||
|
|
||||||
// An ExitError reports an unsuccessful exit by a command.
|
|
||||||
// It is an alias for exec.ExitError.
|
|
||||||
type ExitError = exec.ExitError
|
|
||||||
|
|
||||||
func relError(file, path string) error {
|
|
||||||
return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LookPath searches for an executable named file in the directories
|
|
||||||
// named by the PATH environment variable. If file contains a slash,
|
|
||||||
// it is tried directly and the PATH is not consulted. The result will be
|
|
||||||
// an absolute path.
|
|
||||||
//
|
|
||||||
// LookPath differs from exec.LookPath in its handling of PATH lookups,
|
|
||||||
// which are used for file names without slashes. If exec.LookPath's
|
|
||||||
// PATH lookup would have returned an executable from the current directory,
|
|
||||||
// LookPath instead returns an error.
|
|
||||||
func LookPath(file string) (string, error) {
|
|
||||||
path, err := exec.LookPath(file)
|
|
||||||
if err != nil && !isGo119ErrDot(err) {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if filepath.Base(file) == file && !filepath.IsAbs(path) {
|
|
||||||
return "", relError(file, path)
|
|
||||||
}
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func fixCmd(name string, cmd *exec.Cmd) {
|
|
||||||
if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) {
|
|
||||||
// exec.Command was called with a bare binary name and
|
|
||||||
// exec.LookPath returned a path which is not absolute.
|
|
||||||
// Set cmd.lookPathErr and clear cmd.Path so that it
|
|
||||||
// cannot be run.
|
|
||||||
lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer()))
|
|
||||||
if *lookPathErr == nil {
|
|
||||||
*lookPathErr = relError(name, cmd.Path)
|
|
||||||
}
|
|
||||||
cmd.Path = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommandContext is like Command but includes a context.
|
|
||||||
//
|
|
||||||
// The provided context is used to kill the process (by calling os.Process.Kill)
|
|
||||||
// if the context becomes done before the command completes on its own.
|
|
||||||
func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd {
|
|
||||||
cmd := exec.CommandContext(ctx, name, arg...)
|
|
||||||
fixCmd(name, cmd)
|
|
||||||
return cmd
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the Cmd struct to execute the named program with the given arguments.
|
|
||||||
// See exec.Command for most details.
|
|
||||||
//
|
|
||||||
// Command differs from exec.Command in its handling of PATH lookups,
|
|
||||||
// which are used when the program name contains no slashes.
|
|
||||||
// If exec.Command would have returned an exec.Cmd configured to run an
|
|
||||||
// executable from the current directory, Command instead
|
|
||||||
// returns an exec.Cmd that will return an error from Start or Run.
|
|
||||||
func Command(name string, arg ...string) *exec.Cmd {
|
|
||||||
cmd := exec.Command(name, arg...)
|
|
||||||
fixCmd(name, cmd)
|
|
||||||
return cmd
|
|
||||||
}
|
|
12
vendor/golang.org/x/sys/execabs/execabs_go118.go
generated
vendored
12
vendor/golang.org/x/sys/execabs/execabs_go118.go
generated
vendored
@ -1,12 +0,0 @@
|
|||||||
// Copyright 2022 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 !go1.19
|
|
||||||
// +build !go1.19
|
|
||||||
|
|
||||||
package execabs
|
|
||||||
|
|
||||||
func isGo119ErrDot(err error) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
15
vendor/golang.org/x/sys/execabs/execabs_go119.go
generated
vendored
15
vendor/golang.org/x/sys/execabs/execabs_go119.go
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
// Copyright 2022 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 go1.19
|
|
||||||
// +build go1.19
|
|
||||||
|
|
||||||
package execabs
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
func isGo119ErrDot(err error) bool {
|
|
||||||
// TODO: return errors.Is(err, exec.ErrDot)
|
|
||||||
return strings.Contains(err.Error(), "current directory")
|
|
||||||
}
|
|
31
vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s
generated
vendored
31
vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s
generated
vendored
@ -1,31 +0,0 @@
|
|||||||
// Copyright 2022 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 || freebsd || netbsd || openbsd) && gc
|
|
||||||
// +build darwin freebsd netbsd openbsd
|
|
||||||
// +build gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System call support for ppc64, BSD
|
|
||||||
//
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
|
||||||
JMP syscall·Syscall9(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
29
vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s
generated
vendored
29
vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s
generated
vendored
@ -1,29 +0,0 @@
|
|||||||
// Copyright 2021 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 || freebsd || netbsd || openbsd) && gc
|
|
||||||
// +build darwin freebsd netbsd openbsd
|
|
||||||
// +build gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// System call support for RISCV64 BSD
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
|
||||||
JMP syscall·Syscall9(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
54
vendor/golang.org/x/sys/unix/asm_linux_loong64.s
generated
vendored
54
vendor/golang.org/x/sys/unix/asm_linux_loong64.s
generated
vendored
@ -1,54 +0,0 @@
|
|||||||
// Copyright 2022 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 linux && loong64 && gc
|
|
||||||
// +build linux
|
|
||||||
// +build loong64
|
|
||||||
// +build gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
JAL runtime·entersyscall(SB)
|
|
||||||
MOVV a1+8(FP), R4
|
|
||||||
MOVV a2+16(FP), R5
|
|
||||||
MOVV a3+24(FP), R6
|
|
||||||
MOVV R0, R7
|
|
||||||
MOVV R0, R8
|
|
||||||
MOVV R0, R9
|
|
||||||
MOVV trap+0(FP), R11 // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVV R4, r1+32(FP)
|
|
||||||
MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
|
|
||||||
JAL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
MOVV a1+8(FP), R4
|
|
||||||
MOVV a2+16(FP), R5
|
|
||||||
MOVV a3+24(FP), R6
|
|
||||||
MOVV R0, R7
|
|
||||||
MOVV R0, R8
|
|
||||||
MOVV R0, R9
|
|
||||||
MOVV trap+0(FP), R11 // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVV R4, r1+32(FP)
|
|
||||||
MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
|
|
||||||
RET
|
|
4
vendor/golang.org/x/sys/unix/dirent.go
generated
vendored
4
vendor/golang.org/x/sys/unix/dirent.go
generated
vendored
@ -2,8 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
4
vendor/golang.org/x/sys/unix/endian_little.go
generated
vendored
4
vendor/golang.org/x/sys/unix/endian_little.go
generated
vendored
@ -2,8 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
//
|
//
|
||||||
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh
|
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh
|
||||||
// +build 386 amd64 amd64p32 alpha arm arm64 loong64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh
|
// +build 386 amd64 amd64p32 alpha arm arm64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
233
vendor/golang.org/x/sys/unix/errors_freebsd_386.go
generated
vendored
Normal file
233
vendor/golang.org/x/sys/unix/errors_freebsd_386.go
generated
vendored
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
|
||||||
|
// them here for backwards compatibility.
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
const (
|
||||||
|
DLT_HHDLC = 0x79
|
||||||
|
IFF_SMART = 0x20
|
||||||
|
IFT_1822 = 0x2
|
||||||
|
IFT_A12MPPSWITCH = 0x82
|
||||||
|
IFT_AAL2 = 0xbb
|
||||||
|
IFT_AAL5 = 0x31
|
||||||
|
IFT_ADSL = 0x5e
|
||||||
|
IFT_AFLANE8023 = 0x3b
|
||||||
|
IFT_AFLANE8025 = 0x3c
|
||||||
|
IFT_ARAP = 0x58
|
||||||
|
IFT_ARCNET = 0x23
|
||||||
|
IFT_ARCNETPLUS = 0x24
|
||||||
|
IFT_ASYNC = 0x54
|
||||||
|
IFT_ATM = 0x25
|
||||||
|
IFT_ATMDXI = 0x69
|
||||||
|
IFT_ATMFUNI = 0x6a
|
||||||
|
IFT_ATMIMA = 0x6b
|
||||||
|
IFT_ATMLOGICAL = 0x50
|
||||||
|
IFT_ATMRADIO = 0xbd
|
||||||
|
IFT_ATMSUBINTERFACE = 0x86
|
||||||
|
IFT_ATMVCIENDPT = 0xc2
|
||||||
|
IFT_ATMVIRTUAL = 0x95
|
||||||
|
IFT_BGPPOLICYACCOUNTING = 0xa2
|
||||||
|
IFT_BSC = 0x53
|
||||||
|
IFT_CCTEMUL = 0x3d
|
||||||
|
IFT_CEPT = 0x13
|
||||||
|
IFT_CES = 0x85
|
||||||
|
IFT_CHANNEL = 0x46
|
||||||
|
IFT_CNR = 0x55
|
||||||
|
IFT_COFFEE = 0x84
|
||||||
|
IFT_COMPOSITELINK = 0x9b
|
||||||
|
IFT_DCN = 0x8d
|
||||||
|
IFT_DIGITALPOWERLINE = 0x8a
|
||||||
|
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
|
||||||
|
IFT_DLSW = 0x4a
|
||||||
|
IFT_DOCSCABLEDOWNSTREAM = 0x80
|
||||||
|
IFT_DOCSCABLEMACLAYER = 0x7f
|
||||||
|
IFT_DOCSCABLEUPSTREAM = 0x81
|
||||||
|
IFT_DS0 = 0x51
|
||||||
|
IFT_DS0BUNDLE = 0x52
|
||||||
|
IFT_DS1FDL = 0xaa
|
||||||
|
IFT_DS3 = 0x1e
|
||||||
|
IFT_DTM = 0x8c
|
||||||
|
IFT_DVBASILN = 0xac
|
||||||
|
IFT_DVBASIOUT = 0xad
|
||||||
|
IFT_DVBRCCDOWNSTREAM = 0x93
|
||||||
|
IFT_DVBRCCMACLAYER = 0x92
|
||||||
|
IFT_DVBRCCUPSTREAM = 0x94
|
||||||
|
IFT_ENC = 0xf4
|
||||||
|
IFT_EON = 0x19
|
||||||
|
IFT_EPLRS = 0x57
|
||||||
|
IFT_ESCON = 0x49
|
||||||
|
IFT_ETHER = 0x6
|
||||||
|
IFT_FAITH = 0xf2
|
||||||
|
IFT_FAST = 0x7d
|
||||||
|
IFT_FASTETHER = 0x3e
|
||||||
|
IFT_FASTETHERFX = 0x45
|
||||||
|
IFT_FDDI = 0xf
|
||||||
|
IFT_FIBRECHANNEL = 0x38
|
||||||
|
IFT_FRAMERELAYINTERCONNECT = 0x3a
|
||||||
|
IFT_FRAMERELAYMPI = 0x5c
|
||||||
|
IFT_FRDLCIENDPT = 0xc1
|
||||||
|
IFT_FRELAY = 0x20
|
||||||
|
IFT_FRELAYDCE = 0x2c
|
||||||
|
IFT_FRF16MFRBUNDLE = 0xa3
|
||||||
|
IFT_FRFORWARD = 0x9e
|
||||||
|
IFT_G703AT2MB = 0x43
|
||||||
|
IFT_G703AT64K = 0x42
|
||||||
|
IFT_GIF = 0xf0
|
||||||
|
IFT_GIGABITETHERNET = 0x75
|
||||||
|
IFT_GR303IDT = 0xb2
|
||||||
|
IFT_GR303RDT = 0xb1
|
||||||
|
IFT_H323GATEKEEPER = 0xa4
|
||||||
|
IFT_H323PROXY = 0xa5
|
||||||
|
IFT_HDH1822 = 0x3
|
||||||
|
IFT_HDLC = 0x76
|
||||||
|
IFT_HDSL2 = 0xa8
|
||||||
|
IFT_HIPERLAN2 = 0xb7
|
||||||
|
IFT_HIPPI = 0x2f
|
||||||
|
IFT_HIPPIINTERFACE = 0x39
|
||||||
|
IFT_HOSTPAD = 0x5a
|
||||||
|
IFT_HSSI = 0x2e
|
||||||
|
IFT_HY = 0xe
|
||||||
|
IFT_IBM370PARCHAN = 0x48
|
||||||
|
IFT_IDSL = 0x9a
|
||||||
|
IFT_IEEE80211 = 0x47
|
||||||
|
IFT_IEEE80212 = 0x37
|
||||||
|
IFT_IEEE8023ADLAG = 0xa1
|
||||||
|
IFT_IFGSN = 0x91
|
||||||
|
IFT_IMT = 0xbe
|
||||||
|
IFT_INTERLEAVE = 0x7c
|
||||||
|
IFT_IP = 0x7e
|
||||||
|
IFT_IPFORWARD = 0x8e
|
||||||
|
IFT_IPOVERATM = 0x72
|
||||||
|
IFT_IPOVERCDLC = 0x6d
|
||||||
|
IFT_IPOVERCLAW = 0x6e
|
||||||
|
IFT_IPSWITCH = 0x4e
|
||||||
|
IFT_IPXIP = 0xf9
|
||||||
|
IFT_ISDN = 0x3f
|
||||||
|
IFT_ISDNBASIC = 0x14
|
||||||
|
IFT_ISDNPRIMARY = 0x15
|
||||||
|
IFT_ISDNS = 0x4b
|
||||||
|
IFT_ISDNU = 0x4c
|
||||||
|
IFT_ISO88022LLC = 0x29
|
||||||
|
IFT_ISO88023 = 0x7
|
||||||
|
IFT_ISO88024 = 0x8
|
||||||
|
IFT_ISO88025 = 0x9
|
||||||
|
IFT_ISO88025CRFPINT = 0x62
|
||||||
|
IFT_ISO88025DTR = 0x56
|
||||||
|
IFT_ISO88025FIBER = 0x73
|
||||||
|
IFT_ISO88026 = 0xa
|
||||||
|
IFT_ISUP = 0xb3
|
||||||
|
IFT_L3IPXVLAN = 0x89
|
||||||
|
IFT_LAPB = 0x10
|
||||||
|
IFT_LAPD = 0x4d
|
||||||
|
IFT_LAPF = 0x77
|
||||||
|
IFT_LOCALTALK = 0x2a
|
||||||
|
IFT_LOOP = 0x18
|
||||||
|
IFT_MEDIAMAILOVERIP = 0x8b
|
||||||
|
IFT_MFSIGLINK = 0xa7
|
||||||
|
IFT_MIOX25 = 0x26
|
||||||
|
IFT_MODEM = 0x30
|
||||||
|
IFT_MPC = 0x71
|
||||||
|
IFT_MPLS = 0xa6
|
||||||
|
IFT_MPLSTUNNEL = 0x96
|
||||||
|
IFT_MSDSL = 0x8f
|
||||||
|
IFT_MVL = 0xbf
|
||||||
|
IFT_MYRINET = 0x63
|
||||||
|
IFT_NFAS = 0xaf
|
||||||
|
IFT_NSIP = 0x1b
|
||||||
|
IFT_OPTICALCHANNEL = 0xc3
|
||||||
|
IFT_OPTICALTRANSPORT = 0xc4
|
||||||
|
IFT_OTHER = 0x1
|
||||||
|
IFT_P10 = 0xc
|
||||||
|
IFT_P80 = 0xd
|
||||||
|
IFT_PARA = 0x22
|
||||||
|
IFT_PFLOG = 0xf6
|
||||||
|
IFT_PFSYNC = 0xf7
|
||||||
|
IFT_PLC = 0xae
|
||||||
|
IFT_POS = 0xab
|
||||||
|
IFT_PPPMULTILINKBUNDLE = 0x6c
|
||||||
|
IFT_PROPBWAP2MP = 0xb8
|
||||||
|
IFT_PROPCNLS = 0x59
|
||||||
|
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
|
||||||
|
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
|
||||||
|
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
|
||||||
|
IFT_PROPMUX = 0x36
|
||||||
|
IFT_PROPWIRELESSP2P = 0x9d
|
||||||
|
IFT_PTPSERIAL = 0x16
|
||||||
|
IFT_PVC = 0xf1
|
||||||
|
IFT_QLLC = 0x44
|
||||||
|
IFT_RADIOMAC = 0xbc
|
||||||
|
IFT_RADSL = 0x5f
|
||||||
|
IFT_REACHDSL = 0xc0
|
||||||
|
IFT_RFC1483 = 0x9f
|
||||||
|
IFT_RS232 = 0x21
|
||||||
|
IFT_RSRB = 0x4f
|
||||||
|
IFT_SDLC = 0x11
|
||||||
|
IFT_SDSL = 0x60
|
||||||
|
IFT_SHDSL = 0xa9
|
||||||
|
IFT_SIP = 0x1f
|
||||||
|
IFT_SLIP = 0x1c
|
||||||
|
IFT_SMDSDXI = 0x2b
|
||||||
|
IFT_SMDSICIP = 0x34
|
||||||
|
IFT_SONET = 0x27
|
||||||
|
IFT_SONETOVERHEADCHANNEL = 0xb9
|
||||||
|
IFT_SONETPATH = 0x32
|
||||||
|
IFT_SONETVT = 0x33
|
||||||
|
IFT_SRP = 0x97
|
||||||
|
IFT_SS7SIGLINK = 0x9c
|
||||||
|
IFT_STACKTOSTACK = 0x6f
|
||||||
|
IFT_STARLAN = 0xb
|
||||||
|
IFT_STF = 0xd7
|
||||||
|
IFT_T1 = 0x12
|
||||||
|
IFT_TDLC = 0x74
|
||||||
|
IFT_TERMPAD = 0x5b
|
||||||
|
IFT_TR008 = 0xb0
|
||||||
|
IFT_TRANSPHDLC = 0x7b
|
||||||
|
IFT_TUNNEL = 0x83
|
||||||
|
IFT_ULTRA = 0x1d
|
||||||
|
IFT_USB = 0xa0
|
||||||
|
IFT_V11 = 0x40
|
||||||
|
IFT_V35 = 0x2d
|
||||||
|
IFT_V36 = 0x41
|
||||||
|
IFT_V37 = 0x78
|
||||||
|
IFT_VDSL = 0x61
|
||||||
|
IFT_VIRTUALIPADDRESS = 0x70
|
||||||
|
IFT_VOICEEM = 0x64
|
||||||
|
IFT_VOICEENCAP = 0x67
|
||||||
|
IFT_VOICEFXO = 0x65
|
||||||
|
IFT_VOICEFXS = 0x66
|
||||||
|
IFT_VOICEOVERATM = 0x98
|
||||||
|
IFT_VOICEOVERFRAMERELAY = 0x99
|
||||||
|
IFT_VOICEOVERIP = 0x68
|
||||||
|
IFT_X213 = 0x5d
|
||||||
|
IFT_X25 = 0x5
|
||||||
|
IFT_X25DDN = 0x4
|
||||||
|
IFT_X25HUNTGROUP = 0x7a
|
||||||
|
IFT_X25MLP = 0x79
|
||||||
|
IFT_X25PLE = 0x28
|
||||||
|
IFT_XETHER = 0x1a
|
||||||
|
IPPROTO_MAXID = 0x34
|
||||||
|
IPV6_FAITH = 0x1d
|
||||||
|
IPV6_MIN_MEMBERSHIPS = 0x1f
|
||||||
|
IP_FAITH = 0x16
|
||||||
|
IP_MAX_SOURCE_FILTER = 0x400
|
||||||
|
IP_MIN_MEMBERSHIPS = 0x1f
|
||||||
|
MAP_NORESERVE = 0x40
|
||||||
|
MAP_RENAME = 0x20
|
||||||
|
NET_RT_MAXID = 0x6
|
||||||
|
RTF_PRCLONING = 0x10000
|
||||||
|
RTM_OLDADD = 0x9
|
||||||
|
RTM_OLDDEL = 0xa
|
||||||
|
RT_CACHING_CONTEXT = 0x1
|
||||||
|
RT_NORTREF = 0x2
|
||||||
|
SIOCADDRT = 0x8030720a
|
||||||
|
SIOCALIFADDR = 0x8118691b
|
||||||
|
SIOCDELRT = 0x8030720b
|
||||||
|
SIOCDLIFADDR = 0x8118691d
|
||||||
|
SIOCGLIFADDR = 0xc118691c
|
||||||
|
SIOCGLIFPHYADDR = 0xc118694b
|
||||||
|
SIOCSLIFPHYADDR = 0x8118694a
|
||||||
|
)
|
233
vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go
generated
vendored
Normal file
233
vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go
generated
vendored
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
|
||||||
|
// them here for backwards compatibility.
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
const (
|
||||||
|
DLT_HHDLC = 0x79
|
||||||
|
IFF_SMART = 0x20
|
||||||
|
IFT_1822 = 0x2
|
||||||
|
IFT_A12MPPSWITCH = 0x82
|
||||||
|
IFT_AAL2 = 0xbb
|
||||||
|
IFT_AAL5 = 0x31
|
||||||
|
IFT_ADSL = 0x5e
|
||||||
|
IFT_AFLANE8023 = 0x3b
|
||||||
|
IFT_AFLANE8025 = 0x3c
|
||||||
|
IFT_ARAP = 0x58
|
||||||
|
IFT_ARCNET = 0x23
|
||||||
|
IFT_ARCNETPLUS = 0x24
|
||||||
|
IFT_ASYNC = 0x54
|
||||||
|
IFT_ATM = 0x25
|
||||||
|
IFT_ATMDXI = 0x69
|
||||||
|
IFT_ATMFUNI = 0x6a
|
||||||
|
IFT_ATMIMA = 0x6b
|
||||||
|
IFT_ATMLOGICAL = 0x50
|
||||||
|
IFT_ATMRADIO = 0xbd
|
||||||
|
IFT_ATMSUBINTERFACE = 0x86
|
||||||
|
IFT_ATMVCIENDPT = 0xc2
|
||||||
|
IFT_ATMVIRTUAL = 0x95
|
||||||
|
IFT_BGPPOLICYACCOUNTING = 0xa2
|
||||||
|
IFT_BSC = 0x53
|
||||||
|
IFT_CCTEMUL = 0x3d
|
||||||
|
IFT_CEPT = 0x13
|
||||||
|
IFT_CES = 0x85
|
||||||
|
IFT_CHANNEL = 0x46
|
||||||
|
IFT_CNR = 0x55
|
||||||
|
IFT_COFFEE = 0x84
|
||||||
|
IFT_COMPOSITELINK = 0x9b
|
||||||
|
IFT_DCN = 0x8d
|
||||||
|
IFT_DIGITALPOWERLINE = 0x8a
|
||||||
|
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
|
||||||
|
IFT_DLSW = 0x4a
|
||||||
|
IFT_DOCSCABLEDOWNSTREAM = 0x80
|
||||||
|
IFT_DOCSCABLEMACLAYER = 0x7f
|
||||||
|
IFT_DOCSCABLEUPSTREAM = 0x81
|
||||||
|
IFT_DS0 = 0x51
|
||||||
|
IFT_DS0BUNDLE = 0x52
|
||||||
|
IFT_DS1FDL = 0xaa
|
||||||
|
IFT_DS3 = 0x1e
|
||||||
|
IFT_DTM = 0x8c
|
||||||
|
IFT_DVBASILN = 0xac
|
||||||
|
IFT_DVBASIOUT = 0xad
|
||||||
|
IFT_DVBRCCDOWNSTREAM = 0x93
|
||||||
|
IFT_DVBRCCMACLAYER = 0x92
|
||||||
|
IFT_DVBRCCUPSTREAM = 0x94
|
||||||
|
IFT_ENC = 0xf4
|
||||||
|
IFT_EON = 0x19
|
||||||
|
IFT_EPLRS = 0x57
|
||||||
|
IFT_ESCON = 0x49
|
||||||
|
IFT_ETHER = 0x6
|
||||||
|
IFT_FAITH = 0xf2
|
||||||
|
IFT_FAST = 0x7d
|
||||||
|
IFT_FASTETHER = 0x3e
|
||||||
|
IFT_FASTETHERFX = 0x45
|
||||||
|
IFT_FDDI = 0xf
|
||||||
|
IFT_FIBRECHANNEL = 0x38
|
||||||
|
IFT_FRAMERELAYINTERCONNECT = 0x3a
|
||||||
|
IFT_FRAMERELAYMPI = 0x5c
|
||||||
|
IFT_FRDLCIENDPT = 0xc1
|
||||||
|
IFT_FRELAY = 0x20
|
||||||
|
IFT_FRELAYDCE = 0x2c
|
||||||
|
IFT_FRF16MFRBUNDLE = 0xa3
|
||||||
|
IFT_FRFORWARD = 0x9e
|
||||||
|
IFT_G703AT2MB = 0x43
|
||||||
|
IFT_G703AT64K = 0x42
|
||||||
|
IFT_GIF = 0xf0
|
||||||
|
IFT_GIGABITETHERNET = 0x75
|
||||||
|
IFT_GR303IDT = 0xb2
|
||||||
|
IFT_GR303RDT = 0xb1
|
||||||
|
IFT_H323GATEKEEPER = 0xa4
|
||||||
|
IFT_H323PROXY = 0xa5
|
||||||
|
IFT_HDH1822 = 0x3
|
||||||
|
IFT_HDLC = 0x76
|
||||||
|
IFT_HDSL2 = 0xa8
|
||||||
|
IFT_HIPERLAN2 = 0xb7
|
||||||
|
IFT_HIPPI = 0x2f
|
||||||
|
IFT_HIPPIINTERFACE = 0x39
|
||||||
|
IFT_HOSTPAD = 0x5a
|
||||||
|
IFT_HSSI = 0x2e
|
||||||
|
IFT_HY = 0xe
|
||||||
|
IFT_IBM370PARCHAN = 0x48
|
||||||
|
IFT_IDSL = 0x9a
|
||||||
|
IFT_IEEE80211 = 0x47
|
||||||
|
IFT_IEEE80212 = 0x37
|
||||||
|
IFT_IEEE8023ADLAG = 0xa1
|
||||||
|
IFT_IFGSN = 0x91
|
||||||
|
IFT_IMT = 0xbe
|
||||||
|
IFT_INTERLEAVE = 0x7c
|
||||||
|
IFT_IP = 0x7e
|
||||||
|
IFT_IPFORWARD = 0x8e
|
||||||
|
IFT_IPOVERATM = 0x72
|
||||||
|
IFT_IPOVERCDLC = 0x6d
|
||||||
|
IFT_IPOVERCLAW = 0x6e
|
||||||
|
IFT_IPSWITCH = 0x4e
|
||||||
|
IFT_IPXIP = 0xf9
|
||||||
|
IFT_ISDN = 0x3f
|
||||||
|
IFT_ISDNBASIC = 0x14
|
||||||
|
IFT_ISDNPRIMARY = 0x15
|
||||||
|
IFT_ISDNS = 0x4b
|
||||||
|
IFT_ISDNU = 0x4c
|
||||||
|
IFT_ISO88022LLC = 0x29
|
||||||
|
IFT_ISO88023 = 0x7
|
||||||
|
IFT_ISO88024 = 0x8
|
||||||
|
IFT_ISO88025 = 0x9
|
||||||
|
IFT_ISO88025CRFPINT = 0x62
|
||||||
|
IFT_ISO88025DTR = 0x56
|
||||||
|
IFT_ISO88025FIBER = 0x73
|
||||||
|
IFT_ISO88026 = 0xa
|
||||||
|
IFT_ISUP = 0xb3
|
||||||
|
IFT_L3IPXVLAN = 0x89
|
||||||
|
IFT_LAPB = 0x10
|
||||||
|
IFT_LAPD = 0x4d
|
||||||
|
IFT_LAPF = 0x77
|
||||||
|
IFT_LOCALTALK = 0x2a
|
||||||
|
IFT_LOOP = 0x18
|
||||||
|
IFT_MEDIAMAILOVERIP = 0x8b
|
||||||
|
IFT_MFSIGLINK = 0xa7
|
||||||
|
IFT_MIOX25 = 0x26
|
||||||
|
IFT_MODEM = 0x30
|
||||||
|
IFT_MPC = 0x71
|
||||||
|
IFT_MPLS = 0xa6
|
||||||
|
IFT_MPLSTUNNEL = 0x96
|
||||||
|
IFT_MSDSL = 0x8f
|
||||||
|
IFT_MVL = 0xbf
|
||||||
|
IFT_MYRINET = 0x63
|
||||||
|
IFT_NFAS = 0xaf
|
||||||
|
IFT_NSIP = 0x1b
|
||||||
|
IFT_OPTICALCHANNEL = 0xc3
|
||||||
|
IFT_OPTICALTRANSPORT = 0xc4
|
||||||
|
IFT_OTHER = 0x1
|
||||||
|
IFT_P10 = 0xc
|
||||||
|
IFT_P80 = 0xd
|
||||||
|
IFT_PARA = 0x22
|
||||||
|
IFT_PFLOG = 0xf6
|
||||||
|
IFT_PFSYNC = 0xf7
|
||||||
|
IFT_PLC = 0xae
|
||||||
|
IFT_POS = 0xab
|
||||||
|
IFT_PPPMULTILINKBUNDLE = 0x6c
|
||||||
|
IFT_PROPBWAP2MP = 0xb8
|
||||||
|
IFT_PROPCNLS = 0x59
|
||||||
|
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
|
||||||
|
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
|
||||||
|
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
|
||||||
|
IFT_PROPMUX = 0x36
|
||||||
|
IFT_PROPWIRELESSP2P = 0x9d
|
||||||
|
IFT_PTPSERIAL = 0x16
|
||||||
|
IFT_PVC = 0xf1
|
||||||
|
IFT_QLLC = 0x44
|
||||||
|
IFT_RADIOMAC = 0xbc
|
||||||
|
IFT_RADSL = 0x5f
|
||||||
|
IFT_REACHDSL = 0xc0
|
||||||
|
IFT_RFC1483 = 0x9f
|
||||||
|
IFT_RS232 = 0x21
|
||||||
|
IFT_RSRB = 0x4f
|
||||||
|
IFT_SDLC = 0x11
|
||||||
|
IFT_SDSL = 0x60
|
||||||
|
IFT_SHDSL = 0xa9
|
||||||
|
IFT_SIP = 0x1f
|
||||||
|
IFT_SLIP = 0x1c
|
||||||
|
IFT_SMDSDXI = 0x2b
|
||||||
|
IFT_SMDSICIP = 0x34
|
||||||
|
IFT_SONET = 0x27
|
||||||
|
IFT_SONETOVERHEADCHANNEL = 0xb9
|
||||||
|
IFT_SONETPATH = 0x32
|
||||||
|
IFT_SONETVT = 0x33
|
||||||
|
IFT_SRP = 0x97
|
||||||
|
IFT_SS7SIGLINK = 0x9c
|
||||||
|
IFT_STACKTOSTACK = 0x6f
|
||||||
|
IFT_STARLAN = 0xb
|
||||||
|
IFT_STF = 0xd7
|
||||||
|
IFT_T1 = 0x12
|
||||||
|
IFT_TDLC = 0x74
|
||||||
|
IFT_TERMPAD = 0x5b
|
||||||
|
IFT_TR008 = 0xb0
|
||||||
|
IFT_TRANSPHDLC = 0x7b
|
||||||
|
IFT_TUNNEL = 0x83
|
||||||
|
IFT_ULTRA = 0x1d
|
||||||
|
IFT_USB = 0xa0
|
||||||
|
IFT_V11 = 0x40
|
||||||
|
IFT_V35 = 0x2d
|
||||||
|
IFT_V36 = 0x41
|
||||||
|
IFT_V37 = 0x78
|
||||||
|
IFT_VDSL = 0x61
|
||||||
|
IFT_VIRTUALIPADDRESS = 0x70
|
||||||
|
IFT_VOICEEM = 0x64
|
||||||
|
IFT_VOICEENCAP = 0x67
|
||||||
|
IFT_VOICEFXO = 0x65
|
||||||
|
IFT_VOICEFXS = 0x66
|
||||||
|
IFT_VOICEOVERATM = 0x98
|
||||||
|
IFT_VOICEOVERFRAMERELAY = 0x99
|
||||||
|
IFT_VOICEOVERIP = 0x68
|
||||||
|
IFT_X213 = 0x5d
|
||||||
|
IFT_X25 = 0x5
|
||||||
|
IFT_X25DDN = 0x4
|
||||||
|
IFT_X25HUNTGROUP = 0x7a
|
||||||
|
IFT_X25MLP = 0x79
|
||||||
|
IFT_X25PLE = 0x28
|
||||||
|
IFT_XETHER = 0x1a
|
||||||
|
IPPROTO_MAXID = 0x34
|
||||||
|
IPV6_FAITH = 0x1d
|
||||||
|
IPV6_MIN_MEMBERSHIPS = 0x1f
|
||||||
|
IP_FAITH = 0x16
|
||||||
|
IP_MAX_SOURCE_FILTER = 0x400
|
||||||
|
IP_MIN_MEMBERSHIPS = 0x1f
|
||||||
|
MAP_NORESERVE = 0x40
|
||||||
|
MAP_RENAME = 0x20
|
||||||
|
NET_RT_MAXID = 0x6
|
||||||
|
RTF_PRCLONING = 0x10000
|
||||||
|
RTM_OLDADD = 0x9
|
||||||
|
RTM_OLDDEL = 0xa
|
||||||
|
RT_CACHING_CONTEXT = 0x1
|
||||||
|
RT_NORTREF = 0x2
|
||||||
|
SIOCADDRT = 0x8040720a
|
||||||
|
SIOCALIFADDR = 0x8118691b
|
||||||
|
SIOCDELRT = 0x8040720b
|
||||||
|
SIOCDLIFADDR = 0x8118691d
|
||||||
|
SIOCGLIFADDR = 0xc118691c
|
||||||
|
SIOCGLIFPHYADDR = 0xc118694b
|
||||||
|
SIOCSLIFPHYADDR = 0x8118694a
|
||||||
|
)
|
226
vendor/golang.org/x/sys/unix/errors_freebsd_arm.go
generated
vendored
Normal file
226
vendor/golang.org/x/sys/unix/errors_freebsd_arm.go
generated
vendored
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
// Copyright 2017 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 unix
|
||||||
|
|
||||||
|
const (
|
||||||
|
IFT_1822 = 0x2
|
||||||
|
IFT_A12MPPSWITCH = 0x82
|
||||||
|
IFT_AAL2 = 0xbb
|
||||||
|
IFT_AAL5 = 0x31
|
||||||
|
IFT_ADSL = 0x5e
|
||||||
|
IFT_AFLANE8023 = 0x3b
|
||||||
|
IFT_AFLANE8025 = 0x3c
|
||||||
|
IFT_ARAP = 0x58
|
||||||
|
IFT_ARCNET = 0x23
|
||||||
|
IFT_ARCNETPLUS = 0x24
|
||||||
|
IFT_ASYNC = 0x54
|
||||||
|
IFT_ATM = 0x25
|
||||||
|
IFT_ATMDXI = 0x69
|
||||||
|
IFT_ATMFUNI = 0x6a
|
||||||
|
IFT_ATMIMA = 0x6b
|
||||||
|
IFT_ATMLOGICAL = 0x50
|
||||||
|
IFT_ATMRADIO = 0xbd
|
||||||
|
IFT_ATMSUBINTERFACE = 0x86
|
||||||
|
IFT_ATMVCIENDPT = 0xc2
|
||||||
|
IFT_ATMVIRTUAL = 0x95
|
||||||
|
IFT_BGPPOLICYACCOUNTING = 0xa2
|
||||||
|
IFT_BSC = 0x53
|
||||||
|
IFT_CCTEMUL = 0x3d
|
||||||
|
IFT_CEPT = 0x13
|
||||||
|
IFT_CES = 0x85
|
||||||
|
IFT_CHANNEL = 0x46
|
||||||
|
IFT_CNR = 0x55
|
||||||
|
IFT_COFFEE = 0x84
|
||||||
|
IFT_COMPOSITELINK = 0x9b
|
||||||
|
IFT_DCN = 0x8d
|
||||||
|
IFT_DIGITALPOWERLINE = 0x8a
|
||||||
|
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
|
||||||
|
IFT_DLSW = 0x4a
|
||||||
|
IFT_DOCSCABLEDOWNSTREAM = 0x80
|
||||||
|
IFT_DOCSCABLEMACLAYER = 0x7f
|
||||||
|
IFT_DOCSCABLEUPSTREAM = 0x81
|
||||||
|
IFT_DS0 = 0x51
|
||||||
|
IFT_DS0BUNDLE = 0x52
|
||||||
|
IFT_DS1FDL = 0xaa
|
||||||
|
IFT_DS3 = 0x1e
|
||||||
|
IFT_DTM = 0x8c
|
||||||
|
IFT_DVBASILN = 0xac
|
||||||
|
IFT_DVBASIOUT = 0xad
|
||||||
|
IFT_DVBRCCDOWNSTREAM = 0x93
|
||||||
|
IFT_DVBRCCMACLAYER = 0x92
|
||||||
|
IFT_DVBRCCUPSTREAM = 0x94
|
||||||
|
IFT_ENC = 0xf4
|
||||||
|
IFT_EON = 0x19
|
||||||
|
IFT_EPLRS = 0x57
|
||||||
|
IFT_ESCON = 0x49
|
||||||
|
IFT_ETHER = 0x6
|
||||||
|
IFT_FAST = 0x7d
|
||||||
|
IFT_FASTETHER = 0x3e
|
||||||
|
IFT_FASTETHERFX = 0x45
|
||||||
|
IFT_FDDI = 0xf
|
||||||
|
IFT_FIBRECHANNEL = 0x38
|
||||||
|
IFT_FRAMERELAYINTERCONNECT = 0x3a
|
||||||
|
IFT_FRAMERELAYMPI = 0x5c
|
||||||
|
IFT_FRDLCIENDPT = 0xc1
|
||||||
|
IFT_FRELAY = 0x20
|
||||||
|
IFT_FRELAYDCE = 0x2c
|
||||||
|
IFT_FRF16MFRBUNDLE = 0xa3
|
||||||
|
IFT_FRFORWARD = 0x9e
|
||||||
|
IFT_G703AT2MB = 0x43
|
||||||
|
IFT_G703AT64K = 0x42
|
||||||
|
IFT_GIF = 0xf0
|
||||||
|
IFT_GIGABITETHERNET = 0x75
|
||||||
|
IFT_GR303IDT = 0xb2
|
||||||
|
IFT_GR303RDT = 0xb1
|
||||||
|
IFT_H323GATEKEEPER = 0xa4
|
||||||
|
IFT_H323PROXY = 0xa5
|
||||||
|
IFT_HDH1822 = 0x3
|
||||||
|
IFT_HDLC = 0x76
|
||||||
|
IFT_HDSL2 = 0xa8
|
||||||
|
IFT_HIPERLAN2 = 0xb7
|
||||||
|
IFT_HIPPI = 0x2f
|
||||||
|
IFT_HIPPIINTERFACE = 0x39
|
||||||
|
IFT_HOSTPAD = 0x5a
|
||||||
|
IFT_HSSI = 0x2e
|
||||||
|
IFT_HY = 0xe
|
||||||
|
IFT_IBM370PARCHAN = 0x48
|
||||||
|
IFT_IDSL = 0x9a
|
||||||
|
IFT_IEEE80211 = 0x47
|
||||||
|
IFT_IEEE80212 = 0x37
|
||||||
|
IFT_IEEE8023ADLAG = 0xa1
|
||||||
|
IFT_IFGSN = 0x91
|
||||||
|
IFT_IMT = 0xbe
|
||||||
|
IFT_INTERLEAVE = 0x7c
|
||||||
|
IFT_IP = 0x7e
|
||||||
|
IFT_IPFORWARD = 0x8e
|
||||||
|
IFT_IPOVERATM = 0x72
|
||||||
|
IFT_IPOVERCDLC = 0x6d
|
||||||
|
IFT_IPOVERCLAW = 0x6e
|
||||||
|
IFT_IPSWITCH = 0x4e
|
||||||
|
IFT_ISDN = 0x3f
|
||||||
|
IFT_ISDNBASIC = 0x14
|
||||||
|
IFT_ISDNPRIMARY = 0x15
|
||||||
|
IFT_ISDNS = 0x4b
|
||||||
|
IFT_ISDNU = 0x4c
|
||||||
|
IFT_ISO88022LLC = 0x29
|
||||||
|
IFT_ISO88023 = 0x7
|
||||||
|
IFT_ISO88024 = 0x8
|
||||||
|
IFT_ISO88025 = 0x9
|
||||||
|
IFT_ISO88025CRFPINT = 0x62
|
||||||
|
IFT_ISO88025DTR = 0x56
|
||||||
|
IFT_ISO88025FIBER = 0x73
|
||||||
|
IFT_ISO88026 = 0xa
|
||||||
|
IFT_ISUP = 0xb3
|
||||||
|
IFT_L3IPXVLAN = 0x89
|
||||||
|
IFT_LAPB = 0x10
|
||||||
|
IFT_LAPD = 0x4d
|
||||||
|
IFT_LAPF = 0x77
|
||||||
|
IFT_LOCALTALK = 0x2a
|
||||||
|
IFT_LOOP = 0x18
|
||||||
|
IFT_MEDIAMAILOVERIP = 0x8b
|
||||||
|
IFT_MFSIGLINK = 0xa7
|
||||||
|
IFT_MIOX25 = 0x26
|
||||||
|
IFT_MODEM = 0x30
|
||||||
|
IFT_MPC = 0x71
|
||||||
|
IFT_MPLS = 0xa6
|
||||||
|
IFT_MPLSTUNNEL = 0x96
|
||||||
|
IFT_MSDSL = 0x8f
|
||||||
|
IFT_MVL = 0xbf
|
||||||
|
IFT_MYRINET = 0x63
|
||||||
|
IFT_NFAS = 0xaf
|
||||||
|
IFT_NSIP = 0x1b
|
||||||
|
IFT_OPTICALCHANNEL = 0xc3
|
||||||
|
IFT_OPTICALTRANSPORT = 0xc4
|
||||||
|
IFT_OTHER = 0x1
|
||||||
|
IFT_P10 = 0xc
|
||||||
|
IFT_P80 = 0xd
|
||||||
|
IFT_PARA = 0x22
|
||||||
|
IFT_PFLOG = 0xf6
|
||||||
|
IFT_PFSYNC = 0xf7
|
||||||
|
IFT_PLC = 0xae
|
||||||
|
IFT_POS = 0xab
|
||||||
|
IFT_PPPMULTILINKBUNDLE = 0x6c
|
||||||
|
IFT_PROPBWAP2MP = 0xb8
|
||||||
|
IFT_PROPCNLS = 0x59
|
||||||
|
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
|
||||||
|
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
|
||||||
|
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
|
||||||
|
IFT_PROPMUX = 0x36
|
||||||
|
IFT_PROPWIRELESSP2P = 0x9d
|
||||||
|
IFT_PTPSERIAL = 0x16
|
||||||
|
IFT_PVC = 0xf1
|
||||||
|
IFT_QLLC = 0x44
|
||||||
|
IFT_RADIOMAC = 0xbc
|
||||||
|
IFT_RADSL = 0x5f
|
||||||
|
IFT_REACHDSL = 0xc0
|
||||||
|
IFT_RFC1483 = 0x9f
|
||||||
|
IFT_RS232 = 0x21
|
||||||
|
IFT_RSRB = 0x4f
|
||||||
|
IFT_SDLC = 0x11
|
||||||
|
IFT_SDSL = 0x60
|
||||||
|
IFT_SHDSL = 0xa9
|
||||||
|
IFT_SIP = 0x1f
|
||||||
|
IFT_SLIP = 0x1c
|
||||||
|
IFT_SMDSDXI = 0x2b
|
||||||
|
IFT_SMDSICIP = 0x34
|
||||||
|
IFT_SONET = 0x27
|
||||||
|
IFT_SONETOVERHEADCHANNEL = 0xb9
|
||||||
|
IFT_SONETPATH = 0x32
|
||||||
|
IFT_SONETVT = 0x33
|
||||||
|
IFT_SRP = 0x97
|
||||||
|
IFT_SS7SIGLINK = 0x9c
|
||||||
|
IFT_STACKTOSTACK = 0x6f
|
||||||
|
IFT_STARLAN = 0xb
|
||||||
|
IFT_STF = 0xd7
|
||||||
|
IFT_T1 = 0x12
|
||||||
|
IFT_TDLC = 0x74
|
||||||
|
IFT_TERMPAD = 0x5b
|
||||||
|
IFT_TR008 = 0xb0
|
||||||
|
IFT_TRANSPHDLC = 0x7b
|
||||||
|
IFT_TUNNEL = 0x83
|
||||||
|
IFT_ULTRA = 0x1d
|
||||||
|
IFT_USB = 0xa0
|
||||||
|
IFT_V11 = 0x40
|
||||||
|
IFT_V35 = 0x2d
|
||||||
|
IFT_V36 = 0x41
|
||||||
|
IFT_V37 = 0x78
|
||||||
|
IFT_VDSL = 0x61
|
||||||
|
IFT_VIRTUALIPADDRESS = 0x70
|
||||||
|
IFT_VOICEEM = 0x64
|
||||||
|
IFT_VOICEENCAP = 0x67
|
||||||
|
IFT_VOICEFXO = 0x65
|
||||||
|
IFT_VOICEFXS = 0x66
|
||||||
|
IFT_VOICEOVERATM = 0x98
|
||||||
|
IFT_VOICEOVERFRAMERELAY = 0x99
|
||||||
|
IFT_VOICEOVERIP = 0x68
|
||||||
|
IFT_X213 = 0x5d
|
||||||
|
IFT_X25 = 0x5
|
||||||
|
IFT_X25DDN = 0x4
|
||||||
|
IFT_X25HUNTGROUP = 0x7a
|
||||||
|
IFT_X25MLP = 0x79
|
||||||
|
IFT_X25PLE = 0x28
|
||||||
|
IFT_XETHER = 0x1a
|
||||||
|
|
||||||
|
// missing constants on FreeBSD-11.1-RELEASE, copied from old values in ztypes_freebsd_arm.go
|
||||||
|
IFF_SMART = 0x20
|
||||||
|
IFT_FAITH = 0xf2
|
||||||
|
IFT_IPXIP = 0xf9
|
||||||
|
IPPROTO_MAXID = 0x34
|
||||||
|
IPV6_FAITH = 0x1d
|
||||||
|
IP_FAITH = 0x16
|
||||||
|
MAP_NORESERVE = 0x40
|
||||||
|
MAP_RENAME = 0x20
|
||||||
|
NET_RT_MAXID = 0x6
|
||||||
|
RTF_PRCLONING = 0x10000
|
||||||
|
RTM_OLDADD = 0x9
|
||||||
|
RTM_OLDDEL = 0xa
|
||||||
|
SIOCADDRT = 0x8030720a
|
||||||
|
SIOCALIFADDR = 0x8118691b
|
||||||
|
SIOCDELRT = 0x8030720b
|
||||||
|
SIOCDLIFADDR = 0x8118691d
|
||||||
|
SIOCGLIFADDR = 0xc118691c
|
||||||
|
SIOCGLIFPHYADDR = 0xc118694b
|
||||||
|
SIOCSLIFPHYADDR = 0x8118694a
|
||||||
|
)
|
17
vendor/golang.org/x/sys/unix/errors_freebsd_arm64.go
generated
vendored
Normal file
17
vendor/golang.org/x/sys/unix/errors_freebsd_arm64.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2020 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.
|
||||||
|
|
||||||
|
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
|
||||||
|
// them here for backwards compatibility.
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
const (
|
||||||
|
DLT_HHDLC = 0x79
|
||||||
|
IPV6_MIN_MEMBERSHIPS = 0x1f
|
||||||
|
IP_MAX_SOURCE_FILTER = 0x400
|
||||||
|
IP_MIN_MEMBERSHIPS = 0x1f
|
||||||
|
RT_CACHING_CONTEXT = 0x1
|
||||||
|
RT_NORTREF = 0x2
|
||||||
|
)
|
9
vendor/golang.org/x/sys/unix/ifreq_linux.go
generated
vendored
9
vendor/golang.org/x/sys/unix/ifreq_linux.go
generated
vendored
@ -8,6 +8,7 @@
|
|||||||
package unix
|
package unix
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,7 +45,13 @@ func NewIfreq(name string) (*Ifreq, error) {
|
|||||||
|
|
||||||
// Name returns the interface name associated with the Ifreq.
|
// Name returns the interface name associated with the Ifreq.
|
||||||
func (ifr *Ifreq) Name() string {
|
func (ifr *Ifreq) Name() string {
|
||||||
return ByteSliceToString(ifr.raw.Ifrn[:])
|
// BytePtrToString requires a NULL terminator or the program may crash. If
|
||||||
|
// one is not present, just return the empty string.
|
||||||
|
if !bytes.Contains(ifr.raw.Ifrn[:], []byte{0x00}) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return BytePtrToString(&ifr.raw.Ifrn[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to netdevice(7), only AF_INET addresses are returned for numerous
|
// According to netdevice(7), only AF_INET addresses are returned for numerous
|
||||||
|
43
vendor/golang.org/x/sys/unix/ioctl_linux.go
generated
vendored
43
vendor/golang.org/x/sys/unix/ioctl_linux.go
generated
vendored
@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
import "unsafe"
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// IoctlRetInt performs an ioctl operation specified by req on a device
|
// IoctlRetInt performs an ioctl operation specified by req on a device
|
||||||
// associated with opened file descriptor fd, and returns a non-negative
|
// associated with opened file descriptor fd, and returns a non-negative
|
||||||
@ -192,42 +194,3 @@ func ioctlIfreqData(fd int, req uint, value *ifreqData) error {
|
|||||||
// identical so pass *IfreqData directly.
|
// identical so pass *IfreqData directly.
|
||||||
return ioctlPtr(fd, req, unsafe.Pointer(value))
|
return ioctlPtr(fd, req, unsafe.Pointer(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IoctlKCMClone attaches a new file descriptor to a multiplexor by cloning an
|
|
||||||
// existing KCM socket, returning a structure containing the file descriptor of
|
|
||||||
// the new socket.
|
|
||||||
func IoctlKCMClone(fd int) (*KCMClone, error) {
|
|
||||||
var info KCMClone
|
|
||||||
if err := ioctlPtr(fd, SIOCKCMCLONE, unsafe.Pointer(&info)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &info, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IoctlKCMAttach attaches a TCP socket and associated BPF program file
|
|
||||||
// descriptor to a multiplexor.
|
|
||||||
func IoctlKCMAttach(fd int, info KCMAttach) error {
|
|
||||||
return ioctlPtr(fd, SIOCKCMATTACH, unsafe.Pointer(&info))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IoctlKCMUnattach unattaches a TCP socket file descriptor from a multiplexor.
|
|
||||||
func IoctlKCMUnattach(fd int, info KCMUnattach) error {
|
|
||||||
return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IoctlLoopGetStatus64 gets the status of the loop device associated with the
|
|
||||||
// file descriptor fd using the LOOP_GET_STATUS64 operation.
|
|
||||||
func IoctlLoopGetStatus64(fd int) (*LoopInfo64, error) {
|
|
||||||
var value LoopInfo64
|
|
||||||
if err := ioctlPtr(fd, LOOP_GET_STATUS64, unsafe.Pointer(&value)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IoctlLoopSetStatus64 sets the status of the loop device associated with the
|
|
||||||
// file descriptor fd using the LOOP_SET_STATUS64 operation.
|
|
||||||
func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error {
|
|
||||||
return ioctlPtr(fd, LOOP_SET_STATUS64, unsafe.Pointer(value))
|
|
||||||
}
|
|
||||||
|
58
vendor/golang.org/x/sys/unix/mkall.sh
generated
vendored
58
vendor/golang.org/x/sys/unix/mkall.sh
generated
vendored
@ -73,12 +73,12 @@ aix_ppc64)
|
|||||||
darwin_amd64)
|
darwin_amd64)
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
mkasm="go run mkasm.go"
|
mkasm="go run mkasm_darwin.go"
|
||||||
;;
|
;;
|
||||||
darwin_arm64)
|
darwin_arm64)
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
mkasm="go run mkasm.go"
|
mkasm="go run mkasm_darwin.go"
|
||||||
;;
|
;;
|
||||||
dragonfly_amd64)
|
dragonfly_amd64)
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
@ -89,30 +89,25 @@ dragonfly_amd64)
|
|||||||
freebsd_386)
|
freebsd_386)
|
||||||
mkerrors="$mkerrors -m32"
|
mkerrors="$mkerrors -m32"
|
||||||
mksyscall="go run mksyscall.go -l32"
|
mksyscall="go run mksyscall.go -l32"
|
||||||
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
|
mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
;;
|
;;
|
||||||
freebsd_amd64)
|
freebsd_amd64)
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
|
mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
;;
|
;;
|
||||||
freebsd_arm)
|
freebsd_arm)
|
||||||
mkerrors="$mkerrors"
|
mkerrors="$mkerrors"
|
||||||
mksyscall="go run mksyscall.go -l32 -arm"
|
mksyscall="go run mksyscall.go -l32 -arm"
|
||||||
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
|
mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
|
||||||
# Let the type of C char be signed for making the bare syscall
|
# Let the type of C char be signed for making the bare syscall
|
||||||
# API consistent across platforms.
|
# API consistent across platforms.
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||||
;;
|
;;
|
||||||
freebsd_arm64)
|
freebsd_arm64)
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
|
mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
|
||||||
;;
|
|
||||||
freebsd_riscv64)
|
|
||||||
mkerrors="$mkerrors -m64"
|
|
||||||
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
|
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||||
;;
|
;;
|
||||||
netbsd_386)
|
netbsd_386)
|
||||||
@ -142,33 +137,33 @@ netbsd_arm64)
|
|||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
;;
|
;;
|
||||||
openbsd_386)
|
openbsd_386)
|
||||||
mkasm="go run mkasm.go"
|
|
||||||
mkerrors="$mkerrors -m32"
|
mkerrors="$mkerrors -m32"
|
||||||
mksyscall="go run mksyscall.go -l32 -openbsd -libc"
|
mksyscall="go run mksyscall.go -l32 -openbsd"
|
||||||
mksysctl="go run mksysctl_openbsd.go"
|
mksysctl="go run mksysctl_openbsd.go"
|
||||||
|
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
;;
|
;;
|
||||||
openbsd_amd64)
|
openbsd_amd64)
|
||||||
mkasm="go run mkasm.go"
|
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mksyscall="go run mksyscall.go -openbsd -libc"
|
mksyscall="go run mksyscall.go -openbsd"
|
||||||
mksysctl="go run mksysctl_openbsd.go"
|
mksysctl="go run mksysctl_openbsd.go"
|
||||||
|
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
;;
|
;;
|
||||||
openbsd_arm)
|
openbsd_arm)
|
||||||
mkasm="go run mkasm.go"
|
|
||||||
mkerrors="$mkerrors"
|
mkerrors="$mkerrors"
|
||||||
mksyscall="go run mksyscall.go -l32 -openbsd -arm -libc"
|
mksyscall="go run mksyscall.go -l32 -openbsd -arm"
|
||||||
mksysctl="go run mksysctl_openbsd.go"
|
mksysctl="go run mksysctl_openbsd.go"
|
||||||
|
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
|
||||||
# Let the type of C char be signed for making the bare syscall
|
# Let the type of C char be signed for making the bare syscall
|
||||||
# API consistent across platforms.
|
# API consistent across platforms.
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||||
;;
|
;;
|
||||||
openbsd_arm64)
|
openbsd_arm64)
|
||||||
mkasm="go run mkasm.go"
|
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mksyscall="go run mksyscall.go -openbsd -libc"
|
mksyscall="go run mksyscall.go -openbsd"
|
||||||
mksysctl="go run mksysctl_openbsd.go"
|
mksysctl="go run mksysctl_openbsd.go"
|
||||||
|
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
|
||||||
# Let the type of C char be signed for making the bare syscall
|
# Let the type of C char be signed for making the bare syscall
|
||||||
# API consistent across platforms.
|
# API consistent across platforms.
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||||
@ -182,24 +177,6 @@ openbsd_mips64)
|
|||||||
# API consistent across platforms.
|
# API consistent across platforms.
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||||
;;
|
;;
|
||||||
openbsd_ppc64)
|
|
||||||
mkasm="go run mkasm.go"
|
|
||||||
mkerrors="$mkerrors -m64"
|
|
||||||
mksyscall="go run mksyscall.go -openbsd -libc"
|
|
||||||
mksysctl="go run mksysctl_openbsd.go"
|
|
||||||
# Let the type of C char be signed for making the bare syscall
|
|
||||||
# API consistent across platforms.
|
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
|
||||||
;;
|
|
||||||
openbsd_riscv64)
|
|
||||||
mkasm="go run mkasm.go"
|
|
||||||
mkerrors="$mkerrors -m64"
|
|
||||||
mksyscall="go run mksyscall.go -openbsd -libc"
|
|
||||||
mksysctl="go run mksysctl_openbsd.go"
|
|
||||||
# Let the type of C char be signed for making the bare syscall
|
|
||||||
# API consistent across platforms.
|
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
|
||||||
;;
|
|
||||||
solaris_amd64)
|
solaris_amd64)
|
||||||
mksyscall="go run mksyscall_solaris.go"
|
mksyscall="go run mksyscall_solaris.go"
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
@ -232,6 +209,11 @@ esac
|
|||||||
if [ "$GOOSARCH" == "aix_ppc64" ]; then
|
if [ "$GOOSARCH" == "aix_ppc64" ]; then
|
||||||
# aix/ppc64 script generates files instead of writing to stdin.
|
# aix/ppc64 script generates files instead of writing to stdin.
|
||||||
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
|
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
|
||||||
|
elif [ "$GOOS" == "darwin" ]; then
|
||||||
|
# 1.12 and later, syscalls via libSystem
|
||||||
|
echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
|
||||||
|
# 1.13 and later, syscalls via libSystem (including syscallPtr)
|
||||||
|
echo "$mksyscall -tags $GOOS,$GOARCH,go1.13 syscall_darwin.1_13.go |gofmt >zsyscall_$GOOSARCH.1_13.go";
|
||||||
elif [ "$GOOS" == "illumos" ]; then
|
elif [ "$GOOS" == "illumos" ]; then
|
||||||
# illumos code generation requires a --illumos switch
|
# illumos code generation requires a --illumos switch
|
||||||
echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";
|
echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";
|
||||||
@ -245,5 +227,5 @@ esac
|
|||||||
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
|
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
|
||||||
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
|
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
|
||||||
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
|
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
|
||||||
if [ -n "$mkasm" ]; then echo "$mkasm $GOOS $GOARCH"; fi
|
if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi
|
||||||
) | $run
|
) | $run
|
||||||
|
23
vendor/golang.org/x/sys/unix/mkerrors.sh
generated
vendored
23
vendor/golang.org/x/sys/unix/mkerrors.sh
generated
vendored
@ -128,7 +128,6 @@ includes_FreeBSD='
|
|||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/ptrace.h>
|
|
||||||
#include <net/bpf.h>
|
#include <net/bpf.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <net/if_types.h>
|
#include <net/if_types.h>
|
||||||
@ -203,11 +202,9 @@ struct ltchars {
|
|||||||
#include <sys/timerfd.h>
|
#include <sys/timerfd.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <sys/xattr.h>
|
#include <sys/xattr.h>
|
||||||
#include <linux/audit.h>
|
|
||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
#include <linux/can.h>
|
#include <linux/can.h>
|
||||||
#include <linux/can/error.h>
|
#include <linux/can/error.h>
|
||||||
#include <linux/can/netlink.h>
|
|
||||||
#include <linux/can/raw.h>
|
#include <linux/can/raw.h>
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
#include <linux/cryptouser.h>
|
#include <linux/cryptouser.h>
|
||||||
@ -217,7 +214,6 @@ struct ltchars {
|
|||||||
#include <linux/ethtool_netlink.h>
|
#include <linux/ethtool_netlink.h>
|
||||||
#include <linux/falloc.h>
|
#include <linux/falloc.h>
|
||||||
#include <linux/fanotify.h>
|
#include <linux/fanotify.h>
|
||||||
#include <linux/fib_rules.h>
|
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/fscrypt.h>
|
#include <linux/fscrypt.h>
|
||||||
@ -235,7 +231,6 @@ struct ltchars {
|
|||||||
#include <linux/if_packet.h>
|
#include <linux/if_packet.h>
|
||||||
#include <linux/if_xdp.h>
|
#include <linux/if_xdp.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/kcm.h>
|
|
||||||
#include <linux/kexec.h>
|
#include <linux/kexec.h>
|
||||||
#include <linux/keyctl.h>
|
#include <linux/keyctl.h>
|
||||||
#include <linux/landlock.h>
|
#include <linux/landlock.h>
|
||||||
@ -266,7 +261,6 @@ struct ltchars {
|
|||||||
#include <linux/vm_sockets.h>
|
#include <linux/vm_sockets.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
#include <linux/watchdog.h>
|
#include <linux/watchdog.h>
|
||||||
#include <linux/wireguard.h>
|
|
||||||
|
|
||||||
#include <mtd/ubi-user.h>
|
#include <mtd/ubi-user.h>
|
||||||
#include <mtd/mtd-user.h>
|
#include <mtd/mtd-user.h>
|
||||||
@ -297,10 +291,6 @@ struct ltchars {
|
|||||||
#define SOL_NETLINK 270
|
#define SOL_NETLINK 270
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SOL_SMC
|
|
||||||
#define SOL_SMC 286
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SOL_BLUETOOTH
|
#ifdef SOL_BLUETOOTH
|
||||||
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
|
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
|
||||||
// but it is already in bluetooth_linux.go
|
// but it is already in bluetooth_linux.go
|
||||||
@ -512,7 +502,6 @@ ccflags="$@"
|
|||||||
$2 ~ /^O?XTABS$/ ||
|
$2 ~ /^O?XTABS$/ ||
|
||||||
$2 ~ /^TC[IO](ON|OFF)$/ ||
|
$2 ~ /^TC[IO](ON|OFF)$/ ||
|
||||||
$2 ~ /^IN_/ ||
|
$2 ~ /^IN_/ ||
|
||||||
$2 ~ /^KCM/ ||
|
|
||||||
$2 ~ /^LANDLOCK_/ ||
|
$2 ~ /^LANDLOCK_/ ||
|
||||||
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
|
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
|
||||||
$2 ~ /^LO_(KEY|NAME)_SIZE$/ ||
|
$2 ~ /^LO_(KEY|NAME)_SIZE$/ ||
|
||||||
@ -535,7 +524,7 @@ ccflags="$@"
|
|||||||
$2 ~ /^(MS|MNT|MOUNT|UMOUNT)_/ ||
|
$2 ~ /^(MS|MNT|MOUNT|UMOUNT)_/ ||
|
||||||
$2 ~ /^NS_GET_/ ||
|
$2 ~ /^NS_GET_/ ||
|
||||||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
|
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
|
||||||
$2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|PIOD|TFD)_/ ||
|
$2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|TFD)_/ ||
|
||||||
$2 ~ /^KEXEC_/ ||
|
$2 ~ /^KEXEC_/ ||
|
||||||
$2 ~ /^LINUX_REBOOT_CMD_/ ||
|
$2 ~ /^LINUX_REBOOT_CMD_/ ||
|
||||||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
|
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
|
||||||
@ -559,7 +548,6 @@ ccflags="$@"
|
|||||||
$2 ~ /^CLONE_[A-Z_]+/ ||
|
$2 ~ /^CLONE_[A-Z_]+/ ||
|
||||||
$2 !~ /^(BPF_TIMEVAL|BPF_FIB_LOOKUP_[A-Z]+)$/ &&
|
$2 !~ /^(BPF_TIMEVAL|BPF_FIB_LOOKUP_[A-Z]+)$/ &&
|
||||||
$2 ~ /^(BPF|DLT)_/ ||
|
$2 ~ /^(BPF|DLT)_/ ||
|
||||||
$2 ~ /^AUDIT_/ ||
|
|
||||||
$2 ~ /^(CLOCK|TIMER)_/ ||
|
$2 ~ /^(CLOCK|TIMER)_/ ||
|
||||||
$2 ~ /^CAN_/ ||
|
$2 ~ /^CAN_/ ||
|
||||||
$2 ~ /^CAP_/ ||
|
$2 ~ /^CAP_/ ||
|
||||||
@ -582,6 +570,7 @@ ccflags="$@"
|
|||||||
$2 ~ /^SEEK_/ ||
|
$2 ~ /^SEEK_/ ||
|
||||||
$2 ~ /^SPLICE_/ ||
|
$2 ~ /^SPLICE_/ ||
|
||||||
$2 ~ /^SYNC_FILE_RANGE_/ ||
|
$2 ~ /^SYNC_FILE_RANGE_/ ||
|
||||||
|
$2 !~ /^AUDIT_RECORD_MAGIC/ &&
|
||||||
$2 !~ /IOC_MAGIC/ &&
|
$2 !~ /IOC_MAGIC/ &&
|
||||||
$2 ~ /^[A-Z][A-Z0-9_]+_MAGIC2?$/ ||
|
$2 ~ /^[A-Z][A-Z0-9_]+_MAGIC2?$/ ||
|
||||||
$2 ~ /^(VM|VMADDR)_/ ||
|
$2 ~ /^(VM|VMADDR)_/ ||
|
||||||
@ -607,10 +596,8 @@ ccflags="$@"
|
|||||||
$2 ~ /^DEVLINK_/ ||
|
$2 ~ /^DEVLINK_/ ||
|
||||||
$2 ~ /^ETHTOOL_/ ||
|
$2 ~ /^ETHTOOL_/ ||
|
||||||
$2 ~ /^LWTUNNEL_IP/ ||
|
$2 ~ /^LWTUNNEL_IP/ ||
|
||||||
$2 ~ /^ITIMER_/ ||
|
|
||||||
$2 !~ "WMESGLEN" &&
|
$2 !~ "WMESGLEN" &&
|
||||||
$2 ~ /^W[A-Z0-9]+$/ ||
|
$2 ~ /^W[A-Z0-9]+$/ ||
|
||||||
$2 ~ /^P_/ ||
|
|
||||||
$2 ~/^PPPIOC/ ||
|
$2 ~/^PPPIOC/ ||
|
||||||
$2 ~ /^FAN_|FANOTIFY_/ ||
|
$2 ~ /^FAN_|FANOTIFY_/ ||
|
||||||
$2 == "HID_MAX_DESCRIPTOR_SIZE" ||
|
$2 == "HID_MAX_DESCRIPTOR_SIZE" ||
|
||||||
@ -619,8 +606,6 @@ ccflags="$@"
|
|||||||
$2 ~ /^MTD/ ||
|
$2 ~ /^MTD/ ||
|
||||||
$2 ~ /^OTP/ ||
|
$2 ~ /^OTP/ ||
|
||||||
$2 ~ /^MEM/ ||
|
$2 ~ /^MEM/ ||
|
||||||
$2 ~ /^WG/ ||
|
|
||||||
$2 ~ /^FIB_RULE_/ ||
|
|
||||||
$2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)}
|
$2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)}
|
||||||
$2 ~ /^__WCOREFLAG$/ {next}
|
$2 ~ /^__WCOREFLAG$/ {next}
|
||||||
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
|
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
|
||||||
@ -642,7 +627,7 @@ errors=$(
|
|||||||
signals=$(
|
signals=$(
|
||||||
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
|
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
|
||||||
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
|
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
|
||||||
grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
|
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' |
|
||||||
sort
|
sort
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -652,7 +637,7 @@ echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
|
|||||||
sort >_error.grep
|
sort >_error.grep
|
||||||
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
|
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
|
||||||
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
|
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
|
||||||
grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
|
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' |
|
||||||
sort >_signal.grep
|
sort >_signal.grep
|
||||||
|
|
||||||
echo '// mkerrors.sh' "$@"
|
echo '// mkerrors.sh' "$@"
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user