3
0
mirror of https://github.com/ergochat/ergo.git synced 2025-12-28 05:47:56 +01:00

dependency upgrades for v2.18 release cycle (#2314)

This commit is contained in:
Shivaram Lingamneni 2025-12-23 00:07:39 -05:00 committed by GitHub
parent 462e568f00
commit 748700877e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
134 changed files with 7198 additions and 1595 deletions

13
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1 github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1
github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881 github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881
github.com/ergochat/irc-go v0.5.0-rc2 github.com/ergochat/irc-go v0.5.0-rc2
github.com/go-sql-driver/mysql v1.7.0 github.com/go-sql-driver/mysql v1.9.3
github.com/gofrs/flock v0.8.1 github.com/gofrs/flock v0.8.1
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd
@ -18,19 +18,20 @@ require (
github.com/stretchr/testify v1.4.0 // indirect github.com/stretchr/testify v1.4.0 // indirect
github.com/tidwall/buntdb v1.3.2 github.com/tidwall/buntdb v1.3.2
github.com/xdg-go/scram v1.0.2 github.com/xdg-go/scram v1.0.2
golang.org/x/crypto v0.38.0 golang.org/x/crypto v0.46.0
golang.org/x/term v0.32.0 golang.org/x/term v0.38.0
golang.org/x/text v0.25.0 golang.org/x/text v0.32.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
) )
require ( require (
github.com/emersion/go-msgauth v0.7.0 github.com/emersion/go-msgauth v0.7.0
github.com/ergochat/webpush-go/v2 v2.0.0 github.com/ergochat/webpush-go/v2 v2.0.0
github.com/golang-jwt/jwt/v5 v5.2.2 github.com/golang-jwt/jwt/v5 v5.3.0
) )
require ( require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/tidwall/btree v1.4.2 // indirect github.com/tidwall/btree v1.4.2 // indirect
github.com/tidwall/gjson v1.14.3 // indirect github.com/tidwall/gjson v1.14.3 // indirect
github.com/tidwall/grect v0.1.4 // indirect github.com/tidwall/grect v0.1.4 // indirect
@ -39,7 +40,7 @@ require (
github.com/tidwall/rtred v0.1.2 // indirect github.com/tidwall/rtred v0.1.2 // indirect
github.com/tidwall/tinyqueue v0.1.1 // indirect github.com/tidwall/tinyqueue v0.1.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect
golang.org/x/sys v0.33.0 // indirect golang.org/x/sys v0.39.0 // indirect
) )
replace github.com/gorilla/websocket => github.com/ergochat/websocket v1.4.2-oragono1 replace github.com/gorilla/websocket => github.com/ergochat/websocket v1.4.2-oragono1

40
go.sum
View File

@ -1,13 +1,13 @@
code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48 h1:/EMHruHCFXR9xClkGV/t0rmHrdhX4+trQUcBqjwc9xE= code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48 h1:/EMHruHCFXR9xClkGV/t0rmHrdhX4+trQUcBqjwc9xE=
code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc= code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 h1:KeNholpO2xKjgaaSyd+DyQRrsQjhbSeS7qe4nEw8aQw= github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 h1:KeNholpO2xKjgaaSyd+DyQRrsQjhbSeS7qe4nEw8aQw=
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962/go.mod h1:kC29dT1vFpj7py2OvG1khBdQpo3kInWP+6QipLbdngo= github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962/go.mod h1:kC29dT1vFpj7py2OvG1khBdQpo3kInWP+6QipLbdngo=
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/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/emersion/go-msgauth v0.6.8 h1:kW/0E9E8Zx5CdKsERC/WnAvnXvX7q9wTHia1OA4944A=
github.com/emersion/go-msgauth v0.6.8/go.mod h1:YDwuyTCUHu9xxmAeVj0eW4INnwB6NNZoPdLerpSxRrc=
github.com/emersion/go-msgauth v0.7.0 h1:vj2hMn6KhFtW41kshIBTXvp6KgYSqpA/ZN9Pv4g1INc= github.com/emersion/go-msgauth v0.7.0 h1:vj2hMn6KhFtW41kshIBTXvp6KgYSqpA/ZN9Pv4g1INc=
github.com/emersion/go-msgauth v0.7.0/go.mod h1:mmS9I6HkSovrNgq0HNXTeu8l3sRAAuQ9RMvbM4KU7Ck= github.com/emersion/go-msgauth v0.7.0/go.mod h1:mmS9I6HkSovrNgq0HNXTeu8l3sRAAuQ9RMvbM4KU7Ck=
github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1 h1:WLHTOodthVyv5NvYLIvWl112kSFv5IInKKrRN2qpons= github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1 h1:WLHTOodthVyv5NvYLIvWl112kSFv5IInKKrRN2qpons=
@ -23,12 +23,12 @@ github.com/ergochat/webpush-go/v2 v2.0.0/go.mod h1:OQlhnq8JeHDzRzAy6bdDObr19uqbH
github.com/ergochat/websocket v1.4.2-oragono1 h1:plMUunFBM6UoSCIYCKKclTdy/TkkHfUslhOfJQzfueM= github.com/ergochat/websocket v1.4.2-oragono1 h1:plMUunFBM6UoSCIYCKKclTdy/TkkHfUslhOfJQzfueM=
github.com/ergochat/websocket v1.4.2-oragono1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/ergochat/websocket v1.4.2-oragono1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@ -70,30 +70,22 @@ github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
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/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

27
vendor/filippo.io/edwards25519/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
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.

14
vendor/filippo.io/edwards25519/README.md generated vendored Normal file
View File

@ -0,0 +1,14 @@
# filippo.io/edwards25519
```
import "filippo.io/edwards25519"
```
This library implements the edwards25519 elliptic curve, exposing the necessary APIs to build a wide array of higher-level primitives.
Read the docs at [pkg.go.dev/filippo.io/edwards25519](https://pkg.go.dev/filippo.io/edwards25519).
The code is originally derived from Adam Langley's internal implementation in the Go standard library, and includes George Tankersley's [performance improvements](https://golang.org/cl/71950). It was then further developed by Henry de Valence for use in ristretto255, and was finally [merged back into the Go standard library](https://golang.org/cl/276272) as of Go 1.17. It now tracks the upstream codebase and extends it with additional functionality.
Most users don't need this package, and should instead use `crypto/ed25519` for signatures, `golang.org/x/crypto/curve25519` for Diffie-Hellman, or `github.com/gtank/ristretto255` for prime order group logic. However, for anyone currently using a fork of `crypto/internal/edwards25519`/`crypto/ed25519/internal/edwards25519` or `github.com/agl/edwards25519`, this package should be a safer, faster, and more powerful alternative.
Since this package is meant to curb proliferation of edwards25519 implementations in the Go ecosystem, it welcomes requests for new APIs or reviewable performance improvements.

20
vendor/filippo.io/edwards25519/doc.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// Copyright (c) 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.
// Package edwards25519 implements group logic for the twisted Edwards curve
//
// -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2
//
// This is better known as the Edwards curve equivalent to Curve25519, and is
// the curve used by the Ed25519 signature scheme.
//
// Most users don't need this package, and should instead use crypto/ed25519 for
// signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or
// github.com/gtank/ristretto255 for prime order group logic.
//
// However, developers who do need to interact with low-level edwards25519
// operations can use this package, which is an extended version of
// crypto/internal/edwards25519 from the standard library repackaged as
// an importable module.
package edwards25519

427
vendor/filippo.io/edwards25519/edwards25519.go generated vendored Normal file
View File

@ -0,0 +1,427 @@
// Copyright (c) 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 edwards25519
import (
"errors"
"filippo.io/edwards25519/field"
)
// Point types.
type projP1xP1 struct {
X, Y, Z, T field.Element
}
type projP2 struct {
X, Y, Z field.Element
}
// Point represents a point on the edwards25519 curve.
//
// This type works similarly to math/big.Int, and all arguments and receivers
// are allowed to alias.
//
// The zero value is NOT valid, and it may be used only as a receiver.
type Point struct {
// Make the type not comparable (i.e. used with == or as a map key), as
// equivalent points can be represented by different Go values.
_ incomparable
// The point is internally represented in extended coordinates (X, Y, Z, T)
// where x = X/Z, y = Y/Z, and xy = T/Z per https://eprint.iacr.org/2008/522.
x, y, z, t field.Element
}
type incomparable [0]func()
func checkInitialized(points ...*Point) {
for _, p := range points {
if p.x == (field.Element{}) && p.y == (field.Element{}) {
panic("edwards25519: use of uninitialized Point")
}
}
}
type projCached struct {
YplusX, YminusX, Z, T2d field.Element
}
type affineCached struct {
YplusX, YminusX, T2d field.Element
}
// Constructors.
func (v *projP2) Zero() *projP2 {
v.X.Zero()
v.Y.One()
v.Z.One()
return v
}
// identity is the point at infinity.
var identity, _ = new(Point).SetBytes([]byte{
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
// NewIdentityPoint returns a new Point set to the identity.
func NewIdentityPoint() *Point {
return new(Point).Set(identity)
}
// generator is the canonical curve basepoint. See TestGenerator for the
// correspondence of this encoding with the values in RFC 8032.
var generator, _ = new(Point).SetBytes([]byte{
0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66})
// NewGeneratorPoint returns a new Point set to the canonical generator.
func NewGeneratorPoint() *Point {
return new(Point).Set(generator)
}
func (v *projCached) Zero() *projCached {
v.YplusX.One()
v.YminusX.One()
v.Z.One()
v.T2d.Zero()
return v
}
func (v *affineCached) Zero() *affineCached {
v.YplusX.One()
v.YminusX.One()
v.T2d.Zero()
return v
}
// Assignments.
// Set sets v = u, and returns v.
func (v *Point) Set(u *Point) *Point {
*v = *u
return v
}
// Encoding.
// Bytes returns the canonical 32-byte encoding of v, according to RFC 8032,
// Section 5.1.2.
func (v *Point) Bytes() []byte {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap.
var buf [32]byte
return v.bytes(&buf)
}
func (v *Point) bytes(buf *[32]byte) []byte {
checkInitialized(v)
var zInv, x, y field.Element
zInv.Invert(&v.z) // zInv = 1 / Z
x.Multiply(&v.x, &zInv) // x = X / Z
y.Multiply(&v.y, &zInv) // y = Y / Z
out := copyFieldElement(buf, &y)
out[31] |= byte(x.IsNegative() << 7)
return out
}
var feOne = new(field.Element).One()
// SetBytes sets v = x, where x is a 32-byte encoding of v. If x does not
// represent a valid point on the curve, SetBytes returns nil and an error and
// the receiver is unchanged. Otherwise, SetBytes returns v.
//
// Note that SetBytes accepts all non-canonical encodings of valid points.
// That is, it follows decoding rules that match most implementations in
// the ecosystem rather than RFC 8032.
func (v *Point) SetBytes(x []byte) (*Point, error) {
// Specifically, the non-canonical encodings that are accepted are
// 1) the ones where the field element is not reduced (see the
// (*field.Element).SetBytes docs) and
// 2) the ones where the x-coordinate is zero and the sign bit is set.
//
// Read more at https://hdevalence.ca/blog/2020-10-04-its-25519am,
// specifically the "Canonical A, R" section.
y, err := new(field.Element).SetBytes(x)
if err != nil {
return nil, errors.New("edwards25519: invalid point encoding length")
}
// -x² + y² = 1 + dx²y²
// x² + dx²y² = x²(dy² + 1) = y² - 1
// x² = (y² - 1) / (dy² + 1)
// u = y² - 1
y2 := new(field.Element).Square(y)
u := new(field.Element).Subtract(y2, feOne)
// v = dy² + 1
vv := new(field.Element).Multiply(y2, d)
vv = vv.Add(vv, feOne)
// x = +√(u/v)
xx, wasSquare := new(field.Element).SqrtRatio(u, vv)
if wasSquare == 0 {
return nil, errors.New("edwards25519: invalid point encoding")
}
// Select the negative square root if the sign bit is set.
xxNeg := new(field.Element).Negate(xx)
xx = xx.Select(xxNeg, xx, int(x[31]>>7))
v.x.Set(xx)
v.y.Set(y)
v.z.One()
v.t.Multiply(xx, y) // xy = T / Z
return v, nil
}
func copyFieldElement(buf *[32]byte, v *field.Element) []byte {
copy(buf[:], v.Bytes())
return buf[:]
}
// Conversions.
func (v *projP2) FromP1xP1(p *projP1xP1) *projP2 {
v.X.Multiply(&p.X, &p.T)
v.Y.Multiply(&p.Y, &p.Z)
v.Z.Multiply(&p.Z, &p.T)
return v
}
func (v *projP2) FromP3(p *Point) *projP2 {
v.X.Set(&p.x)
v.Y.Set(&p.y)
v.Z.Set(&p.z)
return v
}
func (v *Point) fromP1xP1(p *projP1xP1) *Point {
v.x.Multiply(&p.X, &p.T)
v.y.Multiply(&p.Y, &p.Z)
v.z.Multiply(&p.Z, &p.T)
v.t.Multiply(&p.X, &p.Y)
return v
}
func (v *Point) fromP2(p *projP2) *Point {
v.x.Multiply(&p.X, &p.Z)
v.y.Multiply(&p.Y, &p.Z)
v.z.Square(&p.Z)
v.t.Multiply(&p.X, &p.Y)
return v
}
// d is a constant in the curve equation.
var d, _ = new(field.Element).SetBytes([]byte{
0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75,
0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00,
0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c,
0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52})
var d2 = new(field.Element).Add(d, d)
func (v *projCached) FromP3(p *Point) *projCached {
v.YplusX.Add(&p.y, &p.x)
v.YminusX.Subtract(&p.y, &p.x)
v.Z.Set(&p.z)
v.T2d.Multiply(&p.t, d2)
return v
}
func (v *affineCached) FromP3(p *Point) *affineCached {
v.YplusX.Add(&p.y, &p.x)
v.YminusX.Subtract(&p.y, &p.x)
v.T2d.Multiply(&p.t, d2)
var invZ field.Element
invZ.Invert(&p.z)
v.YplusX.Multiply(&v.YplusX, &invZ)
v.YminusX.Multiply(&v.YminusX, &invZ)
v.T2d.Multiply(&v.T2d, &invZ)
return v
}
// (Re)addition and subtraction.
// Add sets v = p + q, and returns v.
func (v *Point) Add(p, q *Point) *Point {
checkInitialized(p, q)
qCached := new(projCached).FromP3(q)
result := new(projP1xP1).Add(p, qCached)
return v.fromP1xP1(result)
}
// Subtract sets v = p - q, and returns v.
func (v *Point) Subtract(p, q *Point) *Point {
checkInitialized(p, q)
qCached := new(projCached).FromP3(q)
result := new(projP1xP1).Sub(p, qCached)
return v.fromP1xP1(result)
}
func (v *projP1xP1) Add(p *Point, q *projCached) *projP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
YplusX.Add(&p.y, &p.x)
YminusX.Subtract(&p.y, &p.x)
PP.Multiply(&YplusX, &q.YplusX)
MM.Multiply(&YminusX, &q.YminusX)
TT2d.Multiply(&p.t, &q.T2d)
ZZ2.Multiply(&p.z, &q.Z)
ZZ2.Add(&ZZ2, &ZZ2)
v.X.Subtract(&PP, &MM)
v.Y.Add(&PP, &MM)
v.Z.Add(&ZZ2, &TT2d)
v.T.Subtract(&ZZ2, &TT2d)
return v
}
func (v *projP1xP1) Sub(p *Point, q *projCached) *projP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
YplusX.Add(&p.y, &p.x)
YminusX.Subtract(&p.y, &p.x)
PP.Multiply(&YplusX, &q.YminusX) // flipped sign
MM.Multiply(&YminusX, &q.YplusX) // flipped sign
TT2d.Multiply(&p.t, &q.T2d)
ZZ2.Multiply(&p.z, &q.Z)
ZZ2.Add(&ZZ2, &ZZ2)
v.X.Subtract(&PP, &MM)
v.Y.Add(&PP, &MM)
v.Z.Subtract(&ZZ2, &TT2d) // flipped sign
v.T.Add(&ZZ2, &TT2d) // flipped sign
return v
}
func (v *projP1xP1) AddAffine(p *Point, q *affineCached) *projP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
YplusX.Add(&p.y, &p.x)
YminusX.Subtract(&p.y, &p.x)
PP.Multiply(&YplusX, &q.YplusX)
MM.Multiply(&YminusX, &q.YminusX)
TT2d.Multiply(&p.t, &q.T2d)
Z2.Add(&p.z, &p.z)
v.X.Subtract(&PP, &MM)
v.Y.Add(&PP, &MM)
v.Z.Add(&Z2, &TT2d)
v.T.Subtract(&Z2, &TT2d)
return v
}
func (v *projP1xP1) SubAffine(p *Point, q *affineCached) *projP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
YplusX.Add(&p.y, &p.x)
YminusX.Subtract(&p.y, &p.x)
PP.Multiply(&YplusX, &q.YminusX) // flipped sign
MM.Multiply(&YminusX, &q.YplusX) // flipped sign
TT2d.Multiply(&p.t, &q.T2d)
Z2.Add(&p.z, &p.z)
v.X.Subtract(&PP, &MM)
v.Y.Add(&PP, &MM)
v.Z.Subtract(&Z2, &TT2d) // flipped sign
v.T.Add(&Z2, &TT2d) // flipped sign
return v
}
// Doubling.
func (v *projP1xP1) Double(p *projP2) *projP1xP1 {
var XX, YY, ZZ2, XplusYsq field.Element
XX.Square(&p.X)
YY.Square(&p.Y)
ZZ2.Square(&p.Z)
ZZ2.Add(&ZZ2, &ZZ2)
XplusYsq.Add(&p.X, &p.Y)
XplusYsq.Square(&XplusYsq)
v.Y.Add(&YY, &XX)
v.Z.Subtract(&YY, &XX)
v.X.Subtract(&XplusYsq, &v.Y)
v.T.Subtract(&ZZ2, &v.Z)
return v
}
// Negation.
// Negate sets v = -p, and returns v.
func (v *Point) Negate(p *Point) *Point {
checkInitialized(p)
v.x.Negate(&p.x)
v.y.Set(&p.y)
v.z.Set(&p.z)
v.t.Negate(&p.t)
return v
}
// Equal returns 1 if v is equivalent to u, and 0 otherwise.
func (v *Point) Equal(u *Point) int {
checkInitialized(v, u)
var t1, t2, t3, t4 field.Element
t1.Multiply(&v.x, &u.z)
t2.Multiply(&u.x, &v.z)
t3.Multiply(&v.y, &u.z)
t4.Multiply(&u.y, &v.z)
return t1.Equal(&t2) & t3.Equal(&t4)
}
// Constant-time operations
// Select sets v to a if cond == 1 and to b if cond == 0.
func (v *projCached) Select(a, b *projCached, cond int) *projCached {
v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
v.Z.Select(&a.Z, &b.Z, cond)
v.T2d.Select(&a.T2d, &b.T2d, cond)
return v
}
// Select sets v to a if cond == 1 and to b if cond == 0.
func (v *affineCached) Select(a, b *affineCached, cond int) *affineCached {
v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
v.T2d.Select(&a.T2d, &b.T2d, cond)
return v
}
// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
func (v *projCached) CondNeg(cond int) *projCached {
v.YplusX.Swap(&v.YminusX, cond)
v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
return v
}
// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
func (v *affineCached) CondNeg(cond int) *affineCached {
v.YplusX.Swap(&v.YminusX, cond)
v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
return v
}

349
vendor/filippo.io/edwards25519/extra.go generated vendored Normal file
View File

@ -0,0 +1,349 @@
// Copyright (c) 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.
package edwards25519
// This file contains additional functionality that is not included in the
// upstream crypto/internal/edwards25519 package.
import (
"errors"
"filippo.io/edwards25519/field"
)
// ExtendedCoordinates returns v in extended coordinates (X:Y:Z:T) where
// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap. Don't change the style without making
// sure it doesn't increase the inliner cost.
var e [4]field.Element
X, Y, Z, T = v.extendedCoordinates(&e)
return
}
func (v *Point) extendedCoordinates(e *[4]field.Element) (X, Y, Z, T *field.Element) {
checkInitialized(v)
X = e[0].Set(&v.x)
Y = e[1].Set(&v.y)
Z = e[2].Set(&v.z)
T = e[3].Set(&v.t)
return
}
// SetExtendedCoordinates sets v = (X:Y:Z:T) in extended coordinates where
// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
//
// If the coordinates are invalid or don't represent a valid point on the curve,
// SetExtendedCoordinates returns nil and an error and the receiver is
// unchanged. Otherwise, SetExtendedCoordinates returns v.
func (v *Point) SetExtendedCoordinates(X, Y, Z, T *field.Element) (*Point, error) {
if !isOnCurve(X, Y, Z, T) {
return nil, errors.New("edwards25519: invalid point coordinates")
}
v.x.Set(X)
v.y.Set(Y)
v.z.Set(Z)
v.t.Set(T)
return v, nil
}
func isOnCurve(X, Y, Z, T *field.Element) bool {
var lhs, rhs field.Element
XX := new(field.Element).Square(X)
YY := new(field.Element).Square(Y)
ZZ := new(field.Element).Square(Z)
TT := new(field.Element).Square(T)
// -x² + y² = 1 + dx²y²
// -(X/Z)² + (Y/Z)² = 1 + d(T/Z)²
// -X² + Y² = Z² + dT²
lhs.Subtract(YY, XX)
rhs.Multiply(d, TT).Add(&rhs, ZZ)
if lhs.Equal(&rhs) != 1 {
return false
}
// xy = T/Z
// XY/Z² = T/Z
// XY = TZ
lhs.Multiply(X, Y)
rhs.Multiply(T, Z)
return lhs.Equal(&rhs) == 1
}
// BytesMontgomery converts v to a point on the birationally-equivalent
// Curve25519 Montgomery curve, and returns its canonical 32 bytes encoding
// according to RFC 7748.
//
// Note that BytesMontgomery only encodes the u-coordinate, so v and -v encode
// to the same value. If v is the identity point, BytesMontgomery returns 32
// zero bytes, analogously to the X25519 function.
//
// The lack of an inverse operation (such as SetMontgomeryBytes) is deliberate:
// while every valid edwards25519 point has a unique u-coordinate Montgomery
// encoding, X25519 accepts inputs on the quadratic twist, which don't correspond
// to any edwards25519 point, and every other X25519 input corresponds to two
// edwards25519 points.
func (v *Point) BytesMontgomery() []byte {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap.
var buf [32]byte
return v.bytesMontgomery(&buf)
}
func (v *Point) bytesMontgomery(buf *[32]byte) []byte {
checkInitialized(v)
// RFC 7748, Section 4.1 provides the bilinear map to calculate the
// Montgomery u-coordinate
//
// u = (1 + y) / (1 - y)
//
// where y = Y / Z.
var y, recip, u field.Element
y.Multiply(&v.y, y.Invert(&v.z)) // y = Y / Z
recip.Invert(recip.Subtract(feOne, &y)) // r = 1/(1 - y)
u.Multiply(u.Add(feOne, &y), &recip) // u = (1 + y)*r
return copyFieldElement(buf, &u)
}
// MultByCofactor sets v = 8 * p, and returns v.
func (v *Point) MultByCofactor(p *Point) *Point {
checkInitialized(p)
result := projP1xP1{}
pp := (&projP2{}).FromP3(p)
result.Double(pp)
pp.FromP1xP1(&result)
result.Double(pp)
pp.FromP1xP1(&result)
result.Double(pp)
return v.fromP1xP1(&result)
}
// Given k > 0, set s = s**(2*i).
func (s *Scalar) pow2k(k int) {
for i := 0; i < k; i++ {
s.Multiply(s, s)
}
}
// Invert sets s to the inverse of a nonzero scalar v, and returns s.
//
// If t is zero, Invert returns zero.
func (s *Scalar) Invert(t *Scalar) *Scalar {
// Uses a hardcoded sliding window of width 4.
var table [8]Scalar
var tt Scalar
tt.Multiply(t, t)
table[0] = *t
for i := 0; i < 7; i++ {
table[i+1].Multiply(&table[i], &tt)
}
// Now table = [t**1, t**3, t**5, t**7, t**9, t**11, t**13, t**15]
// so t**k = t[k/2] for odd k
// To compute the sliding window digits, use the following Sage script:
// sage: import itertools
// sage: def sliding_window(w,k):
// ....: digits = []
// ....: while k > 0:
// ....: if k % 2 == 1:
// ....: kmod = k % (2**w)
// ....: digits.append(kmod)
// ....: k = k - kmod
// ....: else:
// ....: digits.append(0)
// ....: k = k // 2
// ....: return digits
// Now we can compute s roughly as follows:
// sage: s = 1
// sage: for coeff in reversed(sliding_window(4,l-2)):
// ....: s = s*s
// ....: if coeff > 0 :
// ....: s = s*t**coeff
// This works on one bit at a time, with many runs of zeros.
// The digits can be collapsed into [(count, coeff)] as follows:
// sage: [(len(list(group)),d) for d,group in itertools.groupby(sliding_window(4,l-2))]
// Entries of the form (k, 0) turn into pow2k(k)
// Entries of the form (1, coeff) turn into a squaring and then a table lookup.
// We can fold the squaring into the previous pow2k(k) as pow2k(k+1).
*s = table[1/2]
s.pow2k(127 + 1)
s.Multiply(s, &table[1/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[9/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[11/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[13/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[15/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[7/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[15/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[5/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[1/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[15/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[15/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[7/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[3/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[11/2])
s.pow2k(5 + 1)
s.Multiply(s, &table[11/2])
s.pow2k(9 + 1)
s.Multiply(s, &table[9/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[3/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[3/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[3/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[9/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[7/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[3/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[13/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[7/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[9/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[15/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[11/2])
return s
}
// MultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v.
//
// Execution time depends only on the lengths of the two slices, which must match.
func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point {
if len(scalars) != len(points) {
panic("edwards25519: called MultiScalarMult with different size inputs")
}
checkInitialized(points...)
// Proceed as in the single-base case, but share doublings
// between each point in the multiscalar equation.
// Build lookup tables for each point
tables := make([]projLookupTable, len(points))
for i := range tables {
tables[i].FromP3(points[i])
}
// Compute signed radix-16 digits for each scalar
digits := make([][64]int8, len(scalars))
for i := range digits {
digits[i] = scalars[i].signedRadix16()
}
// Unwrap first loop iteration to save computing 16*identity
multiple := &projCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
// Lookup-and-add the appropriate multiple of each input point
for j := range tables {
tables[j].SelectInto(multiple, digits[j][63])
tmp1.Add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords
v.fromP1xP1(tmp1) // update v
}
tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration
for i := 62; i >= 0; i-- {
tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords
// Lookup-and-add the appropriate multiple of each input point
for j := range tables {
tables[j].SelectInto(multiple, digits[j][i])
tmp1.Add(v, multiple) // tmp1 = v + x_(j,i)*Q in P1xP1 coords
v.fromP1xP1(tmp1) // update v
}
tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration
}
return v
}
// VarTimeMultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v.
//
// Execution time depends on the inputs.
func (v *Point) VarTimeMultiScalarMult(scalars []*Scalar, points []*Point) *Point {
if len(scalars) != len(points) {
panic("edwards25519: called VarTimeMultiScalarMult with different size inputs")
}
checkInitialized(points...)
// Generalize double-base NAF computation to arbitrary sizes.
// Here all the points are dynamic, so we only use the smaller
// tables.
// Build lookup tables for each point
tables := make([]nafLookupTable5, len(points))
for i := range tables {
tables[i].FromP3(points[i])
}
// Compute a NAF for each scalar
nafs := make([][256]int8, len(scalars))
for i := range nafs {
nafs[i] = scalars[i].nonAdjacentForm(5)
}
multiple := &projCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
tmp2.Zero()
// Move from high to low bits, doubling the accumulator
// at each iteration and checking whether there is a nonzero
// coefficient to look up a multiple of.
//
// Skip trying to find the first nonzero coefficent, because
// searching might be more work than a few extra doublings.
for i := 255; i >= 0; i-- {
tmp1.Double(tmp2)
for j := range nafs {
if nafs[j][i] > 0 {
v.fromP1xP1(tmp1)
tables[j].SelectInto(multiple, nafs[j][i])
tmp1.Add(v, multiple)
} else if nafs[j][i] < 0 {
v.fromP1xP1(tmp1)
tables[j].SelectInto(multiple, -nafs[j][i])
tmp1.Sub(v, multiple)
}
}
tmp2.FromP1xP1(tmp1)
}
v.fromP2(tmp2)
return v
}

420
vendor/filippo.io/edwards25519/field/fe.go generated vendored Normal file
View File

@ -0,0 +1,420 @@
// Copyright (c) 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 field implements fast arithmetic modulo 2^255-19.
package field
import (
"crypto/subtle"
"encoding/binary"
"errors"
"math/bits"
)
// Element represents an element of the field GF(2^255-19). Note that this
// is not a cryptographically secure group, and should only be used to interact
// with edwards25519.Point coordinates.
//
// This type works similarly to math/big.Int, and all arguments and receivers
// are allowed to alias.
//
// The zero value is a valid zero element.
type Element struct {
// An element t represents the integer
// t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
//
// Between operations, all limbs are expected to be lower than 2^52.
l0 uint64
l1 uint64
l2 uint64
l3 uint64
l4 uint64
}
const maskLow51Bits uint64 = (1 << 51) - 1
var feZero = &Element{0, 0, 0, 0, 0}
// Zero sets v = 0, and returns v.
func (v *Element) Zero() *Element {
*v = *feZero
return v
}
var feOne = &Element{1, 0, 0, 0, 0}
// One sets v = 1, and returns v.
func (v *Element) One() *Element {
*v = *feOne
return v
}
// reduce reduces v modulo 2^255 - 19 and returns it.
func (v *Element) reduce() *Element {
v.carryPropagate()
// After the light reduction we now have a field element representation
// v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
// If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
// generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
c := (v.l0 + 19) >> 51
c = (v.l1 + c) >> 51
c = (v.l2 + c) >> 51
c = (v.l3 + c) >> 51
c = (v.l4 + c) >> 51
// If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
// effectively applying the reduction identity to the carry.
v.l0 += 19 * c
v.l1 += v.l0 >> 51
v.l0 = v.l0 & maskLow51Bits
v.l2 += v.l1 >> 51
v.l1 = v.l1 & maskLow51Bits
v.l3 += v.l2 >> 51
v.l2 = v.l2 & maskLow51Bits
v.l4 += v.l3 >> 51
v.l3 = v.l3 & maskLow51Bits
// no additional carry
v.l4 = v.l4 & maskLow51Bits
return v
}
// Add sets v = a + b, and returns v.
func (v *Element) Add(a, b *Element) *Element {
v.l0 = a.l0 + b.l0
v.l1 = a.l1 + b.l1
v.l2 = a.l2 + b.l2
v.l3 = a.l3 + b.l3
v.l4 = a.l4 + b.l4
// Using the generic implementation here is actually faster than the
// assembly. Probably because the body of this function is so simple that
// the compiler can figure out better optimizations by inlining the carry
// propagation.
return v.carryPropagateGeneric()
}
// Subtract sets v = a - b, and returns v.
func (v *Element) Subtract(a, b *Element) *Element {
// We first add 2 * p, to guarantee the subtraction won't underflow, and
// then subtract b (which can be up to 2^255 + 2^13 * 19).
v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
return v.carryPropagate()
}
// Negate sets v = -a, and returns v.
func (v *Element) Negate(a *Element) *Element {
return v.Subtract(feZero, a)
}
// Invert sets v = 1/z mod p, and returns v.
//
// If z == 0, Invert returns v = 0.
func (v *Element) Invert(z *Element) *Element {
// Inversion is implemented as exponentiation with exponent p 2. It uses the
// same sequence of 255 squarings and 11 multiplications as [Curve25519].
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
z2.Square(z) // 2
t.Square(&z2) // 4
t.Square(&t) // 8
z9.Multiply(&t, z) // 9
z11.Multiply(&z9, &z2) // 11
t.Square(&z11) // 22
z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
t.Square(&z2_5_0) // 2^6 - 2^1
for i := 0; i < 4; i++ {
t.Square(&t) // 2^10 - 2^5
}
z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
t.Square(&z2_10_0) // 2^11 - 2^1
for i := 0; i < 9; i++ {
t.Square(&t) // 2^20 - 2^10
}
z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
t.Square(&z2_20_0) // 2^21 - 2^1
for i := 0; i < 19; i++ {
t.Square(&t) // 2^40 - 2^20
}
t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
t.Square(&t) // 2^41 - 2^1
for i := 0; i < 9; i++ {
t.Square(&t) // 2^50 - 2^10
}
z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
t.Square(&z2_50_0) // 2^51 - 2^1
for i := 0; i < 49; i++ {
t.Square(&t) // 2^100 - 2^50
}
z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
t.Square(&z2_100_0) // 2^101 - 2^1
for i := 0; i < 99; i++ {
t.Square(&t) // 2^200 - 2^100
}
t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
t.Square(&t) // 2^201 - 2^1
for i := 0; i < 49; i++ {
t.Square(&t) // 2^250 - 2^50
}
t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
t.Square(&t) // 2^251 - 2^1
t.Square(&t) // 2^252 - 2^2
t.Square(&t) // 2^253 - 2^3
t.Square(&t) // 2^254 - 2^4
t.Square(&t) // 2^255 - 2^5
return v.Multiply(&t, &z11) // 2^255 - 21
}
// Set sets v = a, and returns v.
func (v *Element) Set(a *Element) *Element {
*v = *a
return v
}
// SetBytes sets v to x, where x is a 32-byte little-endian encoding. If x is
// not of the right length, SetBytes returns nil and an error, and the
// receiver is unchanged.
//
// Consistent with RFC 7748, the most significant bit (the high bit of the
// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
// are accepted. Note that this is laxer than specified by RFC 8032, but
// consistent with most Ed25519 implementations.
func (v *Element) SetBytes(x []byte) (*Element, error) {
if len(x) != 32 {
return nil, errors.New("edwards25519: invalid field element input size")
}
// Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
v.l0 = binary.LittleEndian.Uint64(x[0:8])
v.l0 &= maskLow51Bits
// Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
v.l1 &= maskLow51Bits
// Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
v.l2 &= maskLow51Bits
// Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
v.l3 &= maskLow51Bits
// Bits 204:255 (bytes 24:32, bits 192:256, shift 12, mask 51).
// Note: not bytes 25:33, shift 4, to avoid overread.
v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
v.l4 &= maskLow51Bits
return v, nil
}
// Bytes returns the canonical 32-byte little-endian encoding of v.
func (v *Element) Bytes() []byte {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap.
var out [32]byte
return v.bytes(&out)
}
func (v *Element) bytes(out *[32]byte) []byte {
t := *v
t.reduce()
var buf [8]byte
for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
bitsOffset := i * 51
binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8))
for i, bb := range buf {
off := bitsOffset/8 + i
if off >= len(out) {
break
}
out[off] |= bb
}
}
return out[:]
}
// Equal returns 1 if v and u are equal, and 0 otherwise.
func (v *Element) Equal(u *Element) int {
sa, sv := u.Bytes(), v.Bytes()
return subtle.ConstantTimeCompare(sa, sv)
}
// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
// Select sets v to a if cond == 1, and to b if cond == 0.
func (v *Element) Select(a, b *Element, cond int) *Element {
m := mask64Bits(cond)
v.l0 = (m & a.l0) | (^m & b.l0)
v.l1 = (m & a.l1) | (^m & b.l1)
v.l2 = (m & a.l2) | (^m & b.l2)
v.l3 = (m & a.l3) | (^m & b.l3)
v.l4 = (m & a.l4) | (^m & b.l4)
return v
}
// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
func (v *Element) Swap(u *Element, cond int) {
m := mask64Bits(cond)
t := m & (v.l0 ^ u.l0)
v.l0 ^= t
u.l0 ^= t
t = m & (v.l1 ^ u.l1)
v.l1 ^= t
u.l1 ^= t
t = m & (v.l2 ^ u.l2)
v.l2 ^= t
u.l2 ^= t
t = m & (v.l3 ^ u.l3)
v.l3 ^= t
u.l3 ^= t
t = m & (v.l4 ^ u.l4)
v.l4 ^= t
u.l4 ^= t
}
// IsNegative returns 1 if v is negative, and 0 otherwise.
func (v *Element) IsNegative() int {
return int(v.Bytes()[0] & 1)
}
// Absolute sets v to |u|, and returns v.
func (v *Element) Absolute(u *Element) *Element {
return v.Select(new(Element).Negate(u), u, u.IsNegative())
}
// Multiply sets v = x * y, and returns v.
func (v *Element) Multiply(x, y *Element) *Element {
feMul(v, x, y)
return v
}
// Square sets v = x * x, and returns v.
func (v *Element) Square(x *Element) *Element {
feSquare(v, x)
return v
}
// Mult32 sets v = x * y, and returns v.
func (v *Element) Mult32(x *Element, y uint32) *Element {
x0lo, x0hi := mul51(x.l0, y)
x1lo, x1hi := mul51(x.l1, y)
x2lo, x2hi := mul51(x.l2, y)
x3lo, x3hi := mul51(x.l3, y)
x4lo, x4hi := mul51(x.l4, y)
v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
v.l1 = x1lo + x0hi
v.l2 = x2lo + x1hi
v.l3 = x3lo + x2hi
v.l4 = x4lo + x3hi
// The hi portions are going to be only 32 bits, plus any previous excess,
// so we can skip the carry propagation.
return v
}
// mul51 returns lo + hi * 2⁵¹ = a * b.
func mul51(a uint64, b uint32) (lo uint64, hi uint64) {
mh, ml := bits.Mul64(a, uint64(b))
lo = ml & maskLow51Bits
hi = (mh << 13) | (ml >> 51)
return
}
// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
func (v *Element) Pow22523(x *Element) *Element {
var t0, t1, t2 Element
t0.Square(x) // x^2
t1.Square(&t0) // x^4
t1.Square(&t1) // x^8
t1.Multiply(x, &t1) // x^9
t0.Multiply(&t0, &t1) // x^11
t0.Square(&t0) // x^22
t0.Multiply(&t1, &t0) // x^31
t1.Square(&t0) // x^62
for i := 1; i < 5; i++ { // x^992
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1
t1.Square(&t0) // 2^11 - 2
for i := 1; i < 10; i++ { // 2^20 - 2^10
t1.Square(&t1)
}
t1.Multiply(&t1, &t0) // 2^20 - 1
t2.Square(&t1) // 2^21 - 2
for i := 1; i < 20; i++ { // 2^40 - 2^20
t2.Square(&t2)
}
t1.Multiply(&t2, &t1) // 2^40 - 1
t1.Square(&t1) // 2^41 - 2
for i := 1; i < 10; i++ { // 2^50 - 2^10
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // 2^50 - 1
t1.Square(&t0) // 2^51 - 2
for i := 1; i < 50; i++ { // 2^100 - 2^50
t1.Square(&t1)
}
t1.Multiply(&t1, &t0) // 2^100 - 1
t2.Square(&t1) // 2^101 - 2
for i := 1; i < 100; i++ { // 2^200 - 2^100
t2.Square(&t2)
}
t1.Multiply(&t2, &t1) // 2^200 - 1
t1.Square(&t1) // 2^201 - 2
for i := 1; i < 50; i++ { // 2^250 - 2^50
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // 2^250 - 1
t0.Square(&t0) // 2^251 - 2
t0.Square(&t0) // 2^252 - 4
return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
}
// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
var sqrtM1 = &Element{1718705420411056, 234908883556509,
2233514472574048, 2117202627021982, 765476049583133}
// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
//
// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
// and returns r and 0.
func (r *Element) SqrtRatio(u, v *Element) (R *Element, wasSquare int) {
t0 := new(Element)
// r = (u * v3) * (u * v7)^((p-5)/8)
v2 := new(Element).Square(v)
uv3 := new(Element).Multiply(u, t0.Multiply(v2, v))
uv7 := new(Element).Multiply(uv3, t0.Square(v2))
rr := new(Element).Multiply(uv3, t0.Pow22523(uv7))
check := new(Element).Multiply(v, t0.Square(rr)) // check = v * r^2
uNeg := new(Element).Negate(u)
correctSignSqrt := check.Equal(u)
flippedSignSqrt := check.Equal(uNeg)
flippedSignSqrtI := check.Equal(t0.Multiply(uNeg, sqrtM1))
rPrime := new(Element).Multiply(rr, sqrtM1) // r_prime = SQRT_M1 * r
// r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
rr.Select(rPrime, rr, flippedSignSqrt|flippedSignSqrtI)
r.Absolute(rr) // Choose the nonnegative square root.
return r, correctSignSqrt | flippedSignSqrt
}

16
vendor/filippo.io/edwards25519/field/fe_amd64.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
package field
// feMul sets out = a * b. It works like feMulGeneric.
//
//go:noescape
func feMul(out *Element, a *Element, b *Element)
// feSquare sets out = a * a. It works like feSquareGeneric.
//
//go:noescape
func feSquare(out *Element, a *Element)

379
vendor/filippo.io/edwards25519/field/fe_amd64.s generated vendored Normal file
View File

@ -0,0 +1,379 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
#include "textflag.h"
// func feMul(out *Element, a *Element, b *Element)
TEXT ·feMul(SB), NOSPLIT, $0-24
MOVQ a+8(FP), CX
MOVQ b+16(FP), BX
// r0 = a0×b0
MOVQ (CX), AX
MULQ (BX)
MOVQ AX, DI
MOVQ DX, SI
// r0 += 19×a1×b4
MOVQ 8(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, DI
ADCQ DX, SI
// r0 += 19×a2×b3
MOVQ 16(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(BX)
ADDQ AX, DI
ADCQ DX, SI
// r0 += 19×a3×b2
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 16(BX)
ADDQ AX, DI
ADCQ DX, SI
// r0 += 19×a4×b1
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 8(BX)
ADDQ AX, DI
ADCQ DX, SI
// r1 = a0×b1
MOVQ (CX), AX
MULQ 8(BX)
MOVQ AX, R9
MOVQ DX, R8
// r1 += a1×b0
MOVQ 8(CX), AX
MULQ (BX)
ADDQ AX, R9
ADCQ DX, R8
// r1 += 19×a2×b4
MOVQ 16(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, R9
ADCQ DX, R8
// r1 += 19×a3×b3
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(BX)
ADDQ AX, R9
ADCQ DX, R8
// r1 += 19×a4×b2
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 16(BX)
ADDQ AX, R9
ADCQ DX, R8
// r2 = a0×b2
MOVQ (CX), AX
MULQ 16(BX)
MOVQ AX, R11
MOVQ DX, R10
// r2 += a1×b1
MOVQ 8(CX), AX
MULQ 8(BX)
ADDQ AX, R11
ADCQ DX, R10
// r2 += a2×b0
MOVQ 16(CX), AX
MULQ (BX)
ADDQ AX, R11
ADCQ DX, R10
// r2 += 19×a3×b4
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, R11
ADCQ DX, R10
// r2 += 19×a4×b3
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(BX)
ADDQ AX, R11
ADCQ DX, R10
// r3 = a0×b3
MOVQ (CX), AX
MULQ 24(BX)
MOVQ AX, R13
MOVQ DX, R12
// r3 += a1×b2
MOVQ 8(CX), AX
MULQ 16(BX)
ADDQ AX, R13
ADCQ DX, R12
// r3 += a2×b1
MOVQ 16(CX), AX
MULQ 8(BX)
ADDQ AX, R13
ADCQ DX, R12
// r3 += a3×b0
MOVQ 24(CX), AX
MULQ (BX)
ADDQ AX, R13
ADCQ DX, R12
// r3 += 19×a4×b4
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, R13
ADCQ DX, R12
// r4 = a0×b4
MOVQ (CX), AX
MULQ 32(BX)
MOVQ AX, R15
MOVQ DX, R14
// r4 += a1×b3
MOVQ 8(CX), AX
MULQ 24(BX)
ADDQ AX, R15
ADCQ DX, R14
// r4 += a2×b2
MOVQ 16(CX), AX
MULQ 16(BX)
ADDQ AX, R15
ADCQ DX, R14
// r4 += a3×b1
MOVQ 24(CX), AX
MULQ 8(BX)
ADDQ AX, R15
ADCQ DX, R14
// r4 += a4×b0
MOVQ 32(CX), AX
MULQ (BX)
ADDQ AX, R15
ADCQ DX, R14
// First reduction chain
MOVQ $0x0007ffffffffffff, AX
SHLQ $0x0d, DI, SI
SHLQ $0x0d, R9, R8
SHLQ $0x0d, R11, R10
SHLQ $0x0d, R13, R12
SHLQ $0x0d, R15, R14
ANDQ AX, DI
IMUL3Q $0x13, R14, R14
ADDQ R14, DI
ANDQ AX, R9
ADDQ SI, R9
ANDQ AX, R11
ADDQ R8, R11
ANDQ AX, R13
ADDQ R10, R13
ANDQ AX, R15
ADDQ R12, R15
// Second reduction chain (carryPropagate)
MOVQ DI, SI
SHRQ $0x33, SI
MOVQ R9, R8
SHRQ $0x33, R8
MOVQ R11, R10
SHRQ $0x33, R10
MOVQ R13, R12
SHRQ $0x33, R12
MOVQ R15, R14
SHRQ $0x33, R14
ANDQ AX, DI
IMUL3Q $0x13, R14, R14
ADDQ R14, DI
ANDQ AX, R9
ADDQ SI, R9
ANDQ AX, R11
ADDQ R8, R11
ANDQ AX, R13
ADDQ R10, R13
ANDQ AX, R15
ADDQ R12, R15
// Store output
MOVQ out+0(FP), AX
MOVQ DI, (AX)
MOVQ R9, 8(AX)
MOVQ R11, 16(AX)
MOVQ R13, 24(AX)
MOVQ R15, 32(AX)
RET
// func feSquare(out *Element, a *Element)
TEXT ·feSquare(SB), NOSPLIT, $0-16
MOVQ a+8(FP), CX
// r0 = l0×l0
MOVQ (CX), AX
MULQ (CX)
MOVQ AX, SI
MOVQ DX, BX
// r0 += 38×l1×l4
MOVQ 8(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 32(CX)
ADDQ AX, SI
ADCQ DX, BX
// r0 += 38×l2×l3
MOVQ 16(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 24(CX)
ADDQ AX, SI
ADCQ DX, BX
// r1 = 2×l0×l1
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 8(CX)
MOVQ AX, R8
MOVQ DX, DI
// r1 += 38×l2×l4
MOVQ 16(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 32(CX)
ADDQ AX, R8
ADCQ DX, DI
// r1 += 19×l3×l3
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(CX)
ADDQ AX, R8
ADCQ DX, DI
// r2 = 2×l0×l2
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 16(CX)
MOVQ AX, R10
MOVQ DX, R9
// r2 += l1×l1
MOVQ 8(CX), AX
MULQ 8(CX)
ADDQ AX, R10
ADCQ DX, R9
// r2 += 38×l3×l4
MOVQ 24(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 32(CX)
ADDQ AX, R10
ADCQ DX, R9
// r3 = 2×l0×l3
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 24(CX)
MOVQ AX, R12
MOVQ DX, R11
// r3 += 2×l1×l2
MOVQ 8(CX), AX
IMUL3Q $0x02, AX, AX
MULQ 16(CX)
ADDQ AX, R12
ADCQ DX, R11
// r3 += 19×l4×l4
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(CX)
ADDQ AX, R12
ADCQ DX, R11
// r4 = 2×l0×l4
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 32(CX)
MOVQ AX, R14
MOVQ DX, R13
// r4 += 2×l1×l3
MOVQ 8(CX), AX
IMUL3Q $0x02, AX, AX
MULQ 24(CX)
ADDQ AX, R14
ADCQ DX, R13
// r4 += l2×l2
MOVQ 16(CX), AX
MULQ 16(CX)
ADDQ AX, R14
ADCQ DX, R13
// First reduction chain
MOVQ $0x0007ffffffffffff, AX
SHLQ $0x0d, SI, BX
SHLQ $0x0d, R8, DI
SHLQ $0x0d, R10, R9
SHLQ $0x0d, R12, R11
SHLQ $0x0d, R14, R13
ANDQ AX, SI
IMUL3Q $0x13, R13, R13
ADDQ R13, SI
ANDQ AX, R8
ADDQ BX, R8
ANDQ AX, R10
ADDQ DI, R10
ANDQ AX, R12
ADDQ R9, R12
ANDQ AX, R14
ADDQ R11, R14
// Second reduction chain (carryPropagate)
MOVQ SI, BX
SHRQ $0x33, BX
MOVQ R8, DI
SHRQ $0x33, DI
MOVQ R10, R9
SHRQ $0x33, R9
MOVQ R12, R11
SHRQ $0x33, R11
MOVQ R14, R13
SHRQ $0x33, R13
ANDQ AX, SI
IMUL3Q $0x13, R13, R13
ADDQ R13, SI
ANDQ AX, R8
ADDQ BX, R8
ANDQ AX, R10
ADDQ DI, R10
ANDQ AX, R12
ADDQ R9, R12
ANDQ AX, R14
ADDQ R11, R14
// Store output
MOVQ out+0(FP), AX
MOVQ SI, (AX)
MOVQ R8, 8(AX)
MOVQ R10, 16(AX)
MOVQ R12, 24(AX)
MOVQ R14, 32(AX)
RET

12
vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
// Copyright (c) 2019 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 !amd64 || !gc || purego
// +build !amd64 !gc purego
package field
func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
func feSquare(v, x *Element) { feSquareGeneric(v, x) }

16
vendor/filippo.io/edwards25519/field/fe_arm64.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
// Copyright (c) 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.
//go:build arm64 && gc && !purego
// +build arm64,gc,!purego
package field
//go:noescape
func carryPropagate(v *Element)
func (v *Element) carryPropagate() *Element {
carryPropagate(v)
return v
}

42
vendor/filippo.io/edwards25519/field/fe_arm64.s generated vendored Normal file
View File

@ -0,0 +1,42 @@
// Copyright (c) 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.
//go:build arm64 && gc && !purego
#include "textflag.h"
// carryPropagate works exactly like carryPropagateGeneric and uses the
// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but
// avoids loading R0-R4 twice and uses LDP and STP.
//
// See https://golang.org/issues/43145 for the main compiler issue.
//
// func carryPropagate(v *Element)
TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8
MOVD v+0(FP), R20
LDP 0(R20), (R0, R1)
LDP 16(R20), (R2, R3)
MOVD 32(R20), R4
AND $0x7ffffffffffff, R0, R10
AND $0x7ffffffffffff, R1, R11
AND $0x7ffffffffffff, R2, R12
AND $0x7ffffffffffff, R3, R13
AND $0x7ffffffffffff, R4, R14
ADD R0>>51, R11, R11
ADD R1>>51, R12, R12
ADD R2>>51, R13, R13
ADD R3>>51, R14, R14
// R4>>51 * 19 + R10 -> R10
LSR $51, R4, R21
MOVD $19, R22
MADD R22, R10, R21, R10
STP (R10, R11), 0(R20)
STP (R12, R13), 16(R20)
MOVD R14, 32(R20)
RET

12
vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
// Copyright (c) 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 !arm64 || !gc || purego
// +build !arm64 !gc purego
package field
func (v *Element) carryPropagate() *Element {
return v.carryPropagateGeneric()
}

50
vendor/filippo.io/edwards25519/field/fe_extra.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
// Copyright (c) 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.
package field
import "errors"
// This file contains additional functionality that is not included in the
// upstream crypto/ed25519/edwards25519/field package.
// SetWideBytes sets v to x, where x is a 64-byte little-endian encoding, which
// is reduced modulo the field order. If x is not of the right length,
// SetWideBytes returns nil and an error, and the receiver is unchanged.
//
// SetWideBytes is not necessary to select a uniformly distributed value, and is
// only provided for compatibility: SetBytes can be used instead as the chance
// of bias is less than 2⁻²⁵⁰.
func (v *Element) SetWideBytes(x []byte) (*Element, error) {
if len(x) != 64 {
return nil, errors.New("edwards25519: invalid SetWideBytes input size")
}
// Split the 64 bytes into two elements, and extract the most significant
// bit of each, which is ignored by SetBytes.
lo, _ := new(Element).SetBytes(x[:32])
loMSB := uint64(x[31] >> 7)
hi, _ := new(Element).SetBytes(x[32:])
hiMSB := uint64(x[63] >> 7)
// The output we want is
//
// v = lo + loMSB * 2²⁵⁵ + hi * 2²⁵⁶ + hiMSB * 2⁵¹¹
//
// which applying the reduction identity comes out to
//
// v = lo + loMSB * 19 + hi * 2 * 19 + hiMSB * 2 * 19²
//
// l0 will be the sum of a 52 bits value (lo.l0), plus a 5 bits value
// (loMSB * 19), a 6 bits value (hi.l0 * 2 * 19), and a 10 bits value
// (hiMSB * 2 * 19²), so it fits in a uint64.
v.l0 = lo.l0 + loMSB*19 + hi.l0*2*19 + hiMSB*2*19*19
v.l1 = lo.l1 + hi.l1*2*19
v.l2 = lo.l2 + hi.l2*2*19
v.l3 = lo.l3 + hi.l3*2*19
v.l4 = lo.l4 + hi.l4*2*19
return v.carryPropagate(), nil
}

266
vendor/filippo.io/edwards25519/field/fe_generic.go generated vendored Normal file
View File

@ -0,0 +1,266 @@
// Copyright (c) 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 field
import "math/bits"
// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
// bits.Mul64 and bits.Add64 intrinsics.
type uint128 struct {
lo, hi uint64
}
// mul64 returns a * b.
func mul64(a, b uint64) uint128 {
hi, lo := bits.Mul64(a, b)
return uint128{lo, hi}
}
// addMul64 returns v + a * b.
func addMul64(v uint128, a, b uint64) uint128 {
hi, lo := bits.Mul64(a, b)
lo, c := bits.Add64(lo, v.lo, 0)
hi, _ = bits.Add64(hi, v.hi, c)
return uint128{lo, hi}
}
// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits.
func shiftRightBy51(a uint128) uint64 {
return (a.hi << (64 - 51)) | (a.lo >> 51)
}
func feMulGeneric(v, a, b *Element) {
a0 := a.l0
a1 := a.l1
a2 := a.l2
a3 := a.l3
a4 := a.l4
b0 := b.l0
b1 := b.l1
b2 := b.l2
b3 := b.l3
b4 := b.l4
// Limb multiplication works like pen-and-paper columnar multiplication, but
// with 51-bit limbs instead of digits.
//
// a4 a3 a2 a1 a0 x
// b4 b3 b2 b1 b0 =
// ------------------------
// a4b0 a3b0 a2b0 a1b0 a0b0 +
// a4b1 a3b1 a2b1 a1b1 a0b1 +
// a4b2 a3b2 a2b2 a1b2 a0b2 +
// a4b3 a3b3 a2b3 a1b3 a0b3 +
// a4b4 a3b4 a2b4 a1b4 a0b4 =
// ----------------------------------------------
// r8 r7 r6 r5 r4 r3 r2 r1 r0
//
// We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to
// reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5,
// r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc.
//
// Reduction can be carried out simultaneously to multiplication. For
// example, we do not compute r5: whenever the result of a multiplication
// belongs to r5, like a1b4, we multiply it by 19 and add the result to r0.
//
// a4b0 a3b0 a2b0 a1b0 a0b0 +
// a3b1 a2b1 a1b1 a0b1 19×a4b1 +
// a2b2 a1b2 a0b2 19×a4b2 19×a3b2 +
// a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 +
// a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 =
// --------------------------------------
// r4 r3 r2 r1 r0
//
// Finally we add up the columns into wide, overlapping limbs.
a1_19 := a1 * 19
a2_19 := a2 * 19
a3_19 := a3 * 19
a4_19 := a4 * 19
// r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
r0 := mul64(a0, b0)
r0 = addMul64(r0, a1_19, b4)
r0 = addMul64(r0, a2_19, b3)
r0 = addMul64(r0, a3_19, b2)
r0 = addMul64(r0, a4_19, b1)
// r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
r1 := mul64(a0, b1)
r1 = addMul64(r1, a1, b0)
r1 = addMul64(r1, a2_19, b4)
r1 = addMul64(r1, a3_19, b3)
r1 = addMul64(r1, a4_19, b2)
// r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
r2 := mul64(a0, b2)
r2 = addMul64(r2, a1, b1)
r2 = addMul64(r2, a2, b0)
r2 = addMul64(r2, a3_19, b4)
r2 = addMul64(r2, a4_19, b3)
// r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
r3 := mul64(a0, b3)
r3 = addMul64(r3, a1, b2)
r3 = addMul64(r3, a2, b1)
r3 = addMul64(r3, a3, b0)
r3 = addMul64(r3, a4_19, b4)
// r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
r4 := mul64(a0, b4)
r4 = addMul64(r4, a1, b3)
r4 = addMul64(r4, a2, b2)
r4 = addMul64(r4, a3, b1)
r4 = addMul64(r4, a4, b0)
// After the multiplication, we need to reduce (carry) the five coefficients
// to obtain a result with limbs that are at most slightly larger than 2⁵¹,
// to respect the Element invariant.
//
// Overall, the reduction works the same as carryPropagate, except with
// wider inputs: we take the carry for each coefficient by shifting it right
// by 51, and add it to the limb above it. The top carry is multiplied by 19
// according to the reduction identity and added to the lowest limb.
//
// The largest coefficient (r0) will be at most 111 bits, which guarantees
// that all carries are at most 111 - 51 = 60 bits, which fits in a uint64.
//
// r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
// r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²)
// r0 < (1 + 19 × 4) × 2⁵² × 2⁵²
// r0 < 2⁷ × 2⁵² × 2⁵²
// r0 < 2¹¹¹
//
// Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most
// 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and
// allows us to easily apply the reduction identity.
//
// r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
// r4 < 5 × 2⁵² × 2⁵²
// r4 < 2¹⁰⁷
//
c0 := shiftRightBy51(r0)
c1 := shiftRightBy51(r1)
c2 := shiftRightBy51(r2)
c3 := shiftRightBy51(r3)
c4 := shiftRightBy51(r4)
rr0 := r0.lo&maskLow51Bits + c4*19
rr1 := r1.lo&maskLow51Bits + c0
rr2 := r2.lo&maskLow51Bits + c1
rr3 := r3.lo&maskLow51Bits + c2
rr4 := r4.lo&maskLow51Bits + c3
// Now all coefficients fit into 64-bit registers but are still too large to
// be passed around as an Element. We therefore do one last carry chain,
// where the carries will be small enough to fit in the wiggle room above 2⁵¹.
*v = Element{rr0, rr1, rr2, rr3, rr4}
v.carryPropagate()
}
func feSquareGeneric(v, a *Element) {
l0 := a.l0
l1 := a.l1
l2 := a.l2
l3 := a.l3
l4 := a.l4
// Squaring works precisely like multiplication above, but thanks to its
// symmetry we get to group a few terms together.
//
// l4 l3 l2 l1 l0 x
// l4 l3 l2 l1 l0 =
// ------------------------
// l4l0 l3l0 l2l0 l1l0 l0l0 +
// l4l1 l3l1 l2l1 l1l1 l0l1 +
// l4l2 l3l2 l2l2 l1l2 l0l2 +
// l4l3 l3l3 l2l3 l1l3 l0l3 +
// l4l4 l3l4 l2l4 l1l4 l0l4 =
// ----------------------------------------------
// r8 r7 r6 r5 r4 r3 r2 r1 r0
//
// l4l0 l3l0 l2l0 l1l0 l0l0 +
// l3l1 l2l1 l1l1 l0l1 19×l4l1 +
// l2l2 l1l2 l0l2 19×l4l2 19×l3l2 +
// l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 +
// l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 =
// --------------------------------------
// r4 r3 r2 r1 r0
//
// With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with
// only three Mul64 and four Add64, instead of five and eight.
l0_2 := l0 * 2
l1_2 := l1 * 2
l1_38 := l1 * 38
l2_38 := l2 * 38
l3_38 := l3 * 38
l3_19 := l3 * 19
l4_19 := l4 * 19
// r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3)
r0 := mul64(l0, l0)
r0 = addMul64(r0, l1_38, l4)
r0 = addMul64(r0, l2_38, l3)
// r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
r1 := mul64(l0_2, l1)
r1 = addMul64(r1, l2_38, l4)
r1 = addMul64(r1, l3_19, l3)
// r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4
r2 := mul64(l0_2, l2)
r2 = addMul64(r2, l1, l1)
r2 = addMul64(r2, l3_38, l4)
// r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
r3 := mul64(l0_2, l3)
r3 = addMul64(r3, l1_2, l2)
r3 = addMul64(r3, l4_19, l4)
// r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2
r4 := mul64(l0_2, l4)
r4 = addMul64(r4, l1_2, l3)
r4 = addMul64(r4, l2, l2)
c0 := shiftRightBy51(r0)
c1 := shiftRightBy51(r1)
c2 := shiftRightBy51(r2)
c3 := shiftRightBy51(r3)
c4 := shiftRightBy51(r4)
rr0 := r0.lo&maskLow51Bits + c4*19
rr1 := r1.lo&maskLow51Bits + c0
rr2 := r2.lo&maskLow51Bits + c1
rr3 := r3.lo&maskLow51Bits + c2
rr4 := r4.lo&maskLow51Bits + c3
*v = Element{rr0, rr1, rr2, rr3, rr4}
v.carryPropagate()
}
// carryPropagateGeneric brings the limbs below 52 bits by applying the reduction
// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry.
func (v *Element) carryPropagateGeneric() *Element {
c0 := v.l0 >> 51
c1 := v.l1 >> 51
c2 := v.l2 >> 51
c3 := v.l3 >> 51
c4 := v.l4 >> 51
// c4 is at most 64 - 51 = 13 bits, so c4*19 is at most 18 bits, and
// the final l0 will be at most 52 bits. Similarly for the rest.
v.l0 = v.l0&maskLow51Bits + c4*19
v.l1 = v.l1&maskLow51Bits + c0
v.l2 = v.l2&maskLow51Bits + c1
v.l3 = v.l3&maskLow51Bits + c2
v.l4 = v.l4&maskLow51Bits + c3
return v
}

343
vendor/filippo.io/edwards25519/scalar.go generated vendored Normal file
View File

@ -0,0 +1,343 @@
// Copyright (c) 2016 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 edwards25519
import (
"encoding/binary"
"errors"
)
// A Scalar is an integer modulo
//
// l = 2^252 + 27742317777372353535851937790883648493
//
// which is the prime order of the edwards25519 group.
//
// This type works similarly to math/big.Int, and all arguments and
// receivers are allowed to alias.
//
// The zero value is a valid zero element.
type Scalar struct {
// s is the scalar in the Montgomery domain, in the format of the
// fiat-crypto implementation.
s fiatScalarMontgomeryDomainFieldElement
}
// The field implementation in scalar_fiat.go is generated by the fiat-crypto
// project (https://github.com/mit-plv/fiat-crypto) at version v0.0.9 (23d2dbc)
// from a formally verified model.
//
// fiat-crypto code comes under the following license.
//
// Copyright (c) 2015-2020 The fiat-crypto 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:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "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 Berkeley Software Design,
// Inc. 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.
//
// NewScalar returns a new zero Scalar.
func NewScalar() *Scalar {
return &Scalar{}
}
// MultiplyAdd sets s = x * y + z mod l, and returns s. It is equivalent to
// using Multiply and then Add.
func (s *Scalar) MultiplyAdd(x, y, z *Scalar) *Scalar {
// Make a copy of z in case it aliases s.
zCopy := new(Scalar).Set(z)
return s.Multiply(x, y).Add(s, zCopy)
}
// Add sets s = x + y mod l, and returns s.
func (s *Scalar) Add(x, y *Scalar) *Scalar {
// s = 1 * x + y mod l
fiatScalarAdd(&s.s, &x.s, &y.s)
return s
}
// Subtract sets s = x - y mod l, and returns s.
func (s *Scalar) Subtract(x, y *Scalar) *Scalar {
// s = -1 * y + x mod l
fiatScalarSub(&s.s, &x.s, &y.s)
return s
}
// Negate sets s = -x mod l, and returns s.
func (s *Scalar) Negate(x *Scalar) *Scalar {
// s = -1 * x + 0 mod l
fiatScalarOpp(&s.s, &x.s)
return s
}
// Multiply sets s = x * y mod l, and returns s.
func (s *Scalar) Multiply(x, y *Scalar) *Scalar {
// s = x * y + 0 mod l
fiatScalarMul(&s.s, &x.s, &y.s)
return s
}
// Set sets s = x, and returns s.
func (s *Scalar) Set(x *Scalar) *Scalar {
*s = *x
return s
}
// SetUniformBytes sets s = x mod l, where x is a 64-byte little-endian integer.
// If x is not of the right length, SetUniformBytes returns nil and an error,
// and the receiver is unchanged.
//
// SetUniformBytes can be used to set s to a uniformly distributed value given
// 64 uniformly distributed random bytes.
func (s *Scalar) SetUniformBytes(x []byte) (*Scalar, error) {
if len(x) != 64 {
return nil, errors.New("edwards25519: invalid SetUniformBytes input length")
}
// We have a value x of 512 bits, but our fiatScalarFromBytes function
// expects an input lower than l, which is a little over 252 bits.
//
// Instead of writing a reduction function that operates on wider inputs, we
// can interpret x as the sum of three shorter values a, b, and c.
//
// x = a + b * 2^168 + c * 2^336 mod l
//
// We then precompute 2^168 and 2^336 modulo l, and perform the reduction
// with two multiplications and two additions.
s.setShortBytes(x[:21])
t := new(Scalar).setShortBytes(x[21:42])
s.Add(s, t.Multiply(t, scalarTwo168))
t.setShortBytes(x[42:])
s.Add(s, t.Multiply(t, scalarTwo336))
return s, nil
}
// scalarTwo168 and scalarTwo336 are 2^168 and 2^336 modulo l, encoded as a
// fiatScalarMontgomeryDomainFieldElement, which is a little-endian 4-limb value
// in the 2^256 Montgomery domain.
var scalarTwo168 = &Scalar{s: [4]uint64{0x5b8ab432eac74798, 0x38afddd6de59d5d7,
0xa2c131b399411b7c, 0x6329a7ed9ce5a30}}
var scalarTwo336 = &Scalar{s: [4]uint64{0xbd3d108e2b35ecc5, 0x5c3a3718bdf9c90b,
0x63aa97a331b4f2ee, 0x3d217f5be65cb5c}}
// setShortBytes sets s = x mod l, where x is a little-endian integer shorter
// than 32 bytes.
func (s *Scalar) setShortBytes(x []byte) *Scalar {
if len(x) >= 32 {
panic("edwards25519: internal error: setShortBytes called with a long string")
}
var buf [32]byte
copy(buf[:], x)
fiatScalarFromBytes((*[4]uint64)(&s.s), &buf)
fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s))
return s
}
// SetCanonicalBytes sets s = x, where x is a 32-byte little-endian encoding of
// s, and returns s. If x is not a canonical encoding of s, SetCanonicalBytes
// returns nil and an error, and the receiver is unchanged.
func (s *Scalar) SetCanonicalBytes(x []byte) (*Scalar, error) {
if len(x) != 32 {
return nil, errors.New("invalid scalar length")
}
if !isReduced(x) {
return nil, errors.New("invalid scalar encoding")
}
fiatScalarFromBytes((*[4]uint64)(&s.s), (*[32]byte)(x))
fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s))
return s, nil
}
// scalarMinusOneBytes is l - 1 in little endian.
var scalarMinusOneBytes = [32]byte{236, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}
// isReduced returns whether the given scalar in 32-byte little endian encoded
// form is reduced modulo l.
func isReduced(s []byte) bool {
if len(s) != 32 {
return false
}
for i := len(s) - 1; i >= 0; i-- {
switch {
case s[i] > scalarMinusOneBytes[i]:
return false
case s[i] < scalarMinusOneBytes[i]:
return true
}
}
return true
}
// SetBytesWithClamping applies the buffer pruning described in RFC 8032,
// Section 5.1.5 (also known as clamping) and sets s to the result. The input
// must be 32 bytes, and it is not modified. If x is not of the right length,
// SetBytesWithClamping returns nil and an error, and the receiver is unchanged.
//
// Note that since Scalar values are always reduced modulo the prime order of
// the curve, the resulting value will not preserve any of the cofactor-clearing
// properties that clamping is meant to provide. It will however work as
// expected as long as it is applied to points on the prime order subgroup, like
// in Ed25519. In fact, it is lost to history why RFC 8032 adopted the
// irrelevant RFC 7748 clamping, but it is now required for compatibility.
func (s *Scalar) SetBytesWithClamping(x []byte) (*Scalar, error) {
// The description above omits the purpose of the high bits of the clamping
// for brevity, but those are also lost to reductions, and are also
// irrelevant to edwards25519 as they protect against a specific
// implementation bug that was once observed in a generic Montgomery ladder.
if len(x) != 32 {
return nil, errors.New("edwards25519: invalid SetBytesWithClamping input length")
}
// We need to use the wide reduction from SetUniformBytes, since clamping
// sets the 2^254 bit, making the value higher than the order.
var wideBytes [64]byte
copy(wideBytes[:], x[:])
wideBytes[0] &= 248
wideBytes[31] &= 63
wideBytes[31] |= 64
return s.SetUniformBytes(wideBytes[:])
}
// Bytes returns the canonical 32-byte little-endian encoding of s.
func (s *Scalar) Bytes() []byte {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap.
var encoded [32]byte
return s.bytes(&encoded)
}
func (s *Scalar) bytes(out *[32]byte) []byte {
var ss fiatScalarNonMontgomeryDomainFieldElement
fiatScalarFromMontgomery(&ss, &s.s)
fiatScalarToBytes(out, (*[4]uint64)(&ss))
return out[:]
}
// Equal returns 1 if s and t are equal, and 0 otherwise.
func (s *Scalar) Equal(t *Scalar) int {
var diff fiatScalarMontgomeryDomainFieldElement
fiatScalarSub(&diff, &s.s, &t.s)
var nonzero uint64
fiatScalarNonzero(&nonzero, (*[4]uint64)(&diff))
nonzero |= nonzero >> 32
nonzero |= nonzero >> 16
nonzero |= nonzero >> 8
nonzero |= nonzero >> 4
nonzero |= nonzero >> 2
nonzero |= nonzero >> 1
return int(^nonzero) & 1
}
// nonAdjacentForm computes a width-w non-adjacent form for this scalar.
//
// w must be between 2 and 8, or nonAdjacentForm will panic.
func (s *Scalar) nonAdjacentForm(w uint) [256]int8 {
// This implementation is adapted from the one
// in curve25519-dalek and is documented there:
// https://github.com/dalek-cryptography/curve25519-dalek/blob/f630041af28e9a405255f98a8a93adca18e4315b/src/scalar.rs#L800-L871
b := s.Bytes()
if b[31] > 127 {
panic("scalar has high bit set illegally")
}
if w < 2 {
panic("w must be at least 2 by the definition of NAF")
} else if w > 8 {
panic("NAF digits must fit in int8")
}
var naf [256]int8
var digits [5]uint64
for i := 0; i < 4; i++ {
digits[i] = binary.LittleEndian.Uint64(b[i*8:])
}
width := uint64(1 << w)
windowMask := uint64(width - 1)
pos := uint(0)
carry := uint64(0)
for pos < 256 {
indexU64 := pos / 64
indexBit := pos % 64
var bitBuf uint64
if indexBit < 64-w {
// This window's bits are contained in a single u64
bitBuf = digits[indexU64] >> indexBit
} else {
// Combine the current 64 bits with bits from the next 64
bitBuf = (digits[indexU64] >> indexBit) | (digits[1+indexU64] << (64 - indexBit))
}
// Add carry into the current window
window := carry + (bitBuf & windowMask)
if window&1 == 0 {
// If the window value is even, preserve the carry and continue.
// Why is the carry preserved?
// If carry == 0 and window & 1 == 0,
// then the next carry should be 0
// If carry == 1 and window & 1 == 0,
// then bit_buf & 1 == 1 so the next carry should be 1
pos += 1
continue
}
if window < width/2 {
carry = 0
naf[pos] = int8(window)
} else {
carry = 1
naf[pos] = int8(window) - int8(width)
}
pos += w
}
return naf
}
func (s *Scalar) signedRadix16() [64]int8 {
b := s.Bytes()
if b[31] > 127 {
panic("scalar has high bit set illegally")
}
var digits [64]int8
// Compute unsigned radix-16 digits:
for i := 0; i < 32; i++ {
digits[2*i] = int8(b[i] & 15)
digits[2*i+1] = int8((b[i] >> 4) & 15)
}
// Recenter coefficients:
for i := 0; i < 63; i++ {
carry := (digits[i] + 8) >> 4
digits[i] -= carry << 4
digits[i+1] += carry
}
return digits
}

1147
vendor/filippo.io/edwards25519/scalar_fiat.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

214
vendor/filippo.io/edwards25519/scalarmult.go generated vendored Normal file
View File

@ -0,0 +1,214 @@
// Copyright (c) 2019 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 edwards25519
import "sync"
// basepointTable is a set of 32 affineLookupTables, where table i is generated
// from 256i * basepoint. It is precomputed the first time it's used.
func basepointTable() *[32]affineLookupTable {
basepointTablePrecomp.initOnce.Do(func() {
p := NewGeneratorPoint()
for i := 0; i < 32; i++ {
basepointTablePrecomp.table[i].FromP3(p)
for j := 0; j < 8; j++ {
p.Add(p, p)
}
}
})
return &basepointTablePrecomp.table
}
var basepointTablePrecomp struct {
table [32]affineLookupTable
initOnce sync.Once
}
// ScalarBaseMult sets v = x * B, where B is the canonical generator, and
// returns v.
//
// The scalar multiplication is done in constant time.
func (v *Point) ScalarBaseMult(x *Scalar) *Point {
basepointTable := basepointTable()
// Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i )
// as described in the Ed25519 paper
//
// Group even and odd coefficients
// x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
// + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B
// x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
// + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B)
//
// We use a lookup table for each i to get x_i*16^(2*i)*B
// and do four doublings to multiply by 16.
digits := x.signedRadix16()
multiple := &affineCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
// Accumulate the odd components first
v.Set(NewIdentityPoint())
for i := 1; i < 64; i += 2 {
basepointTable[i/2].SelectInto(multiple, digits[i])
tmp1.AddAffine(v, multiple)
v.fromP1xP1(tmp1)
}
// Multiply by 16
tmp2.FromP3(v) // tmp2 = v in P2 coords
tmp1.Double(tmp2) // tmp1 = 2*v in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 2*v in P2 coords
tmp1.Double(tmp2) // tmp1 = 4*v in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 4*v in P2 coords
tmp1.Double(tmp2) // tmp1 = 8*v in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 8*v in P2 coords
tmp1.Double(tmp2) // tmp1 = 16*v in P1xP1 coords
v.fromP1xP1(tmp1) // now v = 16*(odd components)
// Accumulate the even components
for i := 0; i < 64; i += 2 {
basepointTable[i/2].SelectInto(multiple, digits[i])
tmp1.AddAffine(v, multiple)
v.fromP1xP1(tmp1)
}
return v
}
// ScalarMult sets v = x * q, and returns v.
//
// The scalar multiplication is done in constant time.
func (v *Point) ScalarMult(x *Scalar, q *Point) *Point {
checkInitialized(q)
var table projLookupTable
table.FromP3(q)
// Write x = sum(x_i * 16^i)
// so x*Q = sum( Q*x_i*16^i )
// = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... )
// <------compute inside out---------
//
// We use the lookup table to get the x_i*Q values
// and do four doublings to compute 16*Q
digits := x.signedRadix16()
// Unwrap first loop iteration to save computing 16*identity
multiple := &projCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
table.SelectInto(multiple, digits[63])
v.Set(NewIdentityPoint())
tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords
for i := 62; i >= 0; i-- {
tmp2.FromP1xP1(tmp1) // tmp2 = (prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords
table.SelectInto(multiple, digits[i])
tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords
}
v.fromP1xP1(tmp1)
return v
}
// basepointNafTable is the nafLookupTable8 for the basepoint.
// It is precomputed the first time it's used.
func basepointNafTable() *nafLookupTable8 {
basepointNafTablePrecomp.initOnce.Do(func() {
basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint())
})
return &basepointNafTablePrecomp.table
}
var basepointNafTablePrecomp struct {
table nafLookupTable8
initOnce sync.Once
}
// VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical
// generator, and returns v.
//
// Execution time depends on the inputs.
func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point {
checkInitialized(A)
// Similarly to the single variable-base approach, we compute
// digits and use them with a lookup table. However, because
// we are allowed to do variable-time operations, we don't
// need constant-time lookups or constant-time digit
// computations.
//
// So we use a non-adjacent form of some width w instead of
// radix 16. This is like a binary representation (one digit
// for each binary place) but we allow the digits to grow in
// magnitude up to 2^{w-1} so that the nonzero digits are as
// sparse as possible. Intuitively, this "condenses" the
// "mass" of the scalar onto sparse coefficients (meaning
// fewer additions).
basepointNafTable := basepointNafTable()
var aTable nafLookupTable5
aTable.FromP3(A)
// Because the basepoint is fixed, we can use a wider NAF
// corresponding to a bigger table.
aNaf := a.nonAdjacentForm(5)
bNaf := b.nonAdjacentForm(8)
// Find the first nonzero coefficient.
i := 255
for j := i; j >= 0; j-- {
if aNaf[j] != 0 || bNaf[j] != 0 {
break
}
}
multA := &projCached{}
multB := &affineCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
tmp2.Zero()
// Move from high to low bits, doubling the accumulator
// at each iteration and checking whether there is a nonzero
// coefficient to look up a multiple of.
for ; i >= 0; i-- {
tmp1.Double(tmp2)
// Only update v if we have a nonzero coeff to add in.
if aNaf[i] > 0 {
v.fromP1xP1(tmp1)
aTable.SelectInto(multA, aNaf[i])
tmp1.Add(v, multA)
} else if aNaf[i] < 0 {
v.fromP1xP1(tmp1)
aTable.SelectInto(multA, -aNaf[i])
tmp1.Sub(v, multA)
}
if bNaf[i] > 0 {
v.fromP1xP1(tmp1)
basepointNafTable.SelectInto(multB, bNaf[i])
tmp1.AddAffine(v, multB)
} else if bNaf[i] < 0 {
v.fromP1xP1(tmp1)
basepointNafTable.SelectInto(multB, -bNaf[i])
tmp1.SubAffine(v, multB)
}
tmp2.FromP1xP1(tmp1)
}
v.fromP2(tmp2)
return v
}

129
vendor/filippo.io/edwards25519/tables.go generated vendored Normal file
View File

@ -0,0 +1,129 @@
// Copyright (c) 2019 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 edwards25519
import (
"crypto/subtle"
)
// A dynamic lookup table for variable-base, constant-time scalar muls.
type projLookupTable struct {
points [8]projCached
}
// A precomputed lookup table for fixed-base, constant-time scalar muls.
type affineLookupTable struct {
points [8]affineCached
}
// A dynamic lookup table for variable-base, variable-time scalar muls.
type nafLookupTable5 struct {
points [8]projCached
}
// A precomputed lookup table for fixed-base, variable-time scalar muls.
type nafLookupTable8 struct {
points [64]affineCached
}
// Constructors.
// Builds a lookup table at runtime. Fast.
func (v *projLookupTable) FromP3(q *Point) {
// Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
// This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
v.points[0].FromP3(q)
tmpP3 := Point{}
tmpP1xP1 := projP1xP1{}
for i := 0; i < 7; i++ {
// Compute (i+1)*Q as Q + i*Q and convert to a projCached
// This is needlessly complicated because the API has explicit
// receivers instead of creating stack objects and relying on RVO
v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
}
}
// This is not optimised for speed; fixed-base tables should be precomputed.
func (v *affineLookupTable) FromP3(q *Point) {
// Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
// This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
v.points[0].FromP3(q)
tmpP3 := Point{}
tmpP1xP1 := projP1xP1{}
for i := 0; i < 7; i++ {
// Compute (i+1)*Q as Q + i*Q and convert to affineCached
v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i])))
}
}
// Builds a lookup table at runtime. Fast.
func (v *nafLookupTable5) FromP3(q *Point) {
// Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q
// This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q
v.points[0].FromP3(q)
q2 := Point{}
q2.Add(q, q)
tmpP3 := Point{}
tmpP1xP1 := projP1xP1{}
for i := 0; i < 7; i++ {
v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i])))
}
}
// This is not optimised for speed; fixed-base tables should be precomputed.
func (v *nafLookupTable8) FromP3(q *Point) {
v.points[0].FromP3(q)
q2 := Point{}
q2.Add(q, q)
tmpP3 := Point{}
tmpP1xP1 := projP1xP1{}
for i := 0; i < 63; i++ {
v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i])))
}
}
// Selectors.
// Set dest to x*Q, where -8 <= x <= 8, in constant time.
func (v *projLookupTable) SelectInto(dest *projCached, x int8) {
// Compute xabs = |x|
xmask := x >> 7
xabs := uint8((x + xmask) ^ xmask)
dest.Zero()
for j := 1; j <= 8; j++ {
// Set dest = j*Q if |x| = j
cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
dest.Select(&v.points[j-1], dest, cond)
}
// Now dest = |x|*Q, conditionally negate to get x*Q
dest.CondNeg(int(xmask & 1))
}
// Set dest to x*Q, where -8 <= x <= 8, in constant time.
func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) {
// Compute xabs = |x|
xmask := x >> 7
xabs := uint8((x + xmask) ^ xmask)
dest.Zero()
for j := 1; j <= 8; j++ {
// Set dest = j*Q if |x| = j
cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
dest.Select(&v.points[j-1], dest, cond)
}
// Now dest = |x|*Q, conditionally negate to get x*Q
dest.CondNeg(int(xmask & 1))
}
// Given odd x with 0 < x < 2^4, return x*Q (in variable time).
func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) {
*dest = v.points[x/2]
}
// Given odd x with 0 < x < 2^7, return x*Q (in variable time).
func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) {
*dest = v.points[x/2]
}

View File

@ -13,29 +13,41 @@
Aaron Hopkins <go-sql-driver at die.net> Aaron Hopkins <go-sql-driver at die.net>
Achille Roussel <achille.roussel at gmail.com> Achille Roussel <achille.roussel at gmail.com>
Aidan <aidan.liu at pingcap.com>
Alex Snast <alexsn at fb.com> Alex Snast <alexsn at fb.com>
Alexey Palazhchenko <alexey.palazhchenko at gmail.com> Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
Andrew Reid <andrew.reid at tixtrack.com> Andrew Reid <andrew.reid at tixtrack.com>
Animesh Ray <mail.rayanimesh at gmail.com> Animesh Ray <mail.rayanimesh at gmail.com>
Arne Hormann <arnehormann at gmail.com> Arne Hormann <arnehormann at gmail.com>
Ariel Mashraki <ariel at mashraki.co.il> Ariel Mashraki <ariel at mashraki.co.il>
Artur Melanchyk <artur.melanchyk@gmail.com>
Asta Xie <xiemengjun at gmail.com> Asta Xie <xiemengjun at gmail.com>
B Lamarche <blam413 at gmail.com>
Bes Dollma <bdollma@thousandeyes.com>
Bogdan Constantinescu <bog.con.bc at gmail.com>
Brad Higgins <brad at defined.net>
Brian Hendriks <brian at dolthub.com>
Bulat Gaifullin <gaifullinbf at gmail.com> Bulat Gaifullin <gaifullinbf at gmail.com>
Caine Jette <jette at alum.mit.edu> Caine Jette <jette at alum.mit.edu>
Carlos Nieto <jose.carlos at menteslibres.net> Carlos Nieto <jose.carlos at menteslibres.net>
Chris Kirkland <chriskirkland at github.com> Chris Kirkland <chriskirkland at github.com>
Chris Moos <chris at tech9computers.com> Chris Moos <chris at tech9computers.com>
Craig Wilson <craiggwilson at gmail.com> Craig Wilson <craiggwilson at gmail.com>
Daemonxiao <735462752 at qq.com>
Daniel Montoya <dsmontoyam at gmail.com> Daniel Montoya <dsmontoyam at gmail.com>
Daniel Nichter <nil at codenode.com> Daniel Nichter <nil at codenode.com>
Daniël van Eeden <git at myname.nl> Daniël van Eeden <git at myname.nl>
Dave Protasowski <dprotaso at gmail.com> Dave Protasowski <dprotaso at gmail.com>
Diego Dupin <diego.dupin at gmail.com>
Dirkjan Bussink <d.bussink at gmail.com>
DisposaBoy <disposaboy at dby.me> DisposaBoy <disposaboy at dby.me>
Egor Smolyakov <egorsmkv at gmail.com> Egor Smolyakov <egorsmkv at gmail.com>
Erwan Martin <hello at erwan.io> Erwan Martin <hello at erwan.io>
Evan Elias <evan at skeema.net>
Evan Shaw <evan at vendhq.com> Evan Shaw <evan at vendhq.com>
Frederick Mayle <frederickmayle at gmail.com> Frederick Mayle <frederickmayle at gmail.com>
Gustavo Kristic <gkristic at gmail.com> Gustavo Kristic <gkristic at gmail.com>
Gusted <postmaster at gusted.xyz>
Hajime Nakagami <nakagami at gmail.com> Hajime Nakagami <nakagami at gmail.com>
Hanno Braun <mail at hannobraun.com> Hanno Braun <mail at hannobraun.com>
Henri Yandell <flamefew at gmail.com> Henri Yandell <flamefew at gmail.com>
@ -45,13 +57,18 @@ ICHINOSE Shogo <shogo82148 at gmail.com>
Ilia Cimpoes <ichimpoesh at gmail.com> Ilia Cimpoes <ichimpoesh at gmail.com>
INADA Naoki <songofacandy at gmail.com> INADA Naoki <songofacandy at gmail.com>
Jacek Szwec <szwec.jacek at gmail.com> Jacek Szwec <szwec.jacek at gmail.com>
Jakub Adamus <kratky at zobak.cz>
James Harr <james.harr at gmail.com> James Harr <james.harr at gmail.com>
Janek Vedock <janekvedock at comcast.net> Janek Vedock <janekvedock at comcast.net>
Jason Ng <oblitorum at gmail.com>
Jean-Yves Pellé <jy at pelle.link>
Jeff Hodges <jeff at somethingsimilar.com> Jeff Hodges <jeff at somethingsimilar.com>
Jeffrey Charles <jeffreycharles at gmail.com> Jeffrey Charles <jeffreycharles at gmail.com>
Jennifer Purevsuren <jennifer at dolthub.com>
Jerome Meyer <jxmeyer at gmail.com> Jerome Meyer <jxmeyer at gmail.com>
Jiajia Zhong <zhong2plus at gmail.com> Jiajia Zhong <zhong2plus at gmail.com>
Jian Zhen <zhenjl at gmail.com> Jian Zhen <zhenjl at gmail.com>
Joe Mann <contact at joemann.co.uk>
Joshua Prunier <joshua.prunier at gmail.com> Joshua Prunier <joshua.prunier at gmail.com>
Julien Lefevre <julien.lefevr at gmail.com> Julien Lefevre <julien.lefevr at gmail.com>
Julien Schmidt <go-sql-driver at julienschmidt.com> Julien Schmidt <go-sql-driver at julienschmidt.com>
@ -72,17 +89,23 @@ Lunny Xiao <xiaolunwen at gmail.com>
Luke Scott <luke at webconnex.com> Luke Scott <luke at webconnex.com>
Maciej Zimnoch <maciej.zimnoch at codilime.com> Maciej Zimnoch <maciej.zimnoch at codilime.com>
Michael Woolnough <michael.woolnough at gmail.com> Michael Woolnough <michael.woolnough at gmail.com>
Nao Yokotsuka <yokotukanao at gmail.com>
Nathanial Murphy <nathanial.murphy at gmail.com> Nathanial Murphy <nathanial.murphy at gmail.com>
Nicola Peduzzi <thenikso at gmail.com> Nicola Peduzzi <thenikso at gmail.com>
Oliver Bone <owbone at github.com>
Olivier Mengué <dolmen at cpan.org> Olivier Mengué <dolmen at cpan.org>
oscarzhao <oscarzhaosl at gmail.com> oscarzhao <oscarzhaosl at gmail.com>
Paul Bonser <misterpib at gmail.com> Paul Bonser <misterpib at gmail.com>
Paulius Lozys <pauliuslozys at gmail.com>
Peter Schultz <peter.schultz at classmarkets.com> Peter Schultz <peter.schultz at classmarkets.com>
Phil Porada <philporada at gmail.com>
Minh Quang <minhquang4334 at gmail.com>
Rebecca Chin <rchin at pivotal.io> Rebecca Chin <rchin at pivotal.io>
Reed Allman <rdallman10 at gmail.com> Reed Allman <rdallman10 at gmail.com>
Richard Wilkes <wilkes at me.com> Richard Wilkes <wilkes at me.com>
Robert Russell <robert at rrbrussell.com> Robert Russell <robert at rrbrussell.com>
Runrioter Wung <runrioter at gmail.com> Runrioter Wung <runrioter at gmail.com>
Samantha Frank <hello at entropy.cat>
Santhosh Kumar Tekuri <santhosh.tekuri at gmail.com> Santhosh Kumar Tekuri <santhosh.tekuri at gmail.com>
Sho Iizuka <sho.i518 at gmail.com> Sho Iizuka <sho.i518 at gmail.com>
Sho Ikeda <suicaicoca at gmail.com> Sho Ikeda <suicaicoca at gmail.com>
@ -93,6 +116,7 @@ Stan Putrya <root.vagner at gmail.com>
Stanley Gunawan <gunawan.stanley at gmail.com> Stanley Gunawan <gunawan.stanley at gmail.com>
Steven Hartland <steven.hartland at multiplay.co.uk> Steven Hartland <steven.hartland at multiplay.co.uk>
Tan Jinhua <312841925 at qq.com> Tan Jinhua <312841925 at qq.com>
Tetsuro Aoki <t.aoki1130 at gmail.com>
Thomas Wodarek <wodarekwebpage at gmail.com> Thomas Wodarek <wodarekwebpage at gmail.com>
Tim Ruffles <timruffles at gmail.com> Tim Ruffles <timruffles at gmail.com>
Tom Jenkinson <tom at tjenkinson.me> Tom Jenkinson <tom at tjenkinson.me>
@ -102,6 +126,7 @@ Xiangyu Hu <xiangyu.hu at outlook.com>
Xiaobing Jiang <s7v7nislands at gmail.com> Xiaobing Jiang <s7v7nislands at gmail.com>
Xiuming Chen <cc at cxm.cc> Xiuming Chen <cc at cxm.cc>
Xuehong Chan <chanxuehong at gmail.com> Xuehong Chan <chanxuehong at gmail.com>
Zhang Xiang <angwerzx at 126.com>
Zhenye Xie <xiezhenye at gmail.com> Zhenye Xie <xiezhenye at gmail.com>
Zhixin Wen <john.wenzhixin at gmail.com> Zhixin Wen <john.wenzhixin at gmail.com>
Ziheng Lyu <zihenglv at gmail.com> Ziheng Lyu <zihenglv at gmail.com>
@ -110,15 +135,21 @@ Ziheng Lyu <zihenglv at gmail.com>
Barracuda Networks, Inc. Barracuda Networks, Inc.
Counting Ltd. Counting Ltd.
Defined Networking Inc.
DigitalOcean Inc. DigitalOcean Inc.
Dolthub Inc.
dyves labs AG dyves labs AG
Facebook Inc. Facebook Inc.
GitHub Inc. GitHub Inc.
Google Inc. Google Inc.
InfoSum Ltd. InfoSum Ltd.
Keybase Inc. Keybase Inc.
Microsoft Corp.
Multiplay Ltd. Multiplay Ltd.
Percona LLC Percona LLC
PingCAP Inc.
Pivotal Inc. Pivotal Inc.
Shattered Silicon Ltd.
Stripe Inc. Stripe Inc.
ThousandEyes
Zendesk Inc. Zendesk Inc.

View File

@ -1,3 +1,110 @@
# Changelog
## v1.9.3 (2025-06-13)
* `tx.Commit()` and `tx.Rollback()` returned `ErrInvalidConn` always.
Now they return cached real error if present. (#1690)
* Optimize reading small resultsets to fix performance regression
introduced by compression protocol support. (#1707)
* Fix `db.Ping()` on compressed connection. (#1723)
## v1.9.2 (2025-04-07)
v1.9.2 is a re-release of v1.9.1 due to a release process issue; no changes were made to the content.
## v1.9.1 (2025-03-21)
### Major Changes
* Add Charset() option. (#1679)
### Bugfixes
* go.mod: fix go version format (#1682)
* Fix FormatDSN missing ConnectionAttributes (#1619)
## v1.9.0 (2025-02-18)
### Major Changes
- Implement zlib compression. (#1487)
- Supported Go version is updated to Go 1.21+. (#1639)
- Add support for VECTOR type introduced in MySQL 9.0. (#1609)
- Config object can have custom dial function. (#1527)
### Bugfixes
- Fix auth errors when username/password are too long. (#1625)
- Check if MySQL supports CLIENT_CONNECT_ATTRS before sending client attributes. (#1640)
- Fix auth switch request handling. (#1666)
### Other changes
- Add "filename:line" prefix to log in go-mysql. Custom loggers now show it. (#1589)
- Improve error handling. It reduces the "busy buffer" errors. (#1595, #1601, #1641)
- Use `strconv.Atoi` to parse max_allowed_packet. (#1661)
- `rejectReadOnly` option now handles ER_READ_ONLY_MODE (1290) error too. (#1660)
## Version 1.8.1 (2024-03-26)
Bugfixes:
- fix race condition when context is canceled in [#1562](https://github.com/go-sql-driver/mysql/pull/1562) and [#1570](https://github.com/go-sql-driver/mysql/pull/1570)
## Version 1.8.0 (2024-03-09)
Major Changes:
- Use `SET NAMES charset COLLATE collation`. by @methane in [#1437](https://github.com/go-sql-driver/mysql/pull/1437)
- Older go-mysql-driver used `collation_id` in the handshake packet. But it caused collation mismatch in some situation.
- If you don't specify charset nor collation, go-mysql-driver sends `SET NAMES utf8mb4` for new connection. This uses server's default collation for utf8mb4.
- If you specify charset, go-mysql-driver sends `SET NAMES <charset>`. This uses the server's default collation for `<charset>`.
- If you specify collation and/or charset, go-mysql-driver sends `SET NAMES charset COLLATE collation`.
- PathEscape dbname in DSN. by @methane in [#1432](https://github.com/go-sql-driver/mysql/pull/1432)
- This is backward incompatible in rare case. Check your DSN.
- Drop Go 1.13-17 support by @methane in [#1420](https://github.com/go-sql-driver/mysql/pull/1420)
- Use Go 1.18+
- Parse numbers on text protocol too by @methane in [#1452](https://github.com/go-sql-driver/mysql/pull/1452)
- When text protocol is used, go-mysql-driver passed bare `[]byte` to database/sql for avoid unnecessary allocation and conversion.
- If user specified `*any` to `Scan()`, database/sql passed the `[]byte` into the target variable.
- This confused users because most user doesn't know when text/binary protocol used.
- go-mysql-driver 1.8 converts integer/float values into int64/double even in text protocol. This doesn't increase allocation compared to `[]byte` and conversion cost is negatable.
- New options start using the Functional Option Pattern to avoid increasing technical debt in the Config object. Future version may introduce Functional Option for existing options, but not for now.
- Make TimeTruncate functional option by @methane in [1552](https://github.com/go-sql-driver/mysql/pull/1552)
- Add BeforeConnect callback to configuration object by @ItalyPaleAle in [#1469](https://github.com/go-sql-driver/mysql/pull/1469)
Other changes:
- Adding DeregisterDialContext to prevent memory leaks with dialers we don't need anymore by @jypelle in https://github.com/go-sql-driver/mysql/pull/1422
- Make logger configurable per connection by @frozenbonito in https://github.com/go-sql-driver/mysql/pull/1408
- Fix ColumnType.DatabaseTypeName for mediumint unsigned by @evanelias in https://github.com/go-sql-driver/mysql/pull/1428
- Add connection attributes by @Daemonxiao in https://github.com/go-sql-driver/mysql/pull/1389
- Stop `ColumnTypeScanType()` from returning `sql.RawBytes` by @methane in https://github.com/go-sql-driver/mysql/pull/1424
- Exec() now provides access to status of multiple statements. by @mherr-google in https://github.com/go-sql-driver/mysql/pull/1309
- Allow to change (or disable) the default driver name for registration by @dolmen in https://github.com/go-sql-driver/mysql/pull/1499
- Add default connection attribute '_server_host' by @oblitorum in https://github.com/go-sql-driver/mysql/pull/1506
- QueryUnescape DSN ConnectionAttribute value by @zhangyangyu in https://github.com/go-sql-driver/mysql/pull/1470
- Add client_ed25519 authentication by @Gusted in https://github.com/go-sql-driver/mysql/pull/1518
## Version 1.7.1 (2023-04-25)
Changes:
- bump actions/checkout@v3 and actions/setup-go@v3 (#1375)
- Add go1.20 and mariadb10.11 to the testing matrix (#1403)
- Increase default maxAllowedPacket size. (#1411)
Bugfixes:
- Use SET syntax as specified in the MySQL documentation (#1402)
## Version 1.7 (2022-11-29) ## Version 1.7 (2022-11-29)
Changes: Changes:
@ -149,7 +256,7 @@ New Features:
- Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249) - Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249)
- Support for returning table alias on Columns() (#289, #359, #382) - Support for returning table alias on Columns() (#289, #359, #382)
- Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318, #490) - Placeholder interpolation, can be activated with the DSN parameter `interpolateParams=true` (#309, #318, #490)
- Support for uint64 parameters with high bit set (#332, #345) - Support for uint64 parameters with high bit set (#332, #345)
- Cleartext authentication plugin support (#327) - Cleartext authentication plugin support (#327)
- Exported ParseDSN function and the Config struct (#403, #419, #429) - Exported ParseDSN function and the Config struct (#403, #419, #429)
@ -193,7 +300,7 @@ Changes:
- Also exported the MySQLWarning type - Also exported the MySQLWarning type
- mysqlConn.Close returns the first error encountered instead of ignoring all errors - mysqlConn.Close returns the first error encountered instead of ignoring all errors
- writePacket() automatically writes the packet size to the header - writePacket() automatically writes the packet size to the header
- readPacket() uses an iterative approach instead of the recursive approach to merge splitted packets - readPacket() uses an iterative approach instead of the recursive approach to merge split packets
New Features: New Features:
@ -241,7 +348,7 @@ Bugfixes:
- Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification - Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification
- Convert to DB timezone when inserting `time.Time` - Convert to DB timezone when inserting `time.Time`
- Splitted packets (more than 16MB) are now merged correctly - Split packets (more than 16MB) are now merged correctly
- Fixed false positive `io.EOF` errors when the data was fully read - Fixed false positive `io.EOF` errors when the data was fully read
- Avoid panics on reuse of closed connections - Avoid panics on reuse of closed connections
- Fixed empty string producing false nil values - Fixed empty string producing false nil values

View File

@ -38,17 +38,26 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac
* Secure `LOAD DATA LOCAL INFILE` support with file allowlisting and `io.Reader` support * Secure `LOAD DATA LOCAL INFILE` support with file allowlisting and `io.Reader` support
* Optional `time.Time` parsing * Optional `time.Time` parsing
* Optional placeholder interpolation * Optional placeholder interpolation
* Supports zlib compression.
## Requirements ## Requirements
* Go 1.13 or higher. We aim to support the 3 latest versions of Go.
* MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+) * Go 1.21 or higher. We aim to support the 3 latest versions of Go.
* MySQL (5.7+) and MariaDB (10.5+) are supported.
* [TiDB](https://github.com/pingcap/tidb) is supported by PingCAP.
* Do not ask questions about TiDB in our issue tracker or forum.
* [Document](https://docs.pingcap.com/tidb/v6.1/dev-guide-sample-application-golang)
* [Forum](https://ask.pingcap.com/)
* go-mysql would work with Percona Server, Google CloudSQL or Sphinx (2.2.3+).
* Maintainers won't support them. Do not expect issues are investigated and resolved by maintainers.
* Investigate issues yourself and please send a pull request to fix it.
--------------------------------------- ---------------------------------------
## Installation ## Installation
Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell: Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell:
```bash ```bash
$ go get -u github.com/go-sql-driver/mysql go get -u github.com/go-sql-driver/mysql
``` ```
Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`. Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`.
@ -114,6 +123,12 @@ This has the same effect as an empty DSN string:
``` ```
`dbname` is escaped by [PathEscape()](https://pkg.go.dev/net/url#PathEscape) since v1.8.0. If your database name is `dbname/withslash`, it becomes:
```
/dbname%2Fwithslash
```
Alternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mysql#Config.FormatDSN) can be used to create a DSN string by filling a struct. Alternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mysql#Config.FormatDSN) can be used to create a DSN string by filling a struct.
#### Password #### Password
@ -121,7 +136,7 @@ Passwords can consist of any character. Escaping is **not** necessary.
#### Protocol #### Protocol
See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available. See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available.
In general you should use an Unix domain socket if available and TCP otherwise for best performance. In general you should use a Unix domain socket if available and TCP otherwise for best performance.
#### Address #### Address
For TCP and UDP networks, addresses have the form `host[:port]`. For TCP and UDP networks, addresses have the form `host[:port]`.
@ -145,7 +160,7 @@ Default: false
``` ```
`allowAllFiles=true` disables the file allowlist for `LOAD DATA LOCAL INFILE` and allows *all* files. `allowAllFiles=true` disables the file allowlist for `LOAD DATA LOCAL INFILE` and allows *all* files.
[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html) [*Might be insecure!*](https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-local)
##### `allowCleartextPasswords` ##### `allowCleartextPasswords`
@ -194,10 +209,9 @@ Valid Values: <name>
Default: none Default: none
``` ```
Sets the charset used for client-server interaction (`"SET NAMES <value>"`). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset failes. This enables for example support for `utf8mb4` ([introduced in MySQL 5.5.3](http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)) with fallback to `utf8` for older servers (`charset=utf8mb4,utf8`). Sets the charset used for client-server interaction (`"SET NAMES <value>"`). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset fails. This enables for example support for `utf8mb4` ([introduced in MySQL 5.5.3](http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)) with fallback to `utf8` for older servers (`charset=utf8mb4,utf8`).
Usage of the `charset` parameter is discouraged because it issues additional queries to the server. See also [Unicode Support](#unicode-support).
Unless you need the fallback behavior, please use `collation` instead.
##### `checkConnLiveness` ##### `checkConnLiveness`
@ -226,6 +240,7 @@ The default collation (`utf8mb4_general_ci`) is supported from MySQL 5.5. You s
Collations for charset "ucs2", "utf16", "utf16le", and "utf32" can not be used ([ref](https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset)). Collations for charset "ucs2", "utf16", "utf16le", and "utf32" can not be used ([ref](https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset)).
See also [Unicode Support](#unicode-support).
##### `clientFoundRows` ##### `clientFoundRows`
@ -253,6 +268,16 @@ SELECT u.id FROM users as u
will return `u.id` instead of just `id` if `columnsWithAlias=true`. will return `u.id` instead of just `id` if `columnsWithAlias=true`.
##### `compress`
```
Type: bool
Valid Values: true, false
Default: false
```
Toggles zlib compression. false by default.
##### `interpolateParams` ##### `interpolateParams`
``` ```
@ -279,13 +304,22 @@ Note that this sets the location for time.Time values but does not change MySQL'
Please keep in mind, that param values must be [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`. Please keep in mind, that param values must be [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`.
##### `timeTruncate`
```
Type: duration
Default: 0
```
[Truncate time values](https://pkg.go.dev/time#Duration.Truncate) to the specified duration. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
##### `maxAllowedPacket` ##### `maxAllowedPacket`
``` ```
Type: decimal number Type: decimal number
Default: 4194304 Default: 64*1024*1024
``` ```
Max packet size allowed in bytes. The default value is 4 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*. Max packet size allowed in bytes. The default value is 64 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*.
##### `multiStatements` ##### `multiStatements`
@ -295,9 +329,25 @@ Valid Values: true, false
Default: false Default: false
``` ```
Allow multiple statements in one query. While this allows batch queries, it also greatly increases the risk of SQL injections. Only the result of the first query is returned, all other results are silently discarded. Allow multiple statements in one query. This can be used to bach multiple queries. Use [Rows.NextResultSet()](https://pkg.go.dev/database/sql#Rows.NextResultSet) to get result of the second and subsequent queries.
When `multiStatements` is used, `?` parameters must only be used in the first statement. When `multiStatements` is used, `?` parameters must only be used in the first statement. [interpolateParams](#interpolateparams) can be used to avoid this limitation unless prepared statement is used explicitly.
It's possible to access the last inserted ID and number of affected rows for multiple statements by using `sql.Conn.Raw()` and the `mysql.Result`. For example:
```go
conn, _ := db.Conn(ctx)
conn.Raw(func(conn any) error {
ex := conn.(driver.Execer)
res, err := ex.Exec(`
UPDATE point SET x = 1 WHERE y = 2;
UPDATE point SET x = 2 WHERE y = 3;
`, nil)
// Both slices have 2 elements.
log.Print(res.(mysql.Result).AllRowsAffected())
log.Print(res.(mysql.Result).AllLastInsertIds())
})
```
##### `parseTime` ##### `parseTime`
@ -393,6 +443,15 @@ Default: 0
I/O write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. I/O write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
##### `connectionAttributes`
```
Type: comma-delimited string of user-defined "key:value" pairs
Valid Values: (<name1>:<value1>,<name2>:<value2>,...)
Default: none
```
[Connection attributes](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-connection-attribute-tables.html) are key-value pairs that application programs can pass to the server at connect time.
##### System Variables ##### System Variables
@ -465,12 +524,15 @@ user:password@/
The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively. The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively.
## `ColumnType` Support ## `ColumnType` Support
This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported. All Unsigned database type names will be returned `UNSIGNED ` with `INT`, `TINYINT`, `SMALLINT`, `BIGINT`. This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported. All Unsigned database type names will be returned `UNSIGNED ` with `INT`, `TINYINT`, `SMALLINT`, `MEDIUMINT`, `BIGINT`.
## `context.Context` Support ## `context.Context` Support
Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts. Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts.
See [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details. See [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details.
> [!IMPORTANT]
> The `QueryContext`, `ExecContext`, etc. variants provided by `database/sql` will cause the connection to be closed if the provided context is cancelled or timed out before the result is received by the driver.
### `LOAD DATA LOCAL INFILE` support ### `LOAD DATA LOCAL INFILE` support
For this feature you need direct access to the package. Therefore you must change the import path (no `_`): For this feature you need direct access to the package. Therefore you must change the import path (no `_`):
@ -478,7 +540,7 @@ For this feature you need direct access to the package. Therefore you must chang
import "github.com/go-sql-driver/mysql" import "github.com/go-sql-driver/mysql"
``` ```
Files must be explicitly allowed by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the allowlist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)). Files must be explicitly allowed by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the allowlist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-local)).
To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore. To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore.
@ -496,9 +558,11 @@ However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` v
### Unicode support ### Unicode support
Since version 1.5 Go-MySQL-Driver automatically uses the collation ` utf8mb4_general_ci` by default. Since version 1.5 Go-MySQL-Driver automatically uses the collation ` utf8mb4_general_ci` by default.
Other collations / charsets can be set using the [`collation`](#collation) DSN parameter. Other charsets / collations can be set using the [`charset`](#charset) or [`collation`](#collation) DSN parameter.
Version 1.0 of the driver recommended adding `&charset=utf8` (alias for `SET NAMES utf8`) to the DSN to enable proper UTF-8 support. This is not necessary anymore. The [`collation`](#collation) parameter should be preferred to set another collation / charset than the default. - When only the `charset` is specified, the `SET NAMES <charset>` query is sent and the server's default collation is used.
- When both the `charset` and `collation` are specified, the `SET NAMES <charset> COLLATE <collation>` query is sent.
- When only the `collation` is specified, the collation is specified in the protocol handshake and the `SET NAMES` query is not sent. This can save one roundtrip, but note that the server may ignore the specified collation silently and use the server's default charset/collation instead.
See http://dev.mysql.com/doc/refman/8.0/en/charset-unicode.html for more details on MySQL's Unicode support. See http://dev.mysql.com/doc/refman/8.0/en/charset-unicode.html for more details on MySQL's Unicode support.

View File

@ -1,19 +0,0 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package.
//
// Copyright 2022 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build go1.19
// +build go1.19
package mysql
import "sync/atomic"
/******************************************************************************
* Sync utils *
******************************************************************************/
type atomicBool = atomic.Bool

View File

@ -1,47 +0,0 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package.
//
// Copyright 2022 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build !go1.19
// +build !go1.19
package mysql
import "sync/atomic"
/******************************************************************************
* Sync utils *
******************************************************************************/
// atomicBool is an implementation of atomic.Bool for older version of Go.
// it is a wrapper around uint32 for usage as a boolean value with
// atomic access.
type atomicBool struct {
_ noCopy
value uint32
}
// Load returns whether the current boolean value is true
func (ab *atomicBool) Load() bool {
return atomic.LoadUint32(&ab.value) > 0
}
// Store sets the value of the bool regardless of the previous value
func (ab *atomicBool) Store(value bool) {
if value {
atomic.StoreUint32(&ab.value, 1)
} else {
atomic.StoreUint32(&ab.value, 0)
}
}
// Swap sets the value of the bool and returns the old value.
func (ab *atomicBool) Swap(value bool) bool {
if value {
return atomic.SwapUint32(&ab.value, 1) > 0
}
return atomic.SwapUint32(&ab.value, 0) > 0
}

View File

@ -13,10 +13,13 @@ import (
"crypto/rsa" "crypto/rsa"
"crypto/sha1" "crypto/sha1"
"crypto/sha256" "crypto/sha256"
"crypto/sha512"
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"sync" "sync"
"filippo.io/edwards25519"
) )
// server pub keys registry // server pub keys registry
@ -33,7 +36,7 @@ var (
// Note: The provided rsa.PublicKey instance is exclusively owned by the driver // Note: The provided rsa.PublicKey instance is exclusively owned by the driver
// after registering it and may not be modified. // after registering it and may not be modified.
// //
// data, err := ioutil.ReadFile("mykey.pem") // data, err := os.ReadFile("mykey.pem")
// if err != nil { // if err != nil {
// log.Fatal(err) // log.Fatal(err)
// } // }
@ -225,6 +228,44 @@ func encryptPassword(password string, seed []byte, pub *rsa.PublicKey) ([]byte,
return rsa.EncryptOAEP(sha1, rand.Reader, pub, plain, nil) return rsa.EncryptOAEP(sha1, rand.Reader, pub, plain, nil)
} }
// authEd25519 does ed25519 authentication used by MariaDB.
func authEd25519(scramble []byte, password string) ([]byte, error) {
// Derived from https://github.com/MariaDB/server/blob/d8e6bb00888b1f82c031938f4c8ac5d97f6874c3/plugin/auth_ed25519/ref10/sign.c
// Code style is from https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:src/crypto/ed25519/ed25519.go;l=207
h := sha512.Sum512([]byte(password))
s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
if err != nil {
return nil, err
}
A := (&edwards25519.Point{}).ScalarBaseMult(s)
mh := sha512.New()
mh.Write(h[32:])
mh.Write(scramble)
messageDigest := mh.Sum(nil)
r, err := edwards25519.NewScalar().SetUniformBytes(messageDigest)
if err != nil {
return nil, err
}
R := (&edwards25519.Point{}).ScalarBaseMult(r)
kh := sha512.New()
kh.Write(R.Bytes())
kh.Write(A.Bytes())
kh.Write(scramble)
hramDigest := kh.Sum(nil)
k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
if err != nil {
return nil, err
}
S := k.MultiplyAdd(k, s, r)
return append(R.Bytes(), S.Bytes()...), nil
}
func (mc *mysqlConn) sendEncryptedPassword(seed []byte, pub *rsa.PublicKey) error { func (mc *mysqlConn) sendEncryptedPassword(seed []byte, pub *rsa.PublicKey) error {
enc, err := encryptPassword(mc.cfg.Passwd, seed, pub) enc, err := encryptPassword(mc.cfg.Passwd, seed, pub)
if err != nil { if err != nil {
@ -290,8 +331,14 @@ func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) {
enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey) enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey)
return enc, err return enc, err
case "client_ed25519":
if len(authData) != 32 {
return nil, ErrMalformPkt
}
return authEd25519(authData, mc.cfg.Passwd)
default: default:
errLog.Print("unknown auth plugin:", plugin) mc.log("unknown auth plugin:", plugin)
return nil, ErrUnknownPlugin return nil, ErrUnknownPlugin
} }
} }
@ -338,7 +385,7 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
switch plugin { switch plugin {
// https://insidemysql.com/preparing-your-community-connector-for-mysql-8-part-2-sha256/ // https://dev.mysql.com/blog-archive/preparing-your-community-connector-for-mysql-8-part-2-sha256/
case "caching_sha2_password": case "caching_sha2_password":
switch len(authData) { switch len(authData) {
case 0: case 0:
@ -346,7 +393,7 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
case 1: case 1:
switch authData[0] { switch authData[0] {
case cachingSha2PasswordFastAuthSuccess: case cachingSha2PasswordFastAuthSuccess:
if err = mc.readResultOK(); err == nil { if err = mc.resultUnchanged().readResultOK(); err == nil {
return nil // auth successful return nil // auth successful
} }
@ -376,13 +423,13 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
} }
if data[0] != iAuthMoreData { if data[0] != iAuthMoreData {
return fmt.Errorf("unexpect resp from server for caching_sha2_password perform full authentication") return fmt.Errorf("unexpected resp from server for caching_sha2_password, perform full authentication")
} }
// parse public key // parse public key
block, rest := pem.Decode(data[1:]) block, rest := pem.Decode(data[1:])
if block == nil { if block == nil {
return fmt.Errorf("No Pem data found, data: %s", rest) return fmt.Errorf("no pem data found, data: %s", rest)
} }
pkix, err := x509.ParsePKIXPublicKey(block.Bytes) pkix, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil { if err != nil {
@ -397,7 +444,7 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
return err return err
} }
} }
return mc.readResultOK() return mc.resultUnchanged().readResultOK()
default: default:
return ErrMalformPkt return ErrMalformPkt
@ -426,7 +473,7 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
if err != nil { if err != nil {
return err return err
} }
return mc.readResultOK() return mc.resultUnchanged().readResultOK()
} }
default: default:

View File

@ -10,54 +10,47 @@ package mysql
import ( import (
"io" "io"
"net"
"time"
) )
const defaultBufSize = 4096 const defaultBufSize = 4096
const maxCachedBufSize = 256 * 1024 const maxCachedBufSize = 256 * 1024
// readerFunc is a function that compatible with io.Reader.
// We use this function type instead of io.Reader because we want to
// just pass mc.readWithTimeout.
type readerFunc func([]byte) (int, error)
// A buffer which is used for both reading and writing. // A buffer which is used for both reading and writing.
// This is possible since communication on each connection is synchronous. // This is possible since communication on each connection is synchronous.
// In other words, we can't write and read simultaneously on the same connection. // In other words, we can't write and read simultaneously on the same connection.
// The buffer is similar to bufio.Reader / Writer but zero-copy-ish // The buffer is similar to bufio.Reader / Writer but zero-copy-ish
// Also highly optimized for this particular use case. // Also highly optimized for this particular use case.
// This buffer is backed by two byte slices in a double-buffering scheme
type buffer struct { type buffer struct {
buf []byte // buf is a byte buffer who's length and capacity are equal. buf []byte // read buffer.
nc net.Conn cachedBuf []byte // buffer that will be reused. len(cachedBuf) <= maxCachedBufSize.
idx int
length int
timeout time.Duration
dbuf [2][]byte // dbuf is an array with the two byte slices that back this buffer
flipcnt uint // flipccnt is the current buffer counter for double-buffering
} }
// newBuffer allocates and returns a new buffer. // newBuffer allocates and returns a new buffer.
func newBuffer(nc net.Conn) buffer { func newBuffer() buffer {
fg := make([]byte, defaultBufSize)
return buffer{ return buffer{
buf: fg, cachedBuf: make([]byte, defaultBufSize),
nc: nc,
dbuf: [2][]byte{fg, nil},
} }
} }
// flip replaces the active buffer with the background buffer // busy returns true if the read buffer is not empty.
// this is a delayed flip that simply increases the buffer counter; func (b *buffer) busy() bool {
// the actual flip will be performed the next time we call `buffer.fill` return len(b.buf) > 0
func (b *buffer) flip() {
b.flipcnt += 1
} }
// fill reads into the buffer until at least _need_ bytes are in it // len returns how many bytes in the read buffer.
func (b *buffer) fill(need int) error { func (b *buffer) len() int {
n := b.length return len(b.buf)
// fill data into its double-buffering target: if we've called }
// flip on this buffer, we'll be copying to the background buffer,
// and then filling it with network data; otherwise we'll just move // fill reads into the read buffer until at least _need_ bytes are in it.
// the contents of the current buffer to the front before filling it func (b *buffer) fill(need int, r readerFunc) error {
dest := b.dbuf[b.flipcnt&1] // we'll move the contents of the current buffer to dest before filling it.
dest := b.cachedBuf
// grow buffer if necessary to fit the whole packet. // grow buffer if necessary to fit the whole packet.
if need > len(dest) { if need > len(dest) {
@ -67,64 +60,41 @@ func (b *buffer) fill(need int) error {
// if the allocated buffer is not too large, move it to backing storage // if the allocated buffer is not too large, move it to backing storage
// to prevent extra allocations on applications that perform large reads // to prevent extra allocations on applications that perform large reads
if len(dest) <= maxCachedBufSize { if len(dest) <= maxCachedBufSize {
b.dbuf[b.flipcnt&1] = dest b.cachedBuf = dest
} }
} }
// if we're filling the fg buffer, move the existing data to the start of it. // move the existing data to the start of the buffer.
// if we're filling the bg buffer, copy over the data n := len(b.buf)
if n > 0 { copy(dest[:n], b.buf)
copy(dest[:n], b.buf[b.idx:])
}
b.buf = dest
b.idx = 0
for { for {
if b.timeout > 0 { nn, err := r(dest[n:])
if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil {
return err
}
}
nn, err := b.nc.Read(b.buf[n:])
n += nn n += nn
switch err { if err == nil && n < need {
case nil: continue
if n < need {
continue
}
b.length = n
return nil
case io.EOF:
if n >= need {
b.length = n
return nil
}
return io.ErrUnexpectedEOF
default:
return err
} }
b.buf = dest[:n]
if err == io.EOF {
if n < need {
err = io.ErrUnexpectedEOF
} else {
err = nil
}
}
return err
} }
} }
// returns next N bytes from buffer. // returns next N bytes from buffer.
// The returned slice is only guaranteed to be valid until the next read // The returned slice is only guaranteed to be valid until the next read
func (b *buffer) readNext(need int) ([]byte, error) { func (b *buffer) readNext(need int) []byte {
if b.length < need { data := b.buf[:need:need]
// refill b.buf = b.buf[need:]
if err := b.fill(need); err != nil { return data
return nil, err
}
}
offset := b.idx
b.idx += need
b.length -= need
return b.buf[offset:b.idx], nil
} }
// takeBuffer returns a buffer with the requested size. // takeBuffer returns a buffer with the requested size.
@ -132,18 +102,18 @@ func (b *buffer) readNext(need int) ([]byte, error) {
// Otherwise a bigger buffer is made. // Otherwise a bigger buffer is made.
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeBuffer(length int) ([]byte, error) { func (b *buffer) takeBuffer(length int) ([]byte, error) {
if b.length > 0 { if b.busy() {
return nil, ErrBusyBuffer return nil, ErrBusyBuffer
} }
// test (cheap) general case first // test (cheap) general case first
if length <= cap(b.buf) { if length <= len(b.cachedBuf) {
return b.buf[:length], nil return b.cachedBuf[:length], nil
} }
if length < maxPacketSize { if length < maxCachedBufSize {
b.buf = make([]byte, length) b.cachedBuf = make([]byte, length)
return b.buf, nil return b.cachedBuf, nil
} }
// buffer is larger than we want to store. // buffer is larger than we want to store.
@ -154,10 +124,10 @@ func (b *buffer) takeBuffer(length int) ([]byte, error) {
// known to be smaller than defaultBufSize. // known to be smaller than defaultBufSize.
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeSmallBuffer(length int) ([]byte, error) { func (b *buffer) takeSmallBuffer(length int) ([]byte, error) {
if b.length > 0 { if b.busy() {
return nil, ErrBusyBuffer return nil, ErrBusyBuffer
} }
return b.buf[:length], nil return b.cachedBuf[:length], nil
} }
// takeCompleteBuffer returns the complete existing buffer. // takeCompleteBuffer returns the complete existing buffer.
@ -165,18 +135,15 @@ func (b *buffer) takeSmallBuffer(length int) ([]byte, error) {
// cap and len of the returned buffer will be equal. // cap and len of the returned buffer will be equal.
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeCompleteBuffer() ([]byte, error) { func (b *buffer) takeCompleteBuffer() ([]byte, error) {
if b.length > 0 { if b.busy() {
return nil, ErrBusyBuffer return nil, ErrBusyBuffer
} }
return b.buf, nil return b.cachedBuf, nil
} }
// store stores buf, an updated buffer, if its suitable to do so. // store stores buf, an updated buffer, if its suitable to do so.
func (b *buffer) store(buf []byte) error { func (b *buffer) store(buf []byte) {
if b.length > 0 { if cap(buf) <= maxCachedBufSize && cap(buf) > cap(b.cachedBuf) {
return ErrBusyBuffer b.cachedBuf = buf[:cap(buf)]
} else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) {
b.buf = buf[:cap(buf)]
} }
return nil
} }

View File

@ -8,8 +8,8 @@
package mysql package mysql
const defaultCollation = "utf8mb4_general_ci" const defaultCollationID = 45 // utf8mb4_general_ci
const binaryCollation = "binary" const binaryCollationID = 63
// A list of available collations mapped to the internal ID. // A list of available collations mapped to the internal ID.
// To update this map use the following MySQL query: // To update this map use the following MySQL query:

213
vendor/github.com/go-sql-driver/mysql/compress.go generated vendored Normal file
View File

@ -0,0 +1,213 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2024 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
package mysql
import (
"bytes"
"compress/zlib"
"fmt"
"io"
"sync"
)
var (
zrPool *sync.Pool // Do not use directly. Use zDecompress() instead.
zwPool *sync.Pool // Do not use directly. Use zCompress() instead.
)
func init() {
zrPool = &sync.Pool{
New: func() any { return nil },
}
zwPool = &sync.Pool{
New: func() any {
zw, err := zlib.NewWriterLevel(new(bytes.Buffer), 2)
if err != nil {
panic(err) // compress/zlib return non-nil error only if level is invalid
}
return zw
},
}
}
func zDecompress(src []byte, dst *bytes.Buffer) (int, error) {
br := bytes.NewReader(src)
var zr io.ReadCloser
var err error
if a := zrPool.Get(); a == nil {
if zr, err = zlib.NewReader(br); err != nil {
return 0, err
}
} else {
zr = a.(io.ReadCloser)
if err := zr.(zlib.Resetter).Reset(br, nil); err != nil {
return 0, err
}
}
n, _ := dst.ReadFrom(zr) // ignore err because zr.Close() will return it again.
err = zr.Close() // zr.Close() may return chuecksum error.
zrPool.Put(zr)
return int(n), err
}
func zCompress(src []byte, dst io.Writer) error {
zw := zwPool.Get().(*zlib.Writer)
zw.Reset(dst)
if _, err := zw.Write(src); err != nil {
return err
}
err := zw.Close()
zwPool.Put(zw)
return err
}
type compIO struct {
mc *mysqlConn
buff bytes.Buffer
}
func newCompIO(mc *mysqlConn) *compIO {
return &compIO{
mc: mc,
}
}
func (c *compIO) reset() {
c.buff.Reset()
}
func (c *compIO) readNext(need int) ([]byte, error) {
for c.buff.Len() < need {
if err := c.readCompressedPacket(); err != nil {
return nil, err
}
}
data := c.buff.Next(need)
return data[:need:need], nil // prevent caller writes into c.buff
}
func (c *compIO) readCompressedPacket() error {
header, err := c.mc.readNext(7)
if err != nil {
return err
}
_ = header[6] // bounds check hint to compiler; guaranteed by readNext
// compressed header structure
comprLength := getUint24(header[0:3])
compressionSequence := header[3]
uncompressedLength := getUint24(header[4:7])
if debug {
fmt.Printf("uncompress cmplen=%v uncomplen=%v pkt_cmp_seq=%v expected_cmp_seq=%v\n",
comprLength, uncompressedLength, compressionSequence, c.mc.sequence)
}
// Do not return ErrPktSync here.
// Server may return error packet (e.g. 1153 Got a packet bigger than 'max_allowed_packet' bytes)
// before receiving all packets from client. In this case, seqnr is younger than expected.
// NOTE: Both of mariadbclient and mysqlclient do not check seqnr. Only server checks it.
if debug && compressionSequence != c.mc.compressSequence {
fmt.Printf("WARN: unexpected cmpress seq nr: expected %v, got %v",
c.mc.compressSequence, compressionSequence)
}
c.mc.compressSequence = compressionSequence + 1
comprData, err := c.mc.readNext(comprLength)
if err != nil {
return err
}
// if payload is uncompressed, its length will be specified as zero, and its
// true length is contained in comprLength
if uncompressedLength == 0 {
c.buff.Write(comprData)
return nil
}
// use existing capacity in bytesBuf if possible
c.buff.Grow(uncompressedLength)
nread, err := zDecompress(comprData, &c.buff)
if err != nil {
return err
}
if nread != uncompressedLength {
return fmt.Errorf("invalid compressed packet: uncompressed length in header is %d, actual %d",
uncompressedLength, nread)
}
return nil
}
const minCompressLength = 150
const maxPayloadLen = maxPacketSize - 4
// writePackets sends one or some packets with compression.
// Use this instead of mc.netConn.Write() when mc.compress is true.
func (c *compIO) writePackets(packets []byte) (int, error) {
totalBytes := len(packets)
blankHeader := make([]byte, 7)
buf := &c.buff
for len(packets) > 0 {
payloadLen := min(maxPayloadLen, len(packets))
payload := packets[:payloadLen]
uncompressedLen := payloadLen
buf.Reset()
buf.Write(blankHeader) // Buffer.Write() never returns error
// If payload is less than minCompressLength, don't compress.
if uncompressedLen < minCompressLength {
buf.Write(payload)
uncompressedLen = 0
} else {
err := zCompress(payload, buf)
if debug && err != nil {
fmt.Printf("zCompress error: %v", err)
}
// do not compress if compressed data is larger than uncompressed data
// I intentionally miss 7 byte header in the buf; zCompress must compress more than 7 bytes.
if err != nil || buf.Len() >= uncompressedLen {
buf.Reset()
buf.Write(blankHeader)
buf.Write(payload)
uncompressedLen = 0
}
}
if n, err := c.writeCompressedPacket(buf.Bytes(), uncompressedLen); err != nil {
// To allow returning ErrBadConn when sending really 0 bytes, we sum
// up compressed bytes that is returned by underlying Write().
return totalBytes - len(packets) + n, err
}
packets = packets[payloadLen:]
}
return totalBytes, nil
}
// writeCompressedPacket writes a compressed packet with header.
// data should start with 7 size space for header followed by payload.
func (c *compIO) writeCompressedPacket(data []byte, uncompressedLen int) (int, error) {
mc := c.mc
comprLength := len(data) - 7
if debug {
fmt.Printf(
"writeCompressedPacket: comprLength=%v, uncompressedLen=%v, seq=%v\n",
comprLength, uncompressedLen, mc.compressSequence)
}
// compression header
putUint24(data[0:3], comprLength)
data[3] = mc.compressSequence
putUint24(data[4:7], uncompressedLen)
mc.compressSequence++
return mc.writeWithTimeout(data)
}

View File

@ -13,28 +13,32 @@ import (
"database/sql" "database/sql"
"database/sql/driver" "database/sql/driver"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"net" "net"
"runtime"
"strconv" "strconv"
"strings" "strings"
"sync/atomic"
"time" "time"
) )
type mysqlConn struct { type mysqlConn struct {
buf buffer buf buffer
netConn net.Conn netConn net.Conn
rawConn net.Conn // underlying connection when netConn is TLS connection. rawConn net.Conn // underlying connection when netConn is TLS connection.
affectedRows uint64 result mysqlResult // managed by clearResult() and handleOkPacket().
insertId uint64 compIO *compIO
cfg *Config cfg *Config
connector *connector
maxAllowedPacket int maxAllowedPacket int
maxWriteSize int maxWriteSize int
writeTimeout time.Duration
flags clientFlag flags clientFlag
status statusFlag status statusFlag
sequence uint8 sequence uint8
compressSequence uint8
parseTime bool parseTime bool
reset bool // set when the Go SQL package calls ResetSession compress bool
// for context support (Go 1.8+) // for context support (Go 1.8+)
watching bool watching bool
@ -42,61 +46,92 @@ type mysqlConn struct {
closech chan struct{} closech chan struct{}
finished chan<- struct{} finished chan<- struct{}
canceled atomicError // set non-nil if conn is canceled canceled atomicError // set non-nil if conn is canceled
closed atomicBool // set when conn is closed, before closech is closed closed atomic.Bool // set when conn is closed, before closech is closed
}
// Helper function to call per-connection logger.
func (mc *mysqlConn) log(v ...any) {
_, filename, lineno, ok := runtime.Caller(1)
if ok {
pos := strings.LastIndexByte(filename, '/')
if pos != -1 {
filename = filename[pos+1:]
}
prefix := fmt.Sprintf("%s:%d ", filename, lineno)
v = append([]any{prefix}, v...)
}
mc.cfg.Logger.Print(v...)
}
func (mc *mysqlConn) readWithTimeout(b []byte) (int, error) {
to := mc.cfg.ReadTimeout
if to > 0 {
if err := mc.netConn.SetReadDeadline(time.Now().Add(to)); err != nil {
return 0, err
}
}
return mc.netConn.Read(b)
}
func (mc *mysqlConn) writeWithTimeout(b []byte) (int, error) {
to := mc.cfg.WriteTimeout
if to > 0 {
if err := mc.netConn.SetWriteDeadline(time.Now().Add(to)); err != nil {
return 0, err
}
}
return mc.netConn.Write(b)
}
func (mc *mysqlConn) resetSequence() {
mc.sequence = 0
mc.compressSequence = 0
}
// syncSequence must be called when finished writing some packet and before start reading.
func (mc *mysqlConn) syncSequence() {
// Syncs compressionSequence to sequence.
// This is not documented but done in `net_flush()` in MySQL and MariaDB.
// https://github.com/mariadb-corporation/mariadb-connector-c/blob/8228164f850b12353da24df1b93a1e53cc5e85e9/libmariadb/ma_net.c#L170-L171
// https://github.com/mysql/mysql-server/blob/824e2b4064053f7daf17d7f3f84b7a3ed92e5fb4/sql-common/net_serv.cc#L293
if mc.compress {
mc.sequence = mc.compressSequence
mc.compIO.reset()
}
} }
// Handles parameters set in DSN after the connection is established // Handles parameters set in DSN after the connection is established
func (mc *mysqlConn) handleParams() (err error) { func (mc *mysqlConn) handleParams() (err error) {
var cmdSet strings.Builder var cmdSet strings.Builder
for param, val := range mc.cfg.Params {
switch param {
// Charset: character_set_connection, character_set_client, character_set_results
case "charset":
charsets := strings.Split(val, ",")
for i := range charsets {
// ignore errors here - a charset may not exist
err = mc.exec("SET NAMES " + charsets[i])
if err == nil {
break
}
}
if err != nil {
return
}
// Other system vars accumulated in a single SET command for param, val := range mc.cfg.Params {
default: if cmdSet.Len() == 0 {
if cmdSet.Len() == 0 { // Heuristic: 29 chars for each other key=value to reduce reallocations
// Heuristic: 29 chars for each other key=value to reduce reallocations cmdSet.Grow(4 + len(param) + 3 + len(val) + 30*(len(mc.cfg.Params)-1))
cmdSet.Grow(4 + len(param) + 1 + len(val) + 30*(len(mc.cfg.Params)-1)) cmdSet.WriteString("SET ")
cmdSet.WriteString("SET ") } else {
} else { cmdSet.WriteString(", ")
cmdSet.WriteByte(',')
}
cmdSet.WriteString(param)
cmdSet.WriteByte('=')
cmdSet.WriteString(val)
} }
cmdSet.WriteString(param)
cmdSet.WriteString(" = ")
cmdSet.WriteString(val)
} }
if cmdSet.Len() > 0 { if cmdSet.Len() > 0 {
err = mc.exec(cmdSet.String()) err = mc.exec(cmdSet.String())
if err != nil {
return
}
} }
return return
} }
// markBadConn replaces errBadConnNoWrite with driver.ErrBadConn.
// This function is used to return driver.ErrBadConn only when safe to retry.
func (mc *mysqlConn) markBadConn(err error) error { func (mc *mysqlConn) markBadConn(err error) error {
if mc == nil { if err == errBadConnNoWrite {
return err return driver.ErrBadConn
} }
if err != errBadConnNoWrite { return err
return err
}
return driver.ErrBadConn
} }
func (mc *mysqlConn) Begin() (driver.Tx, error) { func (mc *mysqlConn) Begin() (driver.Tx, error) {
@ -105,7 +140,6 @@ func (mc *mysqlConn) Begin() (driver.Tx, error) {
func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) { func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
if mc.closed.Load() { if mc.closed.Load() {
errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
var q string var q string
@ -126,12 +160,16 @@ func (mc *mysqlConn) Close() (err error) {
if !mc.closed.Load() { if !mc.closed.Load() {
err = mc.writeCommandPacket(comQuit) err = mc.writeCommandPacket(comQuit)
} }
mc.close()
mc.cleanup()
return return
} }
// close closes the network connection and clear results without sending COM_QUIT.
func (mc *mysqlConn) close() {
mc.cleanup()
mc.clearResult()
}
// Closes the network connection and unsets internal variables. Do not call this // Closes the network connection and unsets internal variables. Do not call this
// function after successfully authentication, call Close instead. This function // function after successfully authentication, call Close instead. This function
// is called before auth or on auth failure because MySQL will have already // is called before auth or on auth failure because MySQL will have already
@ -143,12 +181,16 @@ func (mc *mysqlConn) cleanup() {
// Makes cleanup idempotent // Makes cleanup idempotent
close(mc.closech) close(mc.closech)
if mc.netConn == nil { conn := mc.rawConn
if conn == nil {
return return
} }
if err := mc.netConn.Close(); err != nil { if err := conn.Close(); err != nil {
errLog.Print(err) mc.log("closing connection:", err)
} }
// This function can be called from multiple goroutines.
// So we can not mc.clearResult() here.
// Caller should do it if they are in safe goroutine.
} }
func (mc *mysqlConn) error() error { func (mc *mysqlConn) error() error {
@ -163,14 +205,13 @@ func (mc *mysqlConn) error() error {
func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
if mc.closed.Load() { if mc.closed.Load() {
errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
// Send command // Send command
err := mc.writeCommandPacketStr(comStmtPrepare, query) err := mc.writeCommandPacketStr(comStmtPrepare, query)
if err != nil { if err != nil {
// STMT_PREPARE is safe to retry. So we can return ErrBadConn here. // STMT_PREPARE is safe to retry. So we can return ErrBadConn here.
errLog.Print(err) mc.log(err)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
@ -204,8 +245,10 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
buf, err := mc.buf.takeCompleteBuffer() buf, err := mc.buf.takeCompleteBuffer()
if err != nil { if err != nil {
// can not take the buffer. Something must be wrong with the connection // can not take the buffer. Something must be wrong with the connection
errLog.Print(err) mc.cleanup()
return "", ErrInvalidConn // interpolateParams would be called before sending any query.
// So its safe to retry.
return "", driver.ErrBadConn
} }
buf = buf[:0] buf = buf[:0]
argPos := 0 argPos := 0
@ -246,7 +289,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
buf = append(buf, "'0000-00-00'"...) buf = append(buf, "'0000-00-00'"...)
} else { } else {
buf = append(buf, '\'') buf = append(buf, '\'')
buf, err = appendDateTime(buf, v.In(mc.cfg.Loc)) buf, err = appendDateTime(buf, v.In(mc.cfg.Loc), mc.cfg.timeTruncate)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -296,7 +339,6 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
if mc.closed.Load() { if mc.closed.Load() {
errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
if len(args) != 0 { if len(args) != 0 {
@ -310,28 +352,25 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err
} }
query = prepared query = prepared
} }
mc.affectedRows = 0
mc.insertId = 0
err := mc.exec(query) err := mc.exec(query)
if err == nil { if err == nil {
return &mysqlResult{ copied := mc.result
affectedRows: int64(mc.affectedRows), return &copied, err
insertId: int64(mc.insertId),
}, err
} }
return nil, mc.markBadConn(err) return nil, mc.markBadConn(err)
} }
// Internal function to execute commands // Internal function to execute commands
func (mc *mysqlConn) exec(query string) error { func (mc *mysqlConn) exec(query string) error {
handleOk := mc.clearResult()
// Send command // Send command
if err := mc.writeCommandPacketStr(comQuery, query); err != nil { if err := mc.writeCommandPacketStr(comQuery, query); err != nil {
return mc.markBadConn(err) return mc.markBadConn(err)
} }
// Read Result // Read Result
resLen, err := mc.readResultSetHeaderPacket() resLen, err := handleOk.readResultSetHeaderPacket()
if err != nil { if err != nil {
return err return err
} }
@ -348,7 +387,7 @@ func (mc *mysqlConn) exec(query string) error {
} }
} }
return mc.discardResults() return handleOk.discardResults()
} }
func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) { func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
@ -356,8 +395,9 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro
} }
func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) { func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) {
handleOk := mc.clearResult()
if mc.closed.Load() { if mc.closed.Load() {
errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
if len(args) != 0 { if len(args) != 0 {
@ -373,43 +413,47 @@ func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error)
} }
// Send command // Send command
err := mc.writeCommandPacketStr(comQuery, query) err := mc.writeCommandPacketStr(comQuery, query)
if err == nil { if err != nil {
// Read Result return nil, mc.markBadConn(err)
var resLen int }
resLen, err = mc.readResultSetHeaderPacket()
if err == nil {
rows := new(textRows)
rows.mc = mc
if resLen == 0 { // Read Result
rows.rs.done = true var resLen int
resLen, err = handleOk.readResultSetHeaderPacket()
if err != nil {
return nil, err
}
switch err := rows.NextResultSet(); err { rows := new(textRows)
case nil, io.EOF: rows.mc = mc
return rows, nil
default:
return nil, err
}
}
// Columns if resLen == 0 {
rows.rs.columns, err = mc.readColumns(resLen) rows.rs.done = true
return rows, err
switch err := rows.NextResultSet(); err {
case nil, io.EOF:
return rows, nil
default:
return nil, err
} }
} }
return nil, mc.markBadConn(err)
// Columns
rows.rs.columns, err = mc.readColumns(resLen)
return rows, err
} }
// Gets the value of the given MySQL System Variable // Gets the value of the given MySQL System Variable
// The returned byte slice is only valid until the next read // The returned byte slice is only valid until the next read
func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
// Send command // Send command
handleOk := mc.clearResult()
if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil { if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil {
return nil, err return nil, err
} }
// Read Result // Read Result
resLen, err := mc.readResultSetHeaderPacket() resLen, err := handleOk.readResultSetHeaderPacket()
if err == nil { if err == nil {
rows := new(textRows) rows := new(textRows)
rows.mc = mc rows.mc = mc
@ -430,7 +474,7 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
return nil, err return nil, err
} }
// finish is called when the query has canceled. // cancel is called when the query has canceled.
func (mc *mysqlConn) cancel(err error) { func (mc *mysqlConn) cancel(err error) {
mc.canceled.Set(err) mc.canceled.Set(err)
mc.cleanup() mc.cleanup()
@ -451,7 +495,6 @@ func (mc *mysqlConn) finish() {
// Ping implements driver.Pinger interface // Ping implements driver.Pinger interface
func (mc *mysqlConn) Ping(ctx context.Context) (err error) { func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
if mc.closed.Load() { if mc.closed.Load() {
errLog.Print(ErrInvalidConn)
return driver.ErrBadConn return driver.ErrBadConn
} }
@ -460,11 +503,12 @@ func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
} }
defer mc.finish() defer mc.finish()
handleOk := mc.clearResult()
if err = mc.writeCommandPacket(comPing); err != nil { if err = mc.writeCommandPacket(comPing); err != nil {
return mc.markBadConn(err) return mc.markBadConn(err)
} }
return mc.readResultOK() return handleOk.readResultOK()
} }
// BeginTx implements driver.ConnBeginTx interface // BeginTx implements driver.ConnBeginTx interface
@ -636,15 +680,42 @@ func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
// ResetSession implements driver.SessionResetter. // ResetSession implements driver.SessionResetter.
// (From Go 1.10) // (From Go 1.10)
func (mc *mysqlConn) ResetSession(ctx context.Context) error { func (mc *mysqlConn) ResetSession(ctx context.Context) error {
if mc.closed.Load() { if mc.closed.Load() || mc.buf.busy() {
return driver.ErrBadConn return driver.ErrBadConn
} }
mc.reset = true
// Perform a stale connection check. We only perform this check for
// the first query on a connection that has been checked out of the
// connection pool: a fresh connection from the pool is more likely
// to be stale, and it has not performed any previous writes that
// could cause data corruption, so it's safe to return ErrBadConn
// if the check fails.
if mc.cfg.CheckConnLiveness {
conn := mc.netConn
if mc.rawConn != nil {
conn = mc.rawConn
}
var err error
if mc.cfg.ReadTimeout != 0 {
err = conn.SetReadDeadline(time.Now().Add(mc.cfg.ReadTimeout))
}
if err == nil {
err = connCheck(conn)
}
if err != nil {
mc.log("closing bad idle connection: ", err)
return driver.ErrBadConn
}
}
return nil return nil
} }
// IsValid implements driver.Validator interface // IsValid implements driver.Validator interface
// (From Go 1.15) // (From Go 1.15)
func (mc *mysqlConn) IsValid() bool { func (mc *mysqlConn) IsValid() bool {
return !mc.closed.Load() return !mc.closed.Load() && !mc.buf.busy()
} }
var _ driver.SessionResetter = &mysqlConn{}
var _ driver.Validator = &mysqlConn{}

View File

@ -11,11 +11,55 @@ package mysql
import ( import (
"context" "context"
"database/sql/driver" "database/sql/driver"
"fmt"
"net" "net"
"os"
"strconv"
"strings"
) )
type connector struct { type connector struct {
cfg *Config // immutable private copy. cfg *Config // immutable private copy.
encodedAttributes string // Encoded connection attributes.
}
func encodeConnectionAttributes(cfg *Config) string {
connAttrsBuf := make([]byte, 0)
// default connection attributes
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrClientName)
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrClientNameValue)
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrOS)
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrOSValue)
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPlatform)
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPlatformValue)
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPid)
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, strconv.Itoa(os.Getpid()))
serverHost, _, _ := net.SplitHostPort(cfg.Addr)
if serverHost != "" {
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrServerHost)
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, serverHost)
}
// user-defined connection attributes
for _, connAttr := range strings.Split(cfg.ConnectionAttributes, ",") {
k, v, found := strings.Cut(connAttr, ":")
if !found {
continue
}
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, k)
connAttrsBuf = appendLengthEncodedString(connAttrsBuf, v)
}
return string(connAttrsBuf)
}
func newConnector(cfg *Config) *connector {
encodedAttributes := encodeConnectionAttributes(cfg)
return &connector{
cfg: cfg,
encodedAttributes: encodedAttributes,
}
} }
// Connect implements driver.Connector interface. // Connect implements driver.Connector interface.
@ -23,43 +67,56 @@ type connector struct {
func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { func (c *connector) Connect(ctx context.Context) (driver.Conn, error) {
var err error var err error
// Invoke beforeConnect if present, with a copy of the configuration
cfg := c.cfg
if c.cfg.beforeConnect != nil {
cfg = c.cfg.Clone()
err = c.cfg.beforeConnect(ctx, cfg)
if err != nil {
return nil, err
}
}
// New mysqlConn // New mysqlConn
mc := &mysqlConn{ mc := &mysqlConn{
maxAllowedPacket: maxPacketSize, maxAllowedPacket: maxPacketSize,
maxWriteSize: maxPacketSize - 1, maxWriteSize: maxPacketSize - 1,
closech: make(chan struct{}), closech: make(chan struct{}),
cfg: c.cfg, cfg: cfg,
connector: c,
} }
mc.parseTime = mc.cfg.ParseTime mc.parseTime = mc.cfg.ParseTime
// Connect to Server // Connect to Server
dialsLock.RLock() dctx := ctx
dial, ok := dials[mc.cfg.Net] if mc.cfg.Timeout > 0 {
dialsLock.RUnlock() var cancel context.CancelFunc
if ok { dctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout)
dctx := ctx defer cancel()
if mc.cfg.Timeout > 0 {
var cancel context.CancelFunc
dctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout)
defer cancel()
}
mc.netConn, err = dial(dctx, mc.cfg.Addr)
} else {
nd := net.Dialer{Timeout: mc.cfg.Timeout}
mc.netConn, err = nd.DialContext(ctx, mc.cfg.Net, mc.cfg.Addr)
} }
if c.cfg.DialFunc != nil {
mc.netConn, err = c.cfg.DialFunc(dctx, mc.cfg.Net, mc.cfg.Addr)
} else {
dialsLock.RLock()
dial, ok := dials[mc.cfg.Net]
dialsLock.RUnlock()
if ok {
mc.netConn, err = dial(dctx, mc.cfg.Addr)
} else {
nd := net.Dialer{}
mc.netConn, err = nd.DialContext(dctx, mc.cfg.Net, mc.cfg.Addr)
}
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
mc.rawConn = mc.netConn
// Enable TCP Keepalives on TCP connections // Enable TCP Keepalives on TCP connections
if tc, ok := mc.netConn.(*net.TCPConn); ok { if tc, ok := mc.netConn.(*net.TCPConn); ok {
if err := tc.SetKeepAlive(true); err != nil { if err := tc.SetKeepAlive(true); err != nil {
// Don't send COM_QUIT before handshake. c.cfg.Logger.Print(err)
mc.netConn.Close()
mc.netConn = nil
return nil, err
} }
} }
@ -71,11 +128,7 @@ func (c *connector) Connect(ctx context.Context) (driver.Conn, error) {
} }
defer mc.finish() defer mc.finish()
mc.buf = newBuffer(mc.netConn) mc.buf = newBuffer()
// Set I/O timeouts
mc.buf.timeout = mc.cfg.ReadTimeout
mc.writeTimeout = mc.cfg.WriteTimeout
// Reading Handshake Initialization Packet // Reading Handshake Initialization Packet
authData, plugin, err := mc.readHandshakePacket() authData, plugin, err := mc.readHandshakePacket()
@ -92,7 +145,7 @@ func (c *connector) Connect(ctx context.Context) (driver.Conn, error) {
authResp, err := mc.auth(authData, plugin) authResp, err := mc.auth(authData, plugin)
if err != nil { if err != nil {
// try the default auth plugin, if using the requested plugin failed // try the default auth plugin, if using the requested plugin failed
errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error()) c.cfg.Logger.Print("could not use requested auth plugin '"+plugin+"': ", err.Error())
plugin = defaultAuthPlugin plugin = defaultAuthPlugin
authResp, err = mc.auth(authData, plugin) authResp, err = mc.auth(authData, plugin)
if err != nil { if err != nil {
@ -114,6 +167,10 @@ func (c *connector) Connect(ctx context.Context) (driver.Conn, error) {
return nil, err return nil, err
} }
if mc.cfg.compress && mc.flags&clientCompress == clientCompress {
mc.compress = true
mc.compIO = newCompIO(mc)
}
if mc.cfg.MaxAllowedPacket > 0 { if mc.cfg.MaxAllowedPacket > 0 {
mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket
} else { } else {
@ -123,12 +180,36 @@ func (c *connector) Connect(ctx context.Context) (driver.Conn, error) {
mc.Close() mc.Close()
return nil, err return nil, err
} }
mc.maxAllowedPacket = stringToInt(maxap) - 1 n, err := strconv.Atoi(string(maxap))
if err != nil {
mc.Close()
return nil, fmt.Errorf("invalid max_allowed_packet value (%q): %w", maxap, err)
}
mc.maxAllowedPacket = n - 1
} }
if mc.maxAllowedPacket < maxPacketSize { if mc.maxAllowedPacket < maxPacketSize {
mc.maxWriteSize = mc.maxAllowedPacket mc.maxWriteSize = mc.maxAllowedPacket
} }
// Charset: character_set_connection, character_set_client, character_set_results
if len(mc.cfg.charsets) > 0 {
for _, cs := range mc.cfg.charsets {
// ignore errors here - a charset may not exist
if mc.cfg.Collation != "" {
err = mc.exec("SET NAMES " + cs + " COLLATE " + mc.cfg.Collation)
} else {
err = mc.exec("SET NAMES " + cs)
}
if err == nil {
break
}
}
if err != nil {
mc.Close()
return nil, err
}
}
// Handle DSN Params // Handle DSN Params
err = mc.handleParams() err = mc.handleParams()
if err != nil { if err != nil {

View File

@ -8,12 +8,27 @@
package mysql package mysql
import "runtime"
const ( const (
debug = false // for debugging. Set true only in development.
defaultAuthPlugin = "mysql_native_password" defaultAuthPlugin = "mysql_native_password"
defaultMaxAllowedPacket = 4 << 20 // 4 MiB defaultMaxAllowedPacket = 64 << 20 // 64 MiB. See https://github.com/go-sql-driver/mysql/issues/1355
minProtocolVersion = 10 minProtocolVersion = 10
maxPacketSize = 1<<24 - 1 maxPacketSize = 1<<24 - 1
timeFormat = "2006-01-02 15:04:05.999999" timeFormat = "2006-01-02 15:04:05.999999"
// Connection attributes
// See https://dev.mysql.com/doc/refman/8.0/en/performance-schema-connection-attribute-tables.html#performance-schema-connection-attributes-available
connAttrClientName = "_client_name"
connAttrClientNameValue = "Go-MySQL-Driver"
connAttrOS = "_os"
connAttrOSValue = runtime.GOOS
connAttrPlatform = "_platform"
connAttrPlatformValue = runtime.GOARCH
connAttrPid = "_pid"
connAttrServerHost = "_server_host"
) )
// MySQL constants documentation: // MySQL constants documentation:
@ -112,7 +127,10 @@ const (
fieldTypeBit fieldTypeBit
) )
const ( const (
fieldTypeJSON fieldType = iota + 0xf5 fieldTypeVector fieldType = iota + 0xf2
fieldTypeInvalid
fieldTypeBool
fieldTypeJSON
fieldTypeNewDecimal fieldTypeNewDecimal
fieldTypeEnum fieldTypeEnum
fieldTypeSet fieldTypeSet

View File

@ -55,6 +55,15 @@ func RegisterDialContext(net string, dial DialContextFunc) {
dials[net] = dial dials[net] = dial
} }
// DeregisterDialContext removes the custom dial function registered with the given net.
func DeregisterDialContext(net string) {
dialsLock.Lock()
defer dialsLock.Unlock()
if dials != nil {
delete(dials, net)
}
}
// RegisterDial registers a custom dial function. It can then be used by the // RegisterDial registers a custom dial function. It can then be used by the
// network address mynet(addr), where mynet is the registered new network. // network address mynet(addr), where mynet is the registered new network.
// addr is passed as a parameter to the dial function. // addr is passed as a parameter to the dial function.
@ -74,14 +83,18 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
c := &connector{ c := newConnector(cfg)
cfg: cfg,
}
return c.Connect(context.Background()) return c.Connect(context.Background())
} }
// This variable can be replaced with -ldflags like below:
// go build "-ldflags=-X github.com/go-sql-driver/mysql.driverName=custom"
var driverName = "mysql"
func init() { func init() {
sql.Register("mysql", &MySQLDriver{}) if driverName != "" {
sql.Register(driverName, &MySQLDriver{})
}
} }
// NewConnector returns new driver.Connector. // NewConnector returns new driver.Connector.
@ -92,7 +105,7 @@ func NewConnector(cfg *Config) (driver.Connector, error) {
if err := cfg.normalize(); err != nil { if err := cfg.normalize(); err != nil {
return nil, err return nil, err
} }
return &connector{cfg: cfg}, nil return newConnector(cfg), nil
} }
// OpenConnector implements driver.DriverContext. // OpenConnector implements driver.DriverContext.
@ -101,7 +114,5 @@ func (d MySQLDriver) OpenConnector(dsn string) (driver.Connector, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &connector{ return newConnector(cfg), nil
cfg: cfg,
}, nil
} }

View File

@ -10,6 +10,7 @@ package mysql
import ( import (
"bytes" "bytes"
"context"
"crypto/rsa" "crypto/rsa"
"crypto/tls" "crypto/tls"
"errors" "errors"
@ -34,22 +35,29 @@ var (
// If a new Config is created instead of being parsed from a DSN string, // If a new Config is created instead of being parsed from a DSN string,
// the NewConfig function should be used, which sets default values. // the NewConfig function should be used, which sets default values.
type Config struct { type Config struct {
User string // Username // non boolean fields
Passwd string // Password (requires User)
Net string // Network type User string // Username
Addr string // Network address (requires Net) Passwd string // Password (requires User)
DBName string // Database name Net string // Network (e.g. "tcp", "tcp6", "unix". default: "tcp")
Params map[string]string // Connection parameters Addr string // Address (default: "127.0.0.1:3306" for "tcp" and "/tmp/mysql.sock" for "unix")
Collation string // Connection collation DBName string // Database name
Loc *time.Location // Location for time.Time values Params map[string]string // Connection parameters
MaxAllowedPacket int // Max packet size allowed ConnectionAttributes string // Connection Attributes, comma-delimited string of user-defined "key:value" pairs
ServerPubKey string // Server public key name Collation string // Connection collation. When set, this will be set in SET NAMES <charset> COLLATE <collation> query
pubKey *rsa.PublicKey // Server public key Loc *time.Location // Location for time.Time values
TLSConfig string // TLS configuration name MaxAllowedPacket int // Max packet size allowed
TLS *tls.Config // TLS configuration, its priority is higher than TLSConfig ServerPubKey string // Server public key name
Timeout time.Duration // Dial timeout TLSConfig string // TLS configuration name
ReadTimeout time.Duration // I/O read timeout TLS *tls.Config // TLS configuration, its priority is higher than TLSConfig
WriteTimeout time.Duration // I/O write timeout Timeout time.Duration // Dial timeout
ReadTimeout time.Duration // I/O read timeout
WriteTimeout time.Duration // I/O write timeout
Logger Logger // Logger
// DialFunc specifies the dial function for creating connections
DialFunc func(ctx context.Context, network, addr string) (net.Conn, error)
// boolean fields
AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE
AllowCleartextPasswords bool // Allows the cleartext client side plugin AllowCleartextPasswords bool // Allows the cleartext client side plugin
@ -63,17 +71,83 @@ type Config struct {
MultiStatements bool // Allow multiple statements in one query MultiStatements bool // Allow multiple statements in one query
ParseTime bool // Parse time values to time.Time ParseTime bool // Parse time values to time.Time
RejectReadOnly bool // Reject read-only connections RejectReadOnly bool // Reject read-only connections
// unexported fields. new options should be come here.
// boolean first. alphabetical order.
compress bool // Enable zlib compression
beforeConnect func(context.Context, *Config) error // Invoked before a connection is established
pubKey *rsa.PublicKey // Server public key
timeTruncate time.Duration // Truncate time.Time values to the specified duration
charsets []string // Connection charset. When set, this will be set in SET NAMES <charset> query
} }
// Functional Options Pattern
// https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
type Option func(*Config) error
// NewConfig creates a new Config and sets default values. // NewConfig creates a new Config and sets default values.
func NewConfig() *Config { func NewConfig() *Config {
return &Config{ cfg := &Config{
Collation: defaultCollation,
Loc: time.UTC, Loc: time.UTC,
MaxAllowedPacket: defaultMaxAllowedPacket, MaxAllowedPacket: defaultMaxAllowedPacket,
Logger: defaultLogger,
AllowNativePasswords: true, AllowNativePasswords: true,
CheckConnLiveness: true, CheckConnLiveness: true,
} }
return cfg
}
// Apply applies the given options to the Config object.
func (c *Config) Apply(opts ...Option) error {
for _, opt := range opts {
err := opt(c)
if err != nil {
return err
}
}
return nil
}
// TimeTruncate sets the time duration to truncate time.Time values in
// query parameters.
func TimeTruncate(d time.Duration) Option {
return func(cfg *Config) error {
cfg.timeTruncate = d
return nil
}
}
// BeforeConnect sets the function to be invoked before a connection is established.
func BeforeConnect(fn func(context.Context, *Config) error) Option {
return func(cfg *Config) error {
cfg.beforeConnect = fn
return nil
}
}
// EnableCompress sets the compression mode.
func EnableCompression(yes bool) Option {
return func(cfg *Config) error {
cfg.compress = yes
return nil
}
}
// Charset sets the connection charset and collation.
//
// charset is the connection charset.
// collation is the connection collation. It can be null or empty string.
//
// When collation is not specified, `SET NAMES <charset>` command is sent when the connection is established.
// When collation is specified, `SET NAMES <charset> COLLATE <collation>` command is sent when the connection is established.
func Charset(charset, collation string) Option {
return func(cfg *Config) error {
cfg.charsets = []string{charset}
cfg.Collation = collation
return nil
}
} }
func (cfg *Config) Clone() *Config { func (cfg *Config) Clone() *Config {
@ -97,7 +171,7 @@ func (cfg *Config) Clone() *Config {
} }
func (cfg *Config) normalize() error { func (cfg *Config) normalize() error {
if cfg.InterpolateParams && unsafeCollations[cfg.Collation] { if cfg.InterpolateParams && cfg.Collation != "" && unsafeCollations[cfg.Collation] {
return errInvalidDSNUnsafeCollation return errInvalidDSNUnsafeCollation
} }
@ -153,6 +227,10 @@ func (cfg *Config) normalize() error {
} }
} }
if cfg.Logger == nil {
cfg.Logger = defaultLogger
}
return nil return nil
} }
@ -171,6 +249,8 @@ func writeDSNParam(buf *bytes.Buffer, hasParam *bool, name, value string) {
// FormatDSN formats the given Config into a DSN string which can be passed to // FormatDSN formats the given Config into a DSN string which can be passed to
// the driver. // the driver.
//
// Note: use [NewConnector] and [database/sql.OpenDB] to open a connection from a [*Config].
func (cfg *Config) FormatDSN() string { func (cfg *Config) FormatDSN() string {
var buf bytes.Buffer var buf bytes.Buffer
@ -196,7 +276,7 @@ func (cfg *Config) FormatDSN() string {
// /dbname // /dbname
buf.WriteByte('/') buf.WriteByte('/')
buf.WriteString(cfg.DBName) buf.WriteString(url.PathEscape(cfg.DBName))
// [?param1=value1&...&paramN=valueN] // [?param1=value1&...&paramN=valueN]
hasParam := false hasParam := false
@ -230,7 +310,11 @@ func (cfg *Config) FormatDSN() string {
writeDSNParam(&buf, &hasParam, "clientFoundRows", "true") writeDSNParam(&buf, &hasParam, "clientFoundRows", "true")
} }
if col := cfg.Collation; col != defaultCollation && len(col) > 0 { if charsets := cfg.charsets; len(charsets) > 0 {
writeDSNParam(&buf, &hasParam, "charset", strings.Join(charsets, ","))
}
if col := cfg.Collation; col != "" {
writeDSNParam(&buf, &hasParam, "collation", col) writeDSNParam(&buf, &hasParam, "collation", col)
} }
@ -238,6 +322,14 @@ func (cfg *Config) FormatDSN() string {
writeDSNParam(&buf, &hasParam, "columnsWithAlias", "true") writeDSNParam(&buf, &hasParam, "columnsWithAlias", "true")
} }
if cfg.ConnectionAttributes != "" {
writeDSNParam(&buf, &hasParam, "connectionAttributes", url.QueryEscape(cfg.ConnectionAttributes))
}
if cfg.compress {
writeDSNParam(&buf, &hasParam, "compress", "true")
}
if cfg.InterpolateParams { if cfg.InterpolateParams {
writeDSNParam(&buf, &hasParam, "interpolateParams", "true") writeDSNParam(&buf, &hasParam, "interpolateParams", "true")
} }
@ -254,6 +346,10 @@ func (cfg *Config) FormatDSN() string {
writeDSNParam(&buf, &hasParam, "parseTime", "true") writeDSNParam(&buf, &hasParam, "parseTime", "true")
} }
if cfg.timeTruncate > 0 {
writeDSNParam(&buf, &hasParam, "timeTruncate", cfg.timeTruncate.String())
}
if cfg.ReadTimeout > 0 { if cfg.ReadTimeout > 0 {
writeDSNParam(&buf, &hasParam, "readTimeout", cfg.ReadTimeout.String()) writeDSNParam(&buf, &hasParam, "readTimeout", cfg.ReadTimeout.String())
} }
@ -358,7 +454,11 @@ func ParseDSN(dsn string) (cfg *Config, err error) {
break break
} }
} }
cfg.DBName = dsn[i+1 : j]
dbname := dsn[i+1 : j]
if cfg.DBName, err = url.PathUnescape(dbname); err != nil {
return nil, fmt.Errorf("invalid dbname %q: %w", dbname, err)
}
break break
} }
@ -378,13 +478,13 @@ func ParseDSN(dsn string) (cfg *Config, err error) {
// Values must be url.QueryEscape'ed // Values must be url.QueryEscape'ed
func parseDSNParams(cfg *Config, params string) (err error) { func parseDSNParams(cfg *Config, params string) (err error) {
for _, v := range strings.Split(params, "&") { for _, v := range strings.Split(params, "&") {
param := strings.SplitN(v, "=", 2) key, value, found := strings.Cut(v, "=")
if len(param) != 2 { if !found {
continue continue
} }
// cfg params // cfg params
switch value := param[1]; param[0] { switch key {
// Disable INFILE allowlist / enable all files // Disable INFILE allowlist / enable all files
case "allowAllFiles": case "allowAllFiles":
var isBool bool var isBool bool
@ -441,6 +541,10 @@ func parseDSNParams(cfg *Config, params string) (err error) {
return errors.New("invalid bool value: " + value) return errors.New("invalid bool value: " + value)
} }
// charset
case "charset":
cfg.charsets = strings.Split(value, ",")
// Collation // Collation
case "collation": case "collation":
cfg.Collation = value cfg.Collation = value
@ -454,7 +558,11 @@ func parseDSNParams(cfg *Config, params string) (err error) {
// Compression // Compression
case "compress": case "compress":
return errors.New("compression not implemented yet") var isBool bool
cfg.compress, isBool = readBool(value)
if !isBool {
return errors.New("invalid bool value: " + value)
}
// Enable client side placeholder substitution // Enable client side placeholder substitution
case "interpolateParams": case "interpolateParams":
@ -490,6 +598,13 @@ func parseDSNParams(cfg *Config, params string) (err error) {
return errors.New("invalid bool value: " + value) return errors.New("invalid bool value: " + value)
} }
// time.Time truncation
case "timeTruncate":
cfg.timeTruncate, err = time.ParseDuration(value)
if err != nil {
return fmt.Errorf("invalid timeTruncate value: %v, error: %w", value, err)
}
// I/O read Timeout // I/O read Timeout
case "readTimeout": case "readTimeout":
cfg.ReadTimeout, err = time.ParseDuration(value) cfg.ReadTimeout, err = time.ParseDuration(value)
@ -554,13 +669,22 @@ func parseDSNParams(cfg *Config, params string) (err error) {
if err != nil { if err != nil {
return return
} }
// Connection attributes
case "connectionAttributes":
connectionAttributes, err := url.QueryUnescape(value)
if err != nil {
return fmt.Errorf("invalid connectionAttributes value: %v", err)
}
cfg.ConnectionAttributes = connectionAttributes
default: default:
// lazy init // lazy init
if cfg.Params == nil { if cfg.Params == nil {
cfg.Params = make(map[string]string) cfg.Params = make(map[string]string)
} }
if cfg.Params[param[0]], err = url.QueryUnescape(value); err != nil { if cfg.Params[key], err = url.QueryUnescape(value); err != nil {
return return
} }
} }

View File

@ -21,36 +21,42 @@ var (
ErrMalformPkt = errors.New("malformed packet") ErrMalformPkt = errors.New("malformed packet")
ErrNoTLS = errors.New("TLS requested but server does not support TLS") ErrNoTLS = errors.New("TLS requested but server does not support TLS")
ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN") ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN")
ErrNativePassword = errors.New("this user requires mysql native password authentication.") ErrNativePassword = errors.New("this user requires mysql native password authentication")
ErrOldPassword = errors.New("this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords") ErrOldPassword = errors.New("this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords")
ErrUnknownPlugin = errors.New("this authentication plugin is not supported") ErrUnknownPlugin = errors.New("this authentication plugin is not supported")
ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+") ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+")
ErrPktSync = errors.New("commands out of sync. You can't run this command now") ErrPktSync = errors.New("commands out of sync. You can't run this command now")
ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?") ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?")
ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server") ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the `Config.MaxAllowedPacket`")
ErrBusyBuffer = errors.New("busy buffer") ErrBusyBuffer = errors.New("busy buffer")
// errBadConnNoWrite is used for connection errors where nothing was sent to the database yet. // errBadConnNoWrite is used for connection errors where nothing was sent to the database yet.
// If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn // If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn
// to trigger a resend. // to trigger a resend. Use mc.markBadConn(err) to do this.
// See https://github.com/go-sql-driver/mysql/pull/302 // See https://github.com/go-sql-driver/mysql/pull/302
errBadConnNoWrite = errors.New("bad connection") errBadConnNoWrite = errors.New("bad connection")
) )
var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile)) var defaultLogger = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime))
// Logger is used to log critical error messages. // Logger is used to log critical error messages.
type Logger interface { type Logger interface {
Print(v ...interface{}) Print(v ...any)
} }
// SetLogger is used to set the logger for critical errors. // NopLogger is a nop implementation of the Logger interface.
type NopLogger struct{}
// Print implements Logger interface.
func (nl *NopLogger) Print(_ ...any) {}
// SetLogger is used to set the default logger for critical errors.
// The initial logger is os.Stderr. // The initial logger is os.Stderr.
func SetLogger(logger Logger) error { func SetLogger(logger Logger) error {
if logger == nil { if logger == nil {
return errors.New("logger is nil") return errors.New("logger is nil")
} }
errLog = logger defaultLogger = logger
return nil return nil
} }

View File

@ -18,7 +18,7 @@ func (mf *mysqlField) typeDatabaseName() string {
case fieldTypeBit: case fieldTypeBit:
return "BIT" return "BIT"
case fieldTypeBLOB: case fieldTypeBLOB:
if mf.charSet != collations[binaryCollation] { if mf.charSet != binaryCollationID {
return "TEXT" return "TEXT"
} }
return "BLOB" return "BLOB"
@ -37,6 +37,9 @@ func (mf *mysqlField) typeDatabaseName() string {
case fieldTypeGeometry: case fieldTypeGeometry:
return "GEOMETRY" return "GEOMETRY"
case fieldTypeInt24: case fieldTypeInt24:
if mf.flags&flagUnsigned != 0 {
return "UNSIGNED MEDIUMINT"
}
return "MEDIUMINT" return "MEDIUMINT"
case fieldTypeJSON: case fieldTypeJSON:
return "JSON" return "JSON"
@ -46,7 +49,7 @@ func (mf *mysqlField) typeDatabaseName() string {
} }
return "INT" return "INT"
case fieldTypeLongBLOB: case fieldTypeLongBLOB:
if mf.charSet != collations[binaryCollation] { if mf.charSet != binaryCollationID {
return "LONGTEXT" return "LONGTEXT"
} }
return "LONGBLOB" return "LONGBLOB"
@ -56,7 +59,7 @@ func (mf *mysqlField) typeDatabaseName() string {
} }
return "BIGINT" return "BIGINT"
case fieldTypeMediumBLOB: case fieldTypeMediumBLOB:
if mf.charSet != collations[binaryCollation] { if mf.charSet != binaryCollationID {
return "MEDIUMTEXT" return "MEDIUMTEXT"
} }
return "MEDIUMBLOB" return "MEDIUMBLOB"
@ -74,7 +77,12 @@ func (mf *mysqlField) typeDatabaseName() string {
} }
return "SMALLINT" return "SMALLINT"
case fieldTypeString: case fieldTypeString:
if mf.charSet == collations[binaryCollation] { if mf.flags&flagEnum != 0 {
return "ENUM"
} else if mf.flags&flagSet != 0 {
return "SET"
}
if mf.charSet == binaryCollationID {
return "BINARY" return "BINARY"
} }
return "CHAR" return "CHAR"
@ -88,43 +96,47 @@ func (mf *mysqlField) typeDatabaseName() string {
} }
return "TINYINT" return "TINYINT"
case fieldTypeTinyBLOB: case fieldTypeTinyBLOB:
if mf.charSet != collations[binaryCollation] { if mf.charSet != binaryCollationID {
return "TINYTEXT" return "TINYTEXT"
} }
return "TINYBLOB" return "TINYBLOB"
case fieldTypeVarChar: case fieldTypeVarChar:
if mf.charSet == collations[binaryCollation] { if mf.charSet == binaryCollationID {
return "VARBINARY" return "VARBINARY"
} }
return "VARCHAR" return "VARCHAR"
case fieldTypeVarString: case fieldTypeVarString:
if mf.charSet == collations[binaryCollation] { if mf.charSet == binaryCollationID {
return "VARBINARY" return "VARBINARY"
} }
return "VARCHAR" return "VARCHAR"
case fieldTypeYear: case fieldTypeYear:
return "YEAR" return "YEAR"
case fieldTypeVector:
return "VECTOR"
default: default:
return "" return ""
} }
} }
var ( var (
scanTypeFloat32 = reflect.TypeOf(float32(0)) scanTypeFloat32 = reflect.TypeOf(float32(0))
scanTypeFloat64 = reflect.TypeOf(float64(0)) scanTypeFloat64 = reflect.TypeOf(float64(0))
scanTypeInt8 = reflect.TypeOf(int8(0)) scanTypeInt8 = reflect.TypeOf(int8(0))
scanTypeInt16 = reflect.TypeOf(int16(0)) scanTypeInt16 = reflect.TypeOf(int16(0))
scanTypeInt32 = reflect.TypeOf(int32(0)) scanTypeInt32 = reflect.TypeOf(int32(0))
scanTypeInt64 = reflect.TypeOf(int64(0)) scanTypeInt64 = reflect.TypeOf(int64(0))
scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) scanTypeNullInt = reflect.TypeOf(sql.NullInt64{})
scanTypeNullTime = reflect.TypeOf(sql.NullTime{}) scanTypeNullTime = reflect.TypeOf(sql.NullTime{})
scanTypeUint8 = reflect.TypeOf(uint8(0)) scanTypeUint8 = reflect.TypeOf(uint8(0))
scanTypeUint16 = reflect.TypeOf(uint16(0)) scanTypeUint16 = reflect.TypeOf(uint16(0))
scanTypeUint32 = reflect.TypeOf(uint32(0)) scanTypeUint32 = reflect.TypeOf(uint32(0))
scanTypeUint64 = reflect.TypeOf(uint64(0)) scanTypeUint64 = reflect.TypeOf(uint64(0))
scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) scanTypeString = reflect.TypeOf("")
scanTypeUnknown = reflect.TypeOf(new(interface{})) scanTypeNullString = reflect.TypeOf(sql.NullString{})
scanTypeBytes = reflect.TypeOf([]byte{})
scanTypeUnknown = reflect.TypeOf(new(any))
) )
type mysqlField struct { type mysqlField struct {
@ -187,12 +199,18 @@ func (mf *mysqlField) scanType() reflect.Type {
} }
return scanTypeNullFloat return scanTypeNullFloat
case fieldTypeBit, fieldTypeTinyBLOB, fieldTypeMediumBLOB, fieldTypeLongBLOB,
fieldTypeBLOB, fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeVector:
if mf.charSet == binaryCollationID {
return scanTypeBytes
}
fallthrough
case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar,
fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, fieldTypeEnum, fieldTypeSet, fieldTypeJSON, fieldTypeTime:
fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, if mf.flags&flagNotNULL != 0 {
fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON, return scanTypeString
fieldTypeTime: }
return scanTypeRawBytes return scanTypeNullString
case fieldTypeDate, fieldTypeNewDate, case fieldTypeDate, fieldTypeNewDate,
fieldTypeTimestamp, fieldTypeDateTime: fieldTypeTimestamp, fieldTypeDateTime:

View File

@ -1,25 +0,0 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package.
//
// Copyright 2020 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build gofuzz
// +build gofuzz
package mysql
import (
"database/sql"
)
func Fuzz(data []byte) int {
db, err := sql.Open("mysql", string(data))
if err != nil {
return 0
}
db.Close()
return 1
}

View File

@ -17,7 +17,7 @@ import (
) )
var ( var (
fileRegister map[string]bool fileRegister map[string]struct{}
fileRegisterLock sync.RWMutex fileRegisterLock sync.RWMutex
readerRegister map[string]func() io.Reader readerRegister map[string]func() io.Reader
readerRegisterLock sync.RWMutex readerRegisterLock sync.RWMutex
@ -37,10 +37,10 @@ func RegisterLocalFile(filePath string) {
fileRegisterLock.Lock() fileRegisterLock.Lock()
// lazy map init // lazy map init
if fileRegister == nil { if fileRegister == nil {
fileRegister = make(map[string]bool) fileRegister = make(map[string]struct{})
} }
fileRegister[strings.Trim(filePath, `"`)] = true fileRegister[strings.Trim(filePath, `"`)] = struct{}{}
fileRegisterLock.Unlock() fileRegisterLock.Unlock()
} }
@ -93,9 +93,8 @@ func deferredClose(err *error, closer io.Closer) {
const defaultPacketSize = 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP const defaultPacketSize = 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP
func (mc *mysqlConn) handleInFileRequest(name string) (err error) { func (mc *okHandler) handleInFileRequest(name string) (err error) {
var rdr io.Reader var rdr io.Reader
var data []byte
packetSize := defaultPacketSize packetSize := defaultPacketSize
if mc.maxWriteSize < packetSize { if mc.maxWriteSize < packetSize {
packetSize = mc.maxWriteSize packetSize = mc.maxWriteSize
@ -116,17 +115,17 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
defer deferredClose(&err, cl) defer deferredClose(&err, cl)
} }
} else { } else {
err = fmt.Errorf("Reader '%s' is <nil>", name) err = fmt.Errorf("reader '%s' is <nil>", name)
} }
} else { } else {
err = fmt.Errorf("Reader '%s' is not registered", name) err = fmt.Errorf("reader '%s' is not registered", name)
} }
} else { // File } else { // File
name = strings.Trim(name, `"`) name = strings.Trim(name, `"`)
fileRegisterLock.RLock() fileRegisterLock.RLock()
fr := fileRegister[name] _, exists := fileRegister[name]
fileRegisterLock.RUnlock() fileRegisterLock.RUnlock()
if mc.cfg.AllowAllFiles || fr { if mc.cfg.AllowAllFiles || exists {
var file *os.File var file *os.File
var fi os.FileInfo var fi os.FileInfo
@ -147,14 +146,16 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
} }
// send content packets // send content packets
var data []byte
// if packetSize == 0, the Reader contains no data // if packetSize == 0, the Reader contains no data
if err == nil && packetSize > 0 { if err == nil && packetSize > 0 {
data := make([]byte, 4+packetSize) data = make([]byte, 4+packetSize)
var n int var n int
for err == nil { for err == nil {
n, err = rdr.Read(data[4:]) n, err = rdr.Read(data[4:])
if n > 0 { if n > 0 {
if ioErr := mc.writePacket(data[:4+n]); ioErr != nil { if ioErr := mc.conn().writePacket(data[:4+n]); ioErr != nil {
return ioErr return ioErr
} }
} }
@ -168,15 +169,16 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
if data == nil { if data == nil {
data = make([]byte, 4) data = make([]byte, 4)
} }
if ioErr := mc.writePacket(data[:4]); ioErr != nil { if ioErr := mc.conn().writePacket(data[:4]); ioErr != nil {
return ioErr return ioErr
} }
mc.conn().syncSequence()
// read OK packet // read OK packet
if err == nil { if err == nil {
return mc.readResultOK() return mc.readResultOK()
} }
mc.readPacket() mc.conn().readPacket()
return err return err
} }

View File

@ -38,7 +38,7 @@ type NullTime sql.NullTime
// Scan implements the Scanner interface. // Scan implements the Scanner interface.
// The value type must be time.Time or string / []byte (formatted time-string), // The value type must be time.Time or string / []byte (formatted time-string),
// otherwise Scan fails. // otherwise Scan fails.
func (nt *NullTime) Scan(value interface{}) (err error) { func (nt *NullTime) Scan(value any) (err error) {
if value == nil { if value == nil {
nt.Time, nt.Valid = time.Time{}, false nt.Time, nt.Valid = time.Time{}, false
return return
@ -59,7 +59,7 @@ func (nt *NullTime) Scan(value interface{}) (err error) {
} }
nt.Valid = false nt.Valid = false
return fmt.Errorf("Can't convert %T to time.Time", value) return fmt.Errorf("can't convert %T to time.Time", value)
} }
// Value implements the driver Valuer interface. // Value implements the driver Valuer interface.

View File

@ -14,75 +14,108 @@ import (
"database/sql/driver" "database/sql/driver"
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"math" "math"
"os"
"strconv"
"time" "time"
) )
// Packets documentation: // MySQL client/server protocol documentations.
// http://dev.mysql.com/doc/internals/en/client-server-protocol.html // https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_PROTOCOL.html
// https://mariadb.com/kb/en/clientserver-protocol/
// read n bytes from mc.buf
func (mc *mysqlConn) readNext(n int) ([]byte, error) {
if mc.buf.len() < n {
err := mc.buf.fill(n, mc.readWithTimeout)
if err != nil {
return nil, err
}
}
return mc.buf.readNext(n), nil
}
// Read packet to buffer 'data' // Read packet to buffer 'data'
func (mc *mysqlConn) readPacket() ([]byte, error) { func (mc *mysqlConn) readPacket() ([]byte, error) {
var prevData []byte var prevData []byte
invalidSequence := false
readNext := mc.readNext
if mc.compress {
readNext = mc.compIO.readNext
}
for { for {
// read packet header // read packet header
data, err := mc.buf.readNext(4) data, err := readNext(4)
if err != nil { if err != nil {
mc.close()
if cerr := mc.canceled.Value(); cerr != nil { if cerr := mc.canceled.Value(); cerr != nil {
return nil, cerr return nil, cerr
} }
errLog.Print(err) mc.log(err)
mc.Close()
return nil, ErrInvalidConn return nil, ErrInvalidConn
} }
// packet length [24 bit] // packet length [24 bit]
pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16) pktLen := getUint24(data[:3])
seq := data[3]
// check packet sync [8 bit] // check packet sync [8 bit]
if data[3] != mc.sequence { if seq != mc.sequence {
if data[3] > mc.sequence { mc.log(fmt.Sprintf("[warn] unexpected sequence nr: expected %v, got %v", mc.sequence, seq))
return nil, ErrPktSyncMul // MySQL and MariaDB doesn't check packet nr in compressed packet.
if !mc.compress {
// For large packets, we stop reading as soon as sync error.
if len(prevData) > 0 {
mc.close()
return nil, ErrPktSyncMul
}
invalidSequence = true
} }
return nil, ErrPktSync
} }
mc.sequence++ mc.sequence = seq + 1
// packets with length 0 terminate a previous packet which is a // packets with length 0 terminate a previous packet which is a
// multiple of (2^24)-1 bytes long // multiple of (2^24)-1 bytes long
if pktLen == 0 { if pktLen == 0 {
// there was no previous packet // there was no previous packet
if prevData == nil { if prevData == nil {
errLog.Print(ErrMalformPkt) mc.log(ErrMalformPkt)
mc.Close() mc.close()
return nil, ErrInvalidConn return nil, ErrInvalidConn
} }
return prevData, nil return prevData, nil
} }
// read packet body [pktLen bytes] // read packet body [pktLen bytes]
data, err = mc.buf.readNext(pktLen) data, err = readNext(pktLen)
if err != nil { if err != nil {
mc.close()
if cerr := mc.canceled.Value(); cerr != nil { if cerr := mc.canceled.Value(); cerr != nil {
return nil, cerr return nil, cerr
} }
errLog.Print(err) mc.log(err)
mc.Close()
return nil, ErrInvalidConn return nil, ErrInvalidConn
} }
// return data if this was the last packet // return data if this was the last packet
if pktLen < maxPacketSize { if pktLen < maxPacketSize {
// zero allocations for non-split packets // zero allocations for non-split packets
if prevData == nil { if prevData != nil {
return data, nil data = append(prevData, data...)
} }
if invalidSequence {
return append(prevData, data...), nil mc.close()
// return sync error only for regular packet.
// error packets may have wrong sequence number.
if data[0] != iERR {
return nil, ErrPktSync
}
}
return data, nil
} }
prevData = append(prevData, data...) prevData = append(prevData, data...)
@ -92,88 +125,52 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
// Write packet buffer 'data' // Write packet buffer 'data'
func (mc *mysqlConn) writePacket(data []byte) error { func (mc *mysqlConn) writePacket(data []byte) error {
pktLen := len(data) - 4 pktLen := len(data) - 4
if pktLen > mc.maxAllowedPacket { if pktLen > mc.maxAllowedPacket {
return ErrPktTooLarge return ErrPktTooLarge
} }
// Perform a stale connection check. We only perform this check for writeFunc := mc.writeWithTimeout
// the first query on a connection that has been checked out of the if mc.compress {
// connection pool: a fresh connection from the pool is more likely writeFunc = mc.compIO.writePackets
// to be stale, and it has not performed any previous writes that
// could cause data corruption, so it's safe to return ErrBadConn
// if the check fails.
if mc.reset {
mc.reset = false
conn := mc.netConn
if mc.rawConn != nil {
conn = mc.rawConn
}
var err error
if mc.cfg.CheckConnLiveness {
if mc.cfg.ReadTimeout != 0 {
err = conn.SetReadDeadline(time.Now().Add(mc.cfg.ReadTimeout))
}
if err == nil {
err = connCheck(conn)
}
}
if err != nil {
errLog.Print("closing bad idle connection: ", err)
mc.Close()
return driver.ErrBadConn
}
} }
for { for {
var size int size := min(maxPacketSize, pktLen)
if pktLen >= maxPacketSize { putUint24(data[:3], size)
data[0] = 0xff
data[1] = 0xff
data[2] = 0xff
size = maxPacketSize
} else {
data[0] = byte(pktLen)
data[1] = byte(pktLen >> 8)
data[2] = byte(pktLen >> 16)
size = pktLen
}
data[3] = mc.sequence data[3] = mc.sequence
// Write packet // Write packet
if mc.writeTimeout > 0 { if debug {
if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil { fmt.Fprintf(os.Stderr, "writePacket: size=%v seq=%v\n", size, mc.sequence)
return err
}
} }
n, err := mc.netConn.Write(data[:4+size]) n, err := writeFunc(data[:4+size])
if err == nil && n == 4+size { if err != nil {
mc.sequence++
if size != maxPacketSize {
return nil
}
pktLen -= size
data = data[size:]
continue
}
// Handle error
if err == nil { // n != len(data)
mc.cleanup() mc.cleanup()
errLog.Print(ErrMalformPkt)
} else {
if cerr := mc.canceled.Value(); cerr != nil { if cerr := mc.canceled.Value(); cerr != nil {
return cerr return cerr
} }
if n == 0 && pktLen == len(data)-4 { if n == 0 && pktLen == len(data)-4 {
// only for the first loop iteration when nothing was written yet // only for the first loop iteration when nothing was written yet
mc.log(err)
return errBadConnNoWrite return errBadConnNoWrite
} else {
return err
} }
mc.cleanup()
errLog.Print(err)
} }
return ErrInvalidConn if n != 4+size {
// io.Writer(b) must return a non-nil error if it cannot write len(b) bytes.
// The io.ErrShortWrite error is used to indicate that this rule has not been followed.
mc.cleanup()
return io.ErrShortWrite
}
mc.sequence++
if size != maxPacketSize {
return nil
}
pktLen -= size
data = data[size:]
} }
} }
@ -186,11 +183,6 @@ func (mc *mysqlConn) writePacket(data []byte) error {
func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err error) { func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err error) {
data, err = mc.readPacket() data, err = mc.readPacket()
if err != nil { if err != nil {
// for init we can rewrite this to ErrBadConn for sql.Driver to retry, since
// in connection initialization we don't risk retrying non-idempotent actions.
if err == ErrInvalidConn {
return nil, "", driver.ErrBadConn
}
return return
} }
@ -234,12 +226,15 @@ func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err erro
if len(data) > pos { if len(data) > pos {
// character set [1 byte] // character set [1 byte]
// status flags [2 bytes] // status flags [2 bytes]
pos += 3
// capability flags (upper 2 bytes) [2 bytes] // capability flags (upper 2 bytes) [2 bytes]
mc.flags |= clientFlag(binary.LittleEndian.Uint16(data[pos:pos+2])) << 16
pos += 2
// length of auth-plugin-data [1 byte] // length of auth-plugin-data [1 byte]
// reserved (all [00]) [10 bytes] // reserved (all [00]) [10 bytes]
pos += 1 + 2 + 2 + 1 + 10 pos += 11
// second part of the password cipher [mininum 13 bytes], // second part of the password cipher [minimum 13 bytes],
// where len=MAX(13, length of auth-plugin-data - 8) // where len=MAX(13, length of auth-plugin-data - 8)
// //
// The web documentation is ambiguous about the length. However, // The web documentation is ambiguous about the length. However,
@ -285,12 +280,17 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
clientLocalFiles | clientLocalFiles |
clientPluginAuth | clientPluginAuth |
clientMultiResults | clientMultiResults |
mc.flags&clientConnectAttrs |
mc.flags&clientLongFlag mc.flags&clientLongFlag
sendConnectAttrs := mc.flags&clientConnectAttrs != 0
if mc.cfg.ClientFoundRows { if mc.cfg.ClientFoundRows {
clientFlags |= clientFoundRows clientFlags |= clientFoundRows
} }
if mc.cfg.compress && mc.flags&clientCompress == clientCompress {
clientFlags |= clientCompress
}
// To enable TLS / SSL // To enable TLS / SSL
if mc.cfg.TLS != nil { if mc.cfg.TLS != nil {
clientFlags |= clientSSL clientFlags |= clientSSL
@ -318,34 +318,38 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
pktLen += n + 1 pktLen += n + 1
} }
// encode length of the connection attributes
var connAttrsLEI []byte
if sendConnectAttrs {
var connAttrsLEIBuf [9]byte
connAttrsLen := len(mc.connector.encodedAttributes)
connAttrsLEI = appendLengthEncodedInteger(connAttrsLEIBuf[:0], uint64(connAttrsLen))
pktLen += len(connAttrsLEI) + len(mc.connector.encodedAttributes)
}
// Calculate packet length and get buffer with that size // Calculate packet length and get buffer with that size
data, err := mc.buf.takeSmallBuffer(pktLen + 4) data, err := mc.buf.takeBuffer(pktLen + 4)
if err != nil { if err != nil {
// cannot take the buffer. Something must be wrong with the connection mc.cleanup()
errLog.Print(err) return err
return errBadConnNoWrite
} }
// ClientFlags [32 bit] // ClientFlags [32 bit]
data[4] = byte(clientFlags) binary.LittleEndian.PutUint32(data[4:], uint32(clientFlags))
data[5] = byte(clientFlags >> 8)
data[6] = byte(clientFlags >> 16)
data[7] = byte(clientFlags >> 24)
// MaxPacketSize [32 bit] (none) // MaxPacketSize [32 bit] (none)
data[8] = 0x00 binary.LittleEndian.PutUint32(data[8:], 0)
data[9] = 0x00
data[10] = 0x00
data[11] = 0x00
// Charset [1 byte] // Collation ID [1 byte]
var found bool data[12] = defaultCollationID
data[12], found = collations[mc.cfg.Collation] if cname := mc.cfg.Collation; cname != "" {
if !found { colID, ok := collations[cname]
// Note possibility for false negatives: if ok {
// could be triggered although the collation is valid if the data[12] = colID
// collations map does not contain entries the server supports. } else if len(mc.cfg.charsets) > 0 {
return errors.New("unknown collation") // When cfg.charset is set, the collation is set by `SET NAMES <charset> COLLATE <collation>`.
return fmt.Errorf("unknown collation: %q", cname)
}
} }
// Filler [23 bytes] (all 0x00) // Filler [23 bytes] (all 0x00)
@ -365,11 +369,12 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
// Switch to TLS // Switch to TLS
tlsConn := tls.Client(mc.netConn, mc.cfg.TLS) tlsConn := tls.Client(mc.netConn, mc.cfg.TLS)
if err := tlsConn.Handshake(); err != nil { if err := tlsConn.Handshake(); err != nil {
if cerr := mc.canceled.Value(); cerr != nil {
return cerr
}
return err return err
} }
mc.rawConn = mc.netConn
mc.netConn = tlsConn mc.netConn = tlsConn
mc.buf.nc = tlsConn
} }
// User [null terminated string] // User [null terminated string]
@ -394,6 +399,12 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
data[pos] = 0x00 data[pos] = 0x00
pos++ pos++
// Connection Attributes
if sendConnectAttrs {
pos += copy(data[pos:], connAttrsLEI)
pos += copy(data[pos:], []byte(mc.connector.encodedAttributes))
}
// Send Auth packet // Send Auth packet
return mc.writePacket(data[:pos]) return mc.writePacket(data[:pos])
} }
@ -401,11 +412,10 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error { func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error {
pktLen := 4 + len(authData) pktLen := 4 + len(authData)
data, err := mc.buf.takeSmallBuffer(pktLen) data, err := mc.buf.takeBuffer(pktLen)
if err != nil { if err != nil {
// cannot take the buffer. Something must be wrong with the connection mc.cleanup()
errLog.Print(err) return err
return errBadConnNoWrite
} }
// Add the auth data [EOF] // Add the auth data [EOF]
@ -419,32 +429,30 @@ func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error {
func (mc *mysqlConn) writeCommandPacket(command byte) error { func (mc *mysqlConn) writeCommandPacket(command byte) error {
// Reset Packet Sequence // Reset Packet Sequence
mc.sequence = 0 mc.resetSequence()
data, err := mc.buf.takeSmallBuffer(4 + 1) data, err := mc.buf.takeSmallBuffer(4 + 1)
if err != nil { if err != nil {
// cannot take the buffer. Something must be wrong with the connection return err
errLog.Print(err)
return errBadConnNoWrite
} }
// Add command byte // Add command byte
data[4] = command data[4] = command
// Send CMD packet // Send CMD packet
return mc.writePacket(data) err = mc.writePacket(data)
mc.syncSequence()
return err
} }
func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error { func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
// Reset Packet Sequence // Reset Packet Sequence
mc.sequence = 0 mc.resetSequence()
pktLen := 1 + len(arg) pktLen := 1 + len(arg)
data, err := mc.buf.takeBuffer(pktLen + 4) data, err := mc.buf.takeBuffer(pktLen + 4)
if err != nil { if err != nil {
// cannot take the buffer. Something must be wrong with the connection return err
errLog.Print(err)
return errBadConnNoWrite
} }
// Add command byte // Add command byte
@ -454,31 +462,30 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
copy(data[5:], arg) copy(data[5:], arg)
// Send CMD packet // Send CMD packet
return mc.writePacket(data) err = mc.writePacket(data)
mc.syncSequence()
return err
} }
func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error { func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
// Reset Packet Sequence // Reset Packet Sequence
mc.sequence = 0 mc.resetSequence()
data, err := mc.buf.takeSmallBuffer(4 + 1 + 4) data, err := mc.buf.takeSmallBuffer(4 + 1 + 4)
if err != nil { if err != nil {
// cannot take the buffer. Something must be wrong with the connection return err
errLog.Print(err)
return errBadConnNoWrite
} }
// Add command byte // Add command byte
data[4] = command data[4] = command
// Add arg [32 bit] // Add arg [32 bit]
data[5] = byte(arg) binary.LittleEndian.PutUint32(data[5:], arg)
data[6] = byte(arg >> 8)
data[7] = byte(arg >> 16)
data[8] = byte(arg >> 24)
// Send CMD packet // Send CMD packet
return mc.writePacket(data) err = mc.writePacket(data)
mc.syncSequence()
return err
} }
/****************************************************************************** /******************************************************************************
@ -495,7 +502,9 @@ func (mc *mysqlConn) readAuthResult() ([]byte, string, error) {
switch data[0] { switch data[0] {
case iOK: case iOK:
return nil, "", mc.handleOkPacket(data) // resultUnchanged, since auth happens before any queries or
// commands have been executed.
return nil, "", mc.resultUnchanged().handleOkPacket(data)
case iAuthMoreData: case iAuthMoreData:
return data[1:], "", err return data[1:], "", err
@ -511,6 +520,9 @@ func (mc *mysqlConn) readAuthResult() ([]byte, string, error) {
} }
plugin := string(data[1:pluginEndIndex]) plugin := string(data[1:pluginEndIndex])
authData := data[pluginEndIndex+1:] authData := data[pluginEndIndex+1:]
if len(authData) > 0 && authData[len(authData)-1] == 0 {
authData = authData[:len(authData)-1]
}
return authData, plugin, nil return authData, plugin, nil
default: // Error otherwise default: // Error otherwise
@ -518,9 +530,9 @@ func (mc *mysqlConn) readAuthResult() ([]byte, string, error) {
} }
} }
// Returns error if Packet is not an 'Result OK'-Packet // Returns error if Packet is not a 'Result OK'-Packet
func (mc *mysqlConn) readResultOK() error { func (mc *okHandler) readResultOK() error {
data, err := mc.readPacket() data, err := mc.conn().readPacket()
if err != nil { if err != nil {
return err return err
} }
@ -528,35 +540,37 @@ func (mc *mysqlConn) readResultOK() error {
if data[0] == iOK { if data[0] == iOK {
return mc.handleOkPacket(data) return mc.handleOkPacket(data)
} }
return mc.handleErrorPacket(data) return mc.conn().handleErrorPacket(data)
} }
// Result Set Header Packet // Result Set Header Packet
// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::Resultset // https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response.html
func (mc *mysqlConn) readResultSetHeaderPacket() (int, error) { func (mc *okHandler) readResultSetHeaderPacket() (int, error) {
data, err := mc.readPacket() // handleOkPacket replaces both values; other cases leave the values unchanged.
if err == nil { mc.result.affectedRows = append(mc.result.affectedRows, 0)
switch data[0] { mc.result.insertIds = append(mc.result.insertIds, 0)
case iOK: data, err := mc.conn().readPacket()
return 0, mc.handleOkPacket(data) if err != nil {
return 0, err
case iERR:
return 0, mc.handleErrorPacket(data)
case iLocalInFile:
return 0, mc.handleInFileRequest(string(data[1:]))
}
// column count
num, _, n := readLengthEncodedInteger(data)
if n-len(data) == 0 {
return int(num), nil
}
return 0, ErrMalformPkt
} }
return 0, err
switch data[0] {
case iOK:
return 0, mc.handleOkPacket(data)
case iERR:
return 0, mc.conn().handleErrorPacket(data)
case iLocalInFile:
return 0, mc.handleInFileRequest(string(data[1:]))
}
// column count
// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_text_resultset.html
num, _, _ := readLengthEncodedInteger(data)
// ignore remaining data in the packet. see #1478.
return int(num), nil
} }
// Error Packet // Error Packet
@ -573,7 +587,8 @@ func (mc *mysqlConn) handleErrorPacket(data []byte) error {
// 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION // 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
// 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover) // 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover)
if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly { // 1836: ER_READ_ONLY_MODE
if (errno == 1792 || errno == 1290 || errno == 1836) && mc.cfg.RejectReadOnly {
// Oops; we are connected to a read-only connection, and won't be able // Oops; we are connected to a read-only connection, and won't be able
// to issue any write statements. Since RejectReadOnly is configured, // to issue any write statements. Since RejectReadOnly is configured,
// we throw away this connection hoping this one would have write // we throw away this connection hoping this one would have write
@ -607,18 +622,61 @@ func readStatus(b []byte) statusFlag {
return statusFlag(b[0]) | statusFlag(b[1])<<8 return statusFlag(b[0]) | statusFlag(b[1])<<8
} }
// Returns an instance of okHandler for codepaths where mysqlConn.result doesn't
// need to be cleared first (e.g. during authentication, or while additional
// resultsets are being fetched.)
func (mc *mysqlConn) resultUnchanged() *okHandler {
return (*okHandler)(mc)
}
// okHandler represents the state of the connection when mysqlConn.result has
// been prepared for processing of OK packets.
//
// To correctly populate mysqlConn.result (updated by handleOkPacket()), all
// callpaths must either:
//
// 1. first clear it using clearResult(), or
// 2. confirm that they don't need to (by calling resultUnchanged()).
//
// Both return an instance of type *okHandler.
type okHandler mysqlConn
// Exposes the underlying type's methods.
func (mc *okHandler) conn() *mysqlConn {
return (*mysqlConn)(mc)
}
// clearResult clears the connection's stored affectedRows and insertIds
// fields.
//
// It returns a handler that can process OK responses.
func (mc *mysqlConn) clearResult() *okHandler {
mc.result = mysqlResult{}
return (*okHandler)(mc)
}
// Ok Packet // Ok Packet
// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet // http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet
func (mc *mysqlConn) handleOkPacket(data []byte) error { func (mc *okHandler) handleOkPacket(data []byte) error {
var n, m int var n, m int
var affectedRows, insertId uint64
// 0x00 [1 byte] // 0x00 [1 byte]
// Affected rows [Length Coded Binary] // Affected rows [Length Coded Binary]
mc.affectedRows, _, n = readLengthEncodedInteger(data[1:]) affectedRows, _, n = readLengthEncodedInteger(data[1:])
// Insert id [Length Coded Binary] // Insert id [Length Coded Binary]
mc.insertId, _, m = readLengthEncodedInteger(data[1+n:]) insertId, _, m = readLengthEncodedInteger(data[1+n:])
// Update for the current statement result (only used by
// readResultSetHeaderPacket).
if len(mc.result.affectedRows) > 0 {
mc.result.affectedRows[len(mc.result.affectedRows)-1] = int64(affectedRows)
}
if len(mc.result.insertIds) > 0 {
mc.result.insertIds[len(mc.result.insertIds)-1] = int64(insertId)
}
// server_status [2 bytes] // server_status [2 bytes]
mc.status = readStatus(data[1+n+m : 1+n+m+2]) mc.status = readStatus(data[1+n+m : 1+n+m+2])
@ -769,7 +827,8 @@ func (rows *textRows) readRow(dest []driver.Value) error {
for i := range dest { for i := range dest {
// Read bytes and convert to string // Read bytes and convert to string
dest[i], isNull, n, err = readLengthEncodedString(data[pos:]) var buf []byte
buf, isNull, n, err = readLengthEncodedString(data[pos:])
pos += n pos += n
if err != nil { if err != nil {
@ -781,19 +840,40 @@ func (rows *textRows) readRow(dest []driver.Value) error {
continue continue
} }
if !mc.parseTime {
continue
}
// Parse time field
switch rows.rs.columns[i].fieldType { switch rows.rs.columns[i].fieldType {
case fieldTypeTimestamp, case fieldTypeTimestamp,
fieldTypeDateTime, fieldTypeDateTime,
fieldTypeDate, fieldTypeDate,
fieldTypeNewDate: fieldTypeNewDate:
if dest[i], err = parseDateTime(dest[i].([]byte), mc.cfg.Loc); err != nil { if mc.parseTime {
return err dest[i], err = parseDateTime(buf, mc.cfg.Loc)
} else {
dest[i] = buf
} }
case fieldTypeTiny, fieldTypeShort, fieldTypeInt24, fieldTypeYear, fieldTypeLong:
dest[i], err = strconv.ParseInt(string(buf), 10, 64)
case fieldTypeLongLong:
if rows.rs.columns[i].flags&flagUnsigned != 0 {
dest[i], err = strconv.ParseUint(string(buf), 10, 64)
} else {
dest[i], err = strconv.ParseInt(string(buf), 10, 64)
}
case fieldTypeFloat:
var d float64
d, err = strconv.ParseFloat(string(buf), 32)
dest[i] = float32(d)
case fieldTypeDouble:
dest[i], err = strconv.ParseFloat(string(buf), 64)
default:
dest[i] = buf
}
if err != nil {
return err
} }
} }
@ -875,32 +955,26 @@ func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
pktLen = dataOffset + argLen pktLen = dataOffset + argLen
} }
stmt.mc.sequence = 0
// Add command byte [1 byte] // Add command byte [1 byte]
data[4] = comStmtSendLongData data[4] = comStmtSendLongData
// Add stmtID [32 bit] // Add stmtID [32 bit]
data[5] = byte(stmt.id) binary.LittleEndian.PutUint32(data[5:], stmt.id)
data[6] = byte(stmt.id >> 8)
data[7] = byte(stmt.id >> 16)
data[8] = byte(stmt.id >> 24)
// Add paramID [16 bit] // Add paramID [16 bit]
data[9] = byte(paramID) binary.LittleEndian.PutUint16(data[9:], uint16(paramID))
data[10] = byte(paramID >> 8)
// Send CMD packet // Send CMD packet
err := stmt.mc.writePacket(data[:4+pktLen]) err := stmt.mc.writePacket(data[:4+pktLen])
// Every COM_LONG_DATA packet reset Packet Sequence
stmt.mc.resetSequence()
if err == nil { if err == nil {
data = data[pktLen-dataOffset:] data = data[pktLen-dataOffset:]
continue continue
} }
return err return err
} }
// Reset Packet Sequence
stmt.mc.sequence = 0
return nil return nil
} }
@ -925,7 +999,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
} }
// Reset packet-sequence // Reset packet-sequence
mc.sequence = 0 mc.resetSequence()
var data []byte var data []byte
var err error var err error
@ -937,28 +1011,20 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
// In this case the len(data) == cap(data) which is used to optimise the flow below. // In this case the len(data) == cap(data) which is used to optimise the flow below.
} }
if err != nil { if err != nil {
// cannot take the buffer. Something must be wrong with the connection return err
errLog.Print(err)
return errBadConnNoWrite
} }
// command [1 byte] // command [1 byte]
data[4] = comStmtExecute data[4] = comStmtExecute
// statement_id [4 bytes] // statement_id [4 bytes]
data[5] = byte(stmt.id) binary.LittleEndian.PutUint32(data[5:], stmt.id)
data[6] = byte(stmt.id >> 8)
data[7] = byte(stmt.id >> 16)
data[8] = byte(stmt.id >> 24)
// flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte] // flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte]
data[9] = 0x00 data[9] = 0x00
// iteration_count (uint32(1)) [4 bytes] // iteration_count (uint32(1)) [4 bytes]
data[10] = 0x01 binary.LittleEndian.PutUint32(data[10:], 1)
data[11] = 0x00
data[12] = 0x00
data[13] = 0x00
if len(args) > 0 { if len(args) > 0 {
pos := minPktLen pos := minPktLen
@ -1012,50 +1078,17 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
case int64: case int64:
paramTypes[i+i] = byte(fieldTypeLongLong) paramTypes[i+i] = byte(fieldTypeLongLong)
paramTypes[i+i+1] = 0x00 paramTypes[i+i+1] = 0x00
paramValues = binary.LittleEndian.AppendUint64(paramValues, uint64(v))
if cap(paramValues)-len(paramValues)-8 >= 0 {
paramValues = paramValues[:len(paramValues)+8]
binary.LittleEndian.PutUint64(
paramValues[len(paramValues)-8:],
uint64(v),
)
} else {
paramValues = append(paramValues,
uint64ToBytes(uint64(v))...,
)
}
case uint64: case uint64:
paramTypes[i+i] = byte(fieldTypeLongLong) paramTypes[i+i] = byte(fieldTypeLongLong)
paramTypes[i+i+1] = 0x80 // type is unsigned paramTypes[i+i+1] = 0x80 // type is unsigned
paramValues = binary.LittleEndian.AppendUint64(paramValues, uint64(v))
if cap(paramValues)-len(paramValues)-8 >= 0 {
paramValues = paramValues[:len(paramValues)+8]
binary.LittleEndian.PutUint64(
paramValues[len(paramValues)-8:],
uint64(v),
)
} else {
paramValues = append(paramValues,
uint64ToBytes(uint64(v))...,
)
}
case float64: case float64:
paramTypes[i+i] = byte(fieldTypeDouble) paramTypes[i+i] = byte(fieldTypeDouble)
paramTypes[i+i+1] = 0x00 paramTypes[i+i+1] = 0x00
paramValues = binary.LittleEndian.AppendUint64(paramValues, math.Float64bits(v))
if cap(paramValues)-len(paramValues)-8 >= 0 {
paramValues = paramValues[:len(paramValues)+8]
binary.LittleEndian.PutUint64(
paramValues[len(paramValues)-8:],
math.Float64bits(v),
)
} else {
paramValues = append(paramValues,
uint64ToBytes(math.Float64bits(v))...,
)
}
case bool: case bool:
paramTypes[i+i] = byte(fieldTypeTiny) paramTypes[i+i] = byte(fieldTypeTiny)
@ -1116,7 +1149,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
if v.IsZero() { if v.IsZero() {
b = append(b, "0000-00-00"...) b = append(b, "0000-00-00"...)
} else { } else {
b, err = appendDateTime(b, v.In(mc.cfg.Loc)) b, err = appendDateTime(b, v.In(mc.cfg.Loc), mc.cfg.timeTruncate)
if err != nil { if err != nil {
return err return err
} }
@ -1136,20 +1169,21 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
// In that case we must build the data packet with the new values buffer // In that case we must build the data packet with the new values buffer
if valuesCap != cap(paramValues) { if valuesCap != cap(paramValues) {
data = append(data[:pos], paramValues...) data = append(data[:pos], paramValues...)
if err = mc.buf.store(data); err != nil { mc.buf.store(data) // allow this buffer to be reused
errLog.Print(err)
return errBadConnNoWrite
}
} }
pos += len(paramValues) pos += len(paramValues)
data = data[:pos] data = data[:pos]
} }
return mc.writePacket(data) err = mc.writePacket(data)
mc.syncSequence()
return err
} }
func (mc *mysqlConn) discardResults() error { // For each remaining resultset in the stream, discards its rows and updates
// mc.affectedRows and mc.insertIds.
func (mc *okHandler) discardResults() error {
for mc.status&statusMoreResultsExists != 0 { for mc.status&statusMoreResultsExists != 0 {
resLen, err := mc.readResultSetHeaderPacket() resLen, err := mc.readResultSetHeaderPacket()
if err != nil { if err != nil {
@ -1157,11 +1191,11 @@ func (mc *mysqlConn) discardResults() error {
} }
if resLen > 0 { if resLen > 0 {
// columns // columns
if err := mc.readUntilEOF(); err != nil { if err := mc.conn().readUntilEOF(); err != nil {
return err return err
} }
// rows // rows
if err := mc.readUntilEOF(); err != nil { if err := mc.conn().readUntilEOF(); err != nil {
return err return err
} }
} }
@ -1268,7 +1302,8 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar,
fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB,
fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB,
fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON: fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON,
fieldTypeVector:
var isNull bool var isNull bool
var n int var n int
dest[i], isNull, n, err = readLengthEncodedString(data[pos:]) dest[i], isNull, n, err = readLengthEncodedString(data[pos:])

View File

@ -8,15 +8,43 @@
package mysql package mysql
import "database/sql/driver"
// Result exposes data not available through *connection.Result.
//
// This is accessible by executing statements using sql.Conn.Raw() and
// downcasting the returned result:
//
// res, err := rawConn.Exec(...)
// res.(mysql.Result).AllRowsAffected()
type Result interface {
driver.Result
// AllRowsAffected returns a slice containing the affected rows for each
// executed statement.
AllRowsAffected() []int64
// AllLastInsertIds returns a slice containing the last inserted ID for each
// executed statement.
AllLastInsertIds() []int64
}
type mysqlResult struct { type mysqlResult struct {
affectedRows int64 // One entry in both slices is created for every executed statement result.
insertId int64 affectedRows []int64
insertIds []int64
} }
func (res *mysqlResult) LastInsertId() (int64, error) { func (res *mysqlResult) LastInsertId() (int64, error) {
return res.insertId, nil return res.insertIds[len(res.insertIds)-1], nil
} }
func (res *mysqlResult) RowsAffected() (int64, error) { func (res *mysqlResult) RowsAffected() (int64, error) {
return res.affectedRows, nil return res.affectedRows[len(res.affectedRows)-1], nil
}
func (res *mysqlResult) AllLastInsertIds() []int64 {
return append([]int64{}, res.insertIds...) // defensive copy
}
func (res *mysqlResult) AllRowsAffected() []int64 {
return append([]int64{}, res.affectedRows...) // defensive copy
} }

View File

@ -111,19 +111,13 @@ func (rows *mysqlRows) Close() (err error) {
return err return err
} }
// flip the buffer for this connection if we need to drain it.
// note that for a successful query (i.e. one where rows.next()
// has been called until it returns false), `rows.mc` will be nil
// by the time the user calls `(*Rows).Close`, so we won't reach this
// see: https://github.com/golang/go/commit/651ddbdb5056ded455f47f9c494c67b389622a47
mc.buf.flip()
// Remove unread packets from stream // Remove unread packets from stream
if !rows.rs.done { if !rows.rs.done {
err = mc.readUntilEOF() err = mc.readUntilEOF()
} }
if err == nil { if err == nil {
if err = mc.discardResults(); err != nil { handleOk := mc.clearResult()
if err = handleOk.discardResults(); err != nil {
return err return err
} }
} }
@ -160,7 +154,15 @@ func (rows *mysqlRows) nextResultSet() (int, error) {
return 0, io.EOF return 0, io.EOF
} }
rows.rs = resultSet{} rows.rs = resultSet{}
return rows.mc.readResultSetHeaderPacket() // rows.mc.affectedRows and rows.mc.insertIds accumulate on each call to
// nextResultSet.
resLen, err := rows.mc.resultUnchanged().readResultSetHeaderPacket()
if err != nil {
// Clean up about multi-results flag
rows.rs.done = true
rows.mc.status = rows.mc.status & (^statusMoreResultsExists)
}
return resLen, err
} }
func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) { func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) {

View File

@ -24,11 +24,12 @@ type mysqlStmt struct {
func (stmt *mysqlStmt) Close() error { func (stmt *mysqlStmt) Close() error {
if stmt.mc == nil || stmt.mc.closed.Load() { if stmt.mc == nil || stmt.mc.closed.Load() {
// driver.Stmt.Close can be called more than once, thus this function // driver.Stmt.Close could be called more than once, thus this function
// has to be idempotent. // had to be idempotent. See also Issue #450 and golang/go#16019.
// See also Issue #450 and golang/go#16019. // This bug has been fixed in Go 1.8.
//errLog.Print(ErrInvalidConn) // https://github.com/golang/go/commit/90b8a0ca2d0b565c7c7199ffcf77b15ea6b6db3a
return driver.ErrBadConn // But we keep this function idempotent because it is safer.
return nil
} }
err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id) err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id)
@ -51,7 +52,6 @@ func (stmt *mysqlStmt) CheckNamedValue(nv *driver.NamedValue) (err error) {
func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
if stmt.mc.closed.Load() { if stmt.mc.closed.Load() {
errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
// Send command // Send command
@ -61,12 +61,10 @@ func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
} }
mc := stmt.mc mc := stmt.mc
handleOk := stmt.mc.clearResult()
mc.affectedRows = 0
mc.insertId = 0
// Read Result // Read Result
resLen, err := mc.readResultSetHeaderPacket() resLen, err := handleOk.readResultSetHeaderPacket()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -83,14 +81,12 @@ func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
} }
} }
if err := mc.discardResults(); err != nil { if err := handleOk.discardResults(); err != nil {
return nil, err return nil, err
} }
return &mysqlResult{ copied := mc.result
affectedRows: int64(mc.affectedRows), return &copied, nil
insertId: int64(mc.insertId),
}, nil
} }
func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
@ -99,7 +95,6 @@ func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
if stmt.mc.closed.Load() { if stmt.mc.closed.Load() {
errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
// Send command // Send command
@ -111,7 +106,8 @@ func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
mc := stmt.mc mc := stmt.mc
// Read Result // Read Result
resLen, err := mc.readResultSetHeaderPacket() handleOk := stmt.mc.clearResult()
resLen, err := handleOk.readResultSetHeaderPacket()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -144,7 +140,7 @@ type converter struct{}
// implementation does not. This function should be kept in sync with // implementation does not. This function should be kept in sync with
// database/sql/driver defaultConverter.ConvertValue() except for that // database/sql/driver defaultConverter.ConvertValue() except for that
// deliberate difference. // deliberate difference.
func (c converter) ConvertValue(v interface{}) (driver.Value, error) { func (c converter) ConvertValue(v any) (driver.Value, error) {
if driver.IsValue(v) { if driver.IsValue(v) {
return v, nil return v, nil
} }

View File

@ -13,18 +13,32 @@ type mysqlTx struct {
} }
func (tx *mysqlTx) Commit() (err error) { func (tx *mysqlTx) Commit() (err error) {
if tx.mc == nil || tx.mc.closed.Load() { if tx.mc == nil {
return ErrInvalidConn return ErrInvalidConn
} }
if tx.mc.closed.Load() {
err = tx.mc.error()
if err == nil {
err = ErrInvalidConn
}
return
}
err = tx.mc.exec("COMMIT") err = tx.mc.exec("COMMIT")
tx.mc = nil tx.mc = nil
return return
} }
func (tx *mysqlTx) Rollback() (err error) { func (tx *mysqlTx) Rollback() (err error) {
if tx.mc == nil || tx.mc.closed.Load() { if tx.mc == nil {
return ErrInvalidConn return ErrInvalidConn
} }
if tx.mc.closed.Load() {
err = tx.mc.error()
if err == nil {
err = ErrInvalidConn
}
return
}
err = tx.mc.exec("ROLLBACK") err = tx.mc.exec("ROLLBACK")
tx.mc = nil tx.mc = nil
return return

View File

@ -36,7 +36,7 @@ var (
// registering it. // registering it.
// //
// rootCertPool := x509.NewCertPool() // rootCertPool := x509.NewCertPool()
// pem, err := ioutil.ReadFile("/path/ca-cert.pem") // pem, err := os.ReadFile("/path/ca-cert.pem")
// if err != nil { // if err != nil {
// log.Fatal(err) // log.Fatal(err)
// } // }
@ -265,7 +265,11 @@ func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Va
return nil, fmt.Errorf("invalid DATETIME packet length %d", num) return nil, fmt.Errorf("invalid DATETIME packet length %d", num)
} }
func appendDateTime(buf []byte, t time.Time) ([]byte, error) { func appendDateTime(buf []byte, t time.Time, timeTruncate time.Duration) ([]byte, error) {
if timeTruncate > 0 {
t = t.Truncate(timeTruncate)
}
year, month, day := t.Date() year, month, day := t.Date()
hour, min, sec := t.Clock() hour, min, sec := t.Clock()
nsec := t.Nanosecond() nsec := t.Nanosecond()
@ -486,17 +490,16 @@ func formatBinaryTime(src []byte, length uint8) (driver.Value, error) {
* Convert from and to bytes * * Convert from and to bytes *
******************************************************************************/ ******************************************************************************/
func uint64ToBytes(n uint64) []byte { // 24bit integer: used for packet headers.
return []byte{
byte(n), func putUint24(data []byte, n int) {
byte(n >> 8), data[2] = byte(n >> 16)
byte(n >> 16), data[1] = byte(n >> 8)
byte(n >> 24), data[0] = byte(n)
byte(n >> 32), }
byte(n >> 40),
byte(n >> 48), func getUint24(data []byte) int {
byte(n >> 56), return int(data[2])<<16 | int(data[1])<<8 | int(data[0])
}
} }
func uint64ToString(n uint64) []byte { func uint64ToString(n uint64) []byte {
@ -521,16 +524,6 @@ func uint64ToString(n uint64) []byte {
return a[i:] return a[i:]
} }
// treats string value as unsigned integer representation
func stringToInt(b []byte) int {
val := 0
for i := range b {
val *= 10
val += int(b[i] - 0x30)
}
return val
}
// returns the string read as a bytes slice, whether the value is NULL, // returns the string read as a bytes slice, whether the value is NULL,
// the number of bytes read and an error, in case the string is longer than // the number of bytes read and an error, in case the string is longer than
// the input slice // the input slice
@ -582,18 +575,15 @@ func readLengthEncodedInteger(b []byte) (uint64, bool, int) {
// 252: value of following 2 // 252: value of following 2
case 0xfc: case 0xfc:
return uint64(b[1]) | uint64(b[2])<<8, false, 3 return uint64(binary.LittleEndian.Uint16(b[1:])), false, 3
// 253: value of following 3 // 253: value of following 3
case 0xfd: case 0xfd:
return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16, false, 4 return uint64(getUint24(b[1:])), false, 4
// 254: value of following 8 // 254: value of following 8
case 0xfe: case 0xfe:
return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16 | return uint64(binary.LittleEndian.Uint64(b[1:])), false, 9
uint64(b[4])<<24 | uint64(b[5])<<32 | uint64(b[6])<<40 |
uint64(b[7])<<48 | uint64(b[8])<<56,
false, 9
} }
// 0-250: value of first byte // 0-250: value of first byte
@ -607,13 +597,19 @@ func appendLengthEncodedInteger(b []byte, n uint64) []byte {
return append(b, byte(n)) return append(b, byte(n))
case n <= 0xffff: case n <= 0xffff:
return append(b, 0xfc, byte(n), byte(n>>8)) b = append(b, 0xfc)
return binary.LittleEndian.AppendUint16(b, uint16(n))
case n <= 0xffffff: case n <= 0xffffff:
return append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16)) return append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16))
} }
return append(b, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24), b = append(b, 0xfe)
byte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56)) return binary.LittleEndian.AppendUint64(b, n)
}
func appendLengthEncodedString(b []byte, s string) []byte {
b = appendLengthEncodedInteger(b, uint64(len(s)))
return append(b, s...)
} }
// reserveBuffer checks cap(buf) and expand buffer to len(buf) + appendSize. // reserveBuffer checks cap(buf) and expand buffer to len(buf) + appendSize.

View File

@ -155,7 +155,7 @@ stored in base64 encoded form, which was redundant with the information in the
type Token struct { type Token struct {
Raw string // Raw contains the raw token Raw string // Raw contains the raw token
Method SigningMethod // Method is the signing method used or to be used Method SigningMethod // Method is the signing method used or to be used
Header map[string]interface{} // Header is the first segment of the token in decoded form Header map[string]any // Header is the first segment of the token in decoded form
Claims Claims // Claims is the second segment of the token in decoded form Claims Claims // Claims is the second segment of the token in decoded form
Signature []byte // Signature is the third segment of the token in decoded form Signature []byte // Signature is the third segment of the token in decoded form
Valid bool // Valid specifies if the token is valid Valid bool // Valid specifies if the token is valid

View File

@ -55,7 +55,7 @@ func (m *SigningMethodECDSA) Alg() string {
// Verify implements token verification for the SigningMethod. // Verify implements token verification for the SigningMethod.
// For this verify method, key must be an ecdsa.PublicKey struct // For this verify method, key must be an ecdsa.PublicKey struct
func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key interface{}) error { func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key any) error {
// Get the key // Get the key
var ecdsaKey *ecdsa.PublicKey var ecdsaKey *ecdsa.PublicKey
switch k := key.(type) { switch k := key.(type) {
@ -89,7 +89,7 @@ func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key interf
// Sign implements token signing for the SigningMethod. // Sign implements token signing for the SigningMethod.
// For this signing method, key must be an ecdsa.PrivateKey struct // For this signing method, key must be an ecdsa.PrivateKey struct
func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodECDSA) Sign(signingString string, key any) ([]byte, error) {
// Get the key // Get the key
var ecdsaKey *ecdsa.PrivateKey var ecdsaKey *ecdsa.PrivateKey
switch k := key.(type) { switch k := key.(type) {

View File

@ -23,7 +23,7 @@ func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
} }
// Parse the key // Parse the key
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil { if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return nil, err return nil, err
@ -50,7 +50,7 @@ func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {
} }
// Parse the key // Parse the key
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
if cert, err := x509.ParseCertificate(block.Bytes); err == nil { if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
parsedKey = cert.PublicKey parsedKey = cert.PublicKey

View File

@ -33,7 +33,7 @@ func (m *SigningMethodEd25519) Alg() string {
// Verify implements token verification for the SigningMethod. // Verify implements token verification for the SigningMethod.
// For this verify method, key must be an ed25519.PublicKey // For this verify method, key must be an ed25519.PublicKey
func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key interface{}) error { func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key any) error {
var ed25519Key ed25519.PublicKey var ed25519Key ed25519.PublicKey
var ok bool var ok bool
@ -55,7 +55,7 @@ func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key inte
// Sign implements token signing for the SigningMethod. // Sign implements token signing for the SigningMethod.
// For this signing method, key must be an ed25519.PrivateKey // For this signing method, key must be an ed25519.PrivateKey
func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodEd25519) Sign(signingString string, key any) ([]byte, error) {
var ed25519Key crypto.Signer var ed25519Key crypto.Signer
var ok bool var ok bool

View File

@ -24,7 +24,7 @@ func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
} }
// Parse the key // Parse the key
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return nil, err return nil, err
} }
@ -49,7 +49,7 @@ func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) {
} }
// Parse the key // Parse the key
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
return nil, err return nil, err
} }

View File

@ -2,6 +2,7 @@ package jwt
import ( import (
"errors" "errors"
"fmt"
"strings" "strings"
) )
@ -47,3 +48,42 @@ func joinErrors(errs ...error) error {
errs: errs, errs: errs,
} }
} }
// Unwrap implements the multiple error unwrapping for this error type, which is
// possible in Go 1.20.
func (je joinedError) Unwrap() []error {
return je.errs
}
// newError creates a new error message with a detailed error message. The
// message will be prefixed with the contents of the supplied error type.
// Additionally, more errors, that provide more context can be supplied which
// will be appended to the message. This makes use of Go 1.20's possibility to
// include more than one %w formatting directive in [fmt.Errorf].
//
// For example,
//
// newError("no keyfunc was provided", ErrTokenUnverifiable)
//
// will produce the error string
//
// "token is unverifiable: no keyfunc was provided"
func newError(message string, err error, more ...error) error {
var format string
var args []any
if message != "" {
format = "%w: %s"
args = []any{err, message}
} else {
format = "%w"
args = []any{err}
}
for _, e := range more {
format += ": %w"
args = append(args, e)
}
err = fmt.Errorf(format, args...)
return err
}

View File

@ -1,47 +0,0 @@
//go:build go1.20
// +build go1.20
package jwt
import (
"fmt"
)
// Unwrap implements the multiple error unwrapping for this error type, which is
// possible in Go 1.20.
func (je joinedError) Unwrap() []error {
return je.errs
}
// newError creates a new error message with a detailed error message. The
// message will be prefixed with the contents of the supplied error type.
// Additionally, more errors, that provide more context can be supplied which
// will be appended to the message. This makes use of Go 1.20's possibility to
// include more than one %w formatting directive in [fmt.Errorf].
//
// For example,
//
// newError("no keyfunc was provided", ErrTokenUnverifiable)
//
// will produce the error string
//
// "token is unverifiable: no keyfunc was provided"
func newError(message string, err error, more ...error) error {
var format string
var args []any
if message != "" {
format = "%w: %s"
args = []any{err, message}
} else {
format = "%w"
args = []any{err}
}
for _, e := range more {
format += ": %w"
args = append(args, e)
}
err = fmt.Errorf(format, args...)
return err
}

View File

@ -1,78 +0,0 @@
//go:build !go1.20
// +build !go1.20
package jwt
import (
"errors"
"fmt"
)
// Is implements checking for multiple errors using [errors.Is], since multiple
// error unwrapping is not possible in versions less than Go 1.20.
func (je joinedError) Is(err error) bool {
for _, e := range je.errs {
if errors.Is(e, err) {
return true
}
}
return false
}
// wrappedErrors is a workaround for wrapping multiple errors in environments
// where Go 1.20 is not available. It basically uses the already implemented
// functionality of joinedError to handle multiple errors with supplies a
// custom error message that is identical to the one we produce in Go 1.20 using
// multiple %w directives.
type wrappedErrors struct {
msg string
joinedError
}
// Error returns the stored error string
func (we wrappedErrors) Error() string {
return we.msg
}
// newError creates a new error message with a detailed error message. The
// message will be prefixed with the contents of the supplied error type.
// Additionally, more errors, that provide more context can be supplied which
// will be appended to the message. Since we cannot use of Go 1.20's possibility
// to include more than one %w formatting directive in [fmt.Errorf], we have to
// emulate that.
//
// For example,
//
// newError("no keyfunc was provided", ErrTokenUnverifiable)
//
// will produce the error string
//
// "token is unverifiable: no keyfunc was provided"
func newError(message string, err error, more ...error) error {
// We cannot wrap multiple errors here with %w, so we have to be a little
// bit creative. Basically, we are using %s instead of %w to produce the
// same error message and then throw the result into a custom error struct.
var format string
var args []any
if message != "" {
format = "%s: %s"
args = []any{err, message}
} else {
format = "%s"
args = []any{err}
}
errs := []error{err}
for _, e := range more {
format += ": %s"
args = append(args, e)
errs = append(errs, e)
}
err = &wrappedErrors{
msg: fmt.Sprintf(format, args...),
joinedError: joinedError{errs: errs},
}
return err
}

View File

@ -55,7 +55,7 @@ func (m *SigningMethodHMAC) Alg() string {
// about this, and why we intentionally are not supporting string as a key can // about this, and why we intentionally are not supporting string as a key can
// be found on our usage guide // be found on our usage guide
// https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types. // https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types.
func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interface{}) error { func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key any) error {
// Verify the key is the right type // Verify the key is the right type
keyBytes, ok := key.([]byte) keyBytes, ok := key.([]byte)
if !ok { if !ok {
@ -88,7 +88,7 @@ func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interfa
// cryptographically random source, e.g. crypto/rand. Additional information // cryptographically random source, e.g. crypto/rand. Additional information
// about this, and why we intentionally are not supporting string as a key can // about this, and why we intentionally are not supporting string as a key can
// be found on our usage guide https://golang-jwt.github.io/jwt/usage/signing_methods/. // be found on our usage guide https://golang-jwt.github.io/jwt/usage/signing_methods/.
func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodHMAC) Sign(signingString string, key any) ([]byte, error) {
if keyBytes, ok := key.([]byte); ok { if keyBytes, ok := key.([]byte); ok {
if !m.Hash.Available() { if !m.Hash.Available() {
return nil, ErrHashUnavailable return nil, ErrHashUnavailable

View File

@ -5,9 +5,9 @@ import (
"fmt" "fmt"
) )
// MapClaims is a claims type that uses the map[string]interface{} for JSON // MapClaims is a claims type that uses the map[string]any for JSON
// decoding. This is the default claims type if you don't supply one // decoding. This is the default claims type if you don't supply one
type MapClaims map[string]interface{} type MapClaims map[string]any
// GetExpirationTime implements the Claims interface. // GetExpirationTime implements the Claims interface.
func (m MapClaims) GetExpirationTime() (*NumericDate, error) { func (m MapClaims) GetExpirationTime() (*NumericDate, error) {
@ -73,7 +73,7 @@ func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
cs = append(cs, v) cs = append(cs, v)
case []string: case []string:
cs = v cs = v
case []interface{}: case []any:
for _, a := range v { for _, a := range v {
vs, ok := a.(string) vs, ok := a.(string)
if !ok { if !ok {
@ -92,7 +92,7 @@ func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
func (m MapClaims) parseString(key string) (string, error) { func (m MapClaims) parseString(key string) (string, error) {
var ( var (
ok bool ok bool
raw interface{} raw any
iss string iss string
) )
raw, ok = m[key] raw, ok = m[key]

View File

@ -25,7 +25,7 @@ func (m *signingMethodNone) Alg() string {
} }
// Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key // Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key
func (m *signingMethodNone) Verify(signingString string, sig []byte, key interface{}) (err error) { func (m *signingMethodNone) Verify(signingString string, sig []byte, key any) (err error) {
// Key must be UnsafeAllowNoneSignatureType to prevent accidentally // Key must be UnsafeAllowNoneSignatureType to prevent accidentally
// accepting 'none' signing method // accepting 'none' signing method
if _, ok := key.(unsafeNoneMagicConstant); !ok { if _, ok := key.(unsafeNoneMagicConstant); !ok {
@ -41,7 +41,7 @@ func (m *signingMethodNone) Verify(signingString string, sig []byte, key interfa
} }
// Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key // Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key
func (m *signingMethodNone) Sign(signingString string, key interface{}) ([]byte, error) { func (m *signingMethodNone) Sign(signingString string, key any) ([]byte, error) {
if _, ok := key.(unsafeNoneMagicConstant); ok { if _, ok := key.(unsafeNoneMagicConstant); ok {
return []byte{}, nil return []byte{}, nil
} }

View File

@ -66,20 +66,37 @@ func WithExpirationRequired() ParserOption {
} }
} }
// WithAudience configures the validator to require the specified audience in // WithAudience configures the validator to require any of the specified
// the `aud` claim. Validation will fail if the audience is not listed in the // audiences in the `aud` claim. Validation will fail if the audience is not
// token or the `aud` claim is missing. // listed in the token or the `aud` claim is missing.
// //
// NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is // NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is
// application-specific. Since this validation API is helping developers in // application-specific. Since this validation API is helping developers in
// writing secure application, we decided to REQUIRE the existence of the claim, // writing secure application, we decided to REQUIRE the existence of the claim,
// if an audience is expected. // if an audience is expected.
func WithAudience(aud string) ParserOption { func WithAudience(aud ...string) ParserOption {
return func(p *Parser) { return func(p *Parser) {
p.validator.expectedAud = aud p.validator.expectedAud = aud
} }
} }
// WithAllAudiences configures the validator to require all the specified
// audiences in the `aud` claim. Validation will fail if the specified audiences
// are not listed in the token or the `aud` claim is missing. Duplicates within
// the list are de-duplicated since internally, we use a map to look up the
// audiences.
//
// NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is
// application-specific. Since this validation API is helping developers in
// writing secure application, we decided to REQUIRE the existence of the claim,
// if an audience is expected.
func WithAllAudiences(aud ...string) ParserOption {
return func(p *Parser) {
p.validator.expectedAud = aud
p.validator.expectAllAud = true
}
}
// WithIssuer configures the validator to require the specified issuer in the // WithIssuer configures the validator to require the specified issuer in the
// `iss` claim. Validation will fail if a different issuer is specified in the // `iss` claim. Validation will fail if a different issuer is specified in the
// token or the `iss` claim is missing. // token or the `iss` claim is missing.

View File

@ -46,7 +46,7 @@ func (m *SigningMethodRSA) Alg() string {
// Verify implements token verification for the SigningMethod // Verify implements token verification for the SigningMethod
// For this signing method, must be an *rsa.PublicKey structure. // For this signing method, must be an *rsa.PublicKey structure.
func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key interface{}) error { func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key any) error {
var rsaKey *rsa.PublicKey var rsaKey *rsa.PublicKey
var ok bool var ok bool
@ -67,7 +67,7 @@ func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key interfac
// Sign implements token signing for the SigningMethod // Sign implements token signing for the SigningMethod
// For this signing method, must be an *rsa.PrivateKey structure. // For this signing method, must be an *rsa.PrivateKey structure.
func (m *SigningMethodRSA) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodRSA) Sign(signingString string, key any) ([]byte, error) {
var rsaKey *rsa.PrivateKey var rsaKey *rsa.PrivateKey
var ok bool var ok bool

View File

@ -1,6 +1,3 @@
//go:build go1.4
// +build go1.4
package jwt package jwt
import ( import (
@ -82,7 +79,7 @@ func init() {
// Verify implements token verification for the SigningMethod. // Verify implements token verification for the SigningMethod.
// For this verify method, key must be an rsa.PublicKey struct // For this verify method, key must be an rsa.PublicKey struct
func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key interface{}) error { func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key any) error {
var rsaKey *rsa.PublicKey var rsaKey *rsa.PublicKey
switch k := key.(type) { switch k := key.(type) {
case *rsa.PublicKey: case *rsa.PublicKey:
@ -108,7 +105,7 @@ func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key inter
// Sign implements token signing for the SigningMethod. // Sign implements token signing for the SigningMethod.
// For this signing method, key must be an rsa.PrivateKey struct // For this signing method, key must be an rsa.PrivateKey struct
func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodRSAPSS) Sign(signingString string, key any) ([]byte, error) {
var rsaKey *rsa.PrivateKey var rsaKey *rsa.PrivateKey
switch k := key.(type) { switch k := key.(type) {

View File

@ -23,7 +23,7 @@ func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
return nil, ErrKeyMustBePEMEncoded return nil, ErrKeyMustBePEMEncoded
} }
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return nil, err return nil, err
@ -53,7 +53,7 @@ func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.Pr
return nil, ErrKeyMustBePEMEncoded return nil, ErrKeyMustBePEMEncoded
} }
var parsedKey interface{} var parsedKey any
var blockDecrypted []byte var blockDecrypted []byte
if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil { if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil {
@ -86,7 +86,7 @@ func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
} }
// Parse the key // Parse the key
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
if cert, err := x509.ParseCertificate(block.Bytes); err == nil { if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
parsedKey = cert.PublicKey parsedKey = cert.PublicKey

View File

@ -12,9 +12,9 @@ var signingMethodLock = new(sync.RWMutex)
// signature in Sign. The signature is then usually base64 encoded as part of a // signature in Sign. The signature is then usually base64 encoded as part of a
// JWT. // JWT.
type SigningMethod interface { type SigningMethod interface {
Verify(signingString string, sig []byte, key interface{}) error // Returns nil if signature is valid Verify(signingString string, sig []byte, key any) error // Returns nil if signature is valid
Sign(signingString string, key interface{}) ([]byte, error) // Returns signature or error Sign(signingString string, key any) ([]byte, error) // Returns signature or error
Alg() string // returns the alg identifier for this method (example: 'HS256') Alg() string // returns the alg identifier for this method (example: 'HS256')
} }
// RegisterSigningMethod registers the "alg" name and a factory function for signing method. // RegisterSigningMethod registers the "alg" name and a factory function for signing method.

View File

@ -11,9 +11,9 @@ import (
// Token. This allows you to use properties in the Header of the token (such as // Token. This allows you to use properties in the Header of the token (such as
// `kid`) to identify which key to use. // `kid`) to identify which key to use.
// //
// The returned interface{} may be a single key or a VerificationKeySet containing // The returned any may be a single key or a VerificationKeySet containing
// multiple keys. // multiple keys.
type Keyfunc func(*Token) (interface{}, error) type Keyfunc func(*Token) (any, error)
// VerificationKey represents a public or secret key for verifying a token's signature. // VerificationKey represents a public or secret key for verifying a token's signature.
type VerificationKey interface { type VerificationKey interface {
@ -28,12 +28,12 @@ type VerificationKeySet struct {
// Token represents a JWT Token. Different fields will be used depending on // Token represents a JWT Token. Different fields will be used depending on
// whether you're creating or parsing/verifying a token. // whether you're creating or parsing/verifying a token.
type Token struct { type Token struct {
Raw string // Raw contains the raw token. Populated when you [Parse] a token Raw string // Raw contains the raw token. Populated when you [Parse] a token
Method SigningMethod // Method is the signing method used or to be used Method SigningMethod // Method is the signing method used or to be used
Header map[string]interface{} // Header is the first segment of the token in decoded form Header map[string]any // Header is the first segment of the token in decoded form
Claims Claims // Claims is the second segment of the token in decoded form Claims Claims // Claims is the second segment of the token in decoded form
Signature []byte // Signature is the third segment of the token in decoded form. Populated when you Parse a token Signature []byte // Signature is the third segment of the token in decoded form. Populated when you Parse a token
Valid bool // Valid specifies if the token is valid. Populated when you Parse/Verify a token Valid bool // Valid specifies if the token is valid. Populated when you Parse/Verify a token
} }
// New creates a new [Token] with the specified signing method and an empty map // New creates a new [Token] with the specified signing method and an empty map
@ -46,7 +46,7 @@ func New(method SigningMethod, opts ...TokenOption) *Token {
// claims. Additional options can be specified, but are currently unused. // claims. Additional options can be specified, but are currently unused.
func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption) *Token { func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption) *Token {
return &Token{ return &Token{
Header: map[string]interface{}{ Header: map[string]any{
"typ": "JWT", "typ": "JWT",
"alg": method.Alg(), "alg": method.Alg(),
}, },
@ -60,7 +60,7 @@ func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption) *To
// https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types // https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types
// for an overview of the different signing methods and their respective key // for an overview of the different signing methods and their respective key
// types. // types.
func (t *Token) SignedString(key interface{}) (string, error) { func (t *Token) SignedString(key any) (string, error) {
sstr, err := t.SigningString() sstr, err := t.SigningString()
if err != nil { if err != nil {
return "", err return "", err

View File

@ -103,7 +103,7 @@ func (date *NumericDate) UnmarshalJSON(b []byte) (err error) {
type ClaimStrings []string type ClaimStrings []string
func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) { func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
var value interface{} var value any
if err = json.Unmarshal(data, &value); err != nil { if err = json.Unmarshal(data, &value); err != nil {
return err return err
@ -116,7 +116,7 @@ func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
aud = append(aud, v) aud = append(aud, v)
case []string: case []string:
aud = ClaimStrings(v) aud = ClaimStrings(v)
case []interface{}: case []any:
for _, vv := range v { for _, vv := range v {
vs, ok := vv.(string) vs, ok := vv.(string)
if !ok { if !ok {

View File

@ -1,8 +1,8 @@
package jwt package jwt
import ( import (
"crypto/subtle"
"fmt" "fmt"
"slices"
"time" "time"
) )
@ -52,8 +52,12 @@ type Validator struct {
verifyIat bool verifyIat bool
// expectedAud contains the audience this token expects. Supplying an empty // expectedAud contains the audience this token expects. Supplying an empty
// string will disable aud checking. // slice will disable aud checking.
expectedAud string expectedAud []string
// expectAllAud specifies whether all expected audiences must be present in
// the token. If false, only one of the expected audiences must be present.
expectAllAud bool
// expectedIss contains the issuer this token expects. Supplying an empty // expectedIss contains the issuer this token expects. Supplying an empty
// string will disable iss checking. // string will disable iss checking.
@ -88,7 +92,7 @@ func NewValidator(opts ...ParserOption) *Validator {
func (v *Validator) Validate(claims Claims) error { func (v *Validator) Validate(claims Claims) error {
var ( var (
now time.Time now time.Time
errs []error = make([]error, 0, 6) errs = make([]error, 0, 6)
err error err error
) )
@ -120,8 +124,8 @@ func (v *Validator) Validate(claims Claims) error {
} }
// If we have an expected audience, we also require the audience claim // If we have an expected audience, we also require the audience claim
if v.expectedAud != "" { if len(v.expectedAud) > 0 {
if err = v.verifyAudience(claims, v.expectedAud, true); err != nil { if err = v.verifyAudience(claims, v.expectedAud, v.expectAllAud); err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
} }
@ -226,33 +230,39 @@ func (v *Validator) verifyNotBefore(claims Claims, cmp time.Time, required bool)
// //
// Additionally, if any error occurs while retrieving the claim, e.g., when its // Additionally, if any error occurs while retrieving the claim, e.g., when its
// the wrong type, an ErrTokenUnverifiable error will be returned. // the wrong type, an ErrTokenUnverifiable error will be returned.
func (v *Validator) verifyAudience(claims Claims, cmp string, required bool) error { func (v *Validator) verifyAudience(claims Claims, cmp []string, expectAllAud bool) error {
aud, err := claims.GetAudience() aud, err := claims.GetAudience()
if err != nil { if err != nil {
return err return err
} }
if len(aud) == 0 { // Check that aud exists and is not empty. We only require the aud claim
// if we expect at least one audience to be present.
if len(aud) == 0 || len(aud) == 1 && aud[0] == "" {
required := len(v.expectedAud) > 0
return errorIfRequired(required, "aud") return errorIfRequired(required, "aud")
} }
// use a var here to keep constant time compare when looping over a number of claims if !expectAllAud {
result := false for _, a := range aud {
// If we only expect one match, we can stop early if we find a match
var stringClaims string if slices.Contains(cmp, a) {
for _, a := range aud { return nil
if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 { }
result = true
} }
stringClaims = stringClaims + a
return ErrTokenInvalidAudience
} }
// case where "" is sent in one or many aud claims // Note that we are looping cmp here to ensure that all expected audiences
if stringClaims == "" { // are present in the aud claim.
return errorIfRequired(required, "aud") for _, a := range cmp {
if !slices.Contains(aud, a) {
return ErrTokenInvalidAudience
}
} }
return errorIfFalse(result, ErrTokenInvalidAudience) return nil
} }
// verifyIssuer compares the iss claim in claims against cmp. // verifyIssuer compares the iss claim in claims against cmp.

View File

@ -50,7 +50,7 @@ func (ih InvalidHashPrefixError) Error() string {
type InvalidCostError int type InvalidCostError int
func (ic InvalidCostError) Error() string { func (ic InvalidCostError) Error() string {
return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), MinCost, MaxCost) return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed inclusive range %d..%d", int(ic), MinCost, MaxCost)
} }
const ( const (

View File

@ -2,16 +2,19 @@
// 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.
// Package ed25519 implements the Ed25519 signature algorithm. See // Package ed25519 implements the Ed25519 signature algorithm.
// https://ed25519.cr.yp.to/.
// //
// These functions are also compatible with the “Ed25519” function defined in // These functions are also compatible with the “Ed25519” function defined in
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key // [RFC 8032]. However, unlike RFC 8032's formulation, this package's private key
// representation includes a public key suffix to make multiple signing // representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC // operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”. // 8032 private key as the “seed”.
// //
// This package is a wrapper around the standard library crypto/ed25519 package. // The ed25519 package is a wrapper for the Ed25519 implementation in the
// crypto/ed25519 package. It is [frozen] and is not accepting new features.
//
// [RFC 8032]: https://datatracker.ietf.org/doc/html/rfc8032
// [frozen]: https://go.dev/wiki/Frozen
package ed25519 package ed25519
import ( import (

View File

@ -1,21 +0,0 @@
// 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 go1.5
package plan9
import "syscall"
func fixwd() {
syscall.Fixwd()
}
func Getwd() (wd string, err error) {
return syscall.Getwd()
}
func Chdir(path string) error {
return syscall.Chdir(path)
}

View File

@ -2,22 +2,18 @@
// 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 !go1.5
package plan9 package plan9
import "syscall"
func fixwd() { func fixwd() {
syscall.Fixwd()
} }
func Getwd() (wd string, err error) { func Getwd() (wd string, err error) {
fd, err := open(".", O_RDONLY) return syscall.Getwd()
if err != nil {
return "", err
}
defer Close(fd)
return Fd2path(fd)
} }
func Chdir(path string) error { func Chdir(path string) error {
return chdir(path) return syscall.Chdir(path)
} }

View File

@ -38,8 +38,15 @@ func SchedSetaffinity(pid int, set *CPUSet) error {
// Zero clears the set s, so that it contains no CPUs. // Zero clears the set s, so that it contains no CPUs.
func (s *CPUSet) Zero() { func (s *CPUSet) Zero() {
clear(s[:])
}
// Fill adds all possible CPU bits to the set s. On Linux, [SchedSetaffinity]
// will silently ignore any invalid CPU bits in [CPUSet] so this is an
// efficient way of resetting the CPU affinity of a process.
func (s *CPUSet) Fill() {
for i := range s { for i := range s {
s[i] = 0 s[i] = ^cpuMask(0)
} }
} }

View File

@ -23,7 +23,5 @@ func (fds *FdSet) IsSet(fd int) bool {
// Zero clears the set fds. // Zero clears the set fds.
func (fds *FdSet) Zero() { func (fds *FdSet) Zero() {
for i := range fds.Bits { clear(fds.Bits[:])
fds.Bits[i] = 0
}
} }

View File

@ -111,9 +111,7 @@ func (ifr *Ifreq) SetUint32(v uint32) {
// clear zeroes the ifreq's union field to prevent trailing garbage data from // clear zeroes the ifreq's union field to prevent trailing garbage data from
// being sent to the kernel if an ifreq is reused. // being sent to the kernel if an ifreq is reused.
func (ifr *Ifreq) clear() { func (ifr *Ifreq) clear() {
for i := range ifr.raw.Ifru { clear(ifr.raw.Ifru[:])
ifr.raw.Ifru[i] = 0
}
} }
// TODO(mdlayher): export as IfreqData? For now we can provide helpers such as // TODO(mdlayher): export as IfreqData? For now we can provide helpers such as

View File

@ -49,6 +49,7 @@ esac
if [[ "$GOOS" = "linux" ]]; then if [[ "$GOOS" = "linux" ]]; then
# Use the Docker-based build system # Use the Docker-based build system
# Files generated through docker (use $cmd so you can Ctl-C the build or run) # Files generated through docker (use $cmd so you can Ctl-C the build or run)
set -e
$cmd docker build --tag generate:$GOOS $GOOS $cmd docker build --tag generate:$GOOS $GOOS
$cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS $cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS
exit exit

View File

@ -226,6 +226,7 @@ struct ltchars {
#include <linux/cryptouser.h> #include <linux/cryptouser.h>
#include <linux/devlink.h> #include <linux/devlink.h>
#include <linux/dm-ioctl.h> #include <linux/dm-ioctl.h>
#include <linux/elf.h>
#include <linux/errqueue.h> #include <linux/errqueue.h>
#include <linux/ethtool_netlink.h> #include <linux/ethtool_netlink.h>
#include <linux/falloc.h> #include <linux/falloc.h>
@ -255,6 +256,7 @@ struct ltchars {
#include <linux/loop.h> #include <linux/loop.h>
#include <linux/lwtunnel.h> #include <linux/lwtunnel.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/mei.h>
#include <linux/memfd.h> #include <linux/memfd.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mount.h> #include <linux/mount.h>
@ -349,6 +351,9 @@ struct ltchars {
#define _HIDIOCGRAWPHYS HIDIOCGRAWPHYS(_HIDIOCGRAWPHYS_LEN) #define _HIDIOCGRAWPHYS HIDIOCGRAWPHYS(_HIDIOCGRAWPHYS_LEN)
#define _HIDIOCGRAWUNIQ HIDIOCGRAWUNIQ(_HIDIOCGRAWUNIQ_LEN) #define _HIDIOCGRAWUNIQ HIDIOCGRAWUNIQ(_HIDIOCGRAWUNIQ_LEN)
// Renamed in v6.16, commit c6d732c38f93 ("net: ethtool: remove duplicate defines for family info")
#define ETHTOOL_FAMILY_NAME ETHTOOL_GENL_NAME
#define ETHTOOL_FAMILY_VERSION ETHTOOL_GENL_VERSION
' '
includes_NetBSD=' includes_NetBSD='
@ -526,6 +531,7 @@ ccflags="$@"
$2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ || $2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ ||
$2 ~ /^(NL|CR|TAB|BS|VT|FF)DLY$/ || $2 ~ /^(NL|CR|TAB|BS|VT|FF)DLY$/ ||
$2 ~ /^(NL|CR|TAB|BS|VT|FF)[0-9]$/ || $2 ~ /^(NL|CR|TAB|BS|VT|FF)[0-9]$/ ||
$2 ~ /^(DT|EI|ELF|EV|NN|NT|PF|SHF|SHN|SHT|STB|STT|VER)_/ ||
$2 ~ /^O?XTABS$/ || $2 ~ /^O?XTABS$/ ||
$2 ~ /^TC[IO](ON|OFF)$/ || $2 ~ /^TC[IO](ON|OFF)$/ ||
$2 ~ /^IN_/ || $2 ~ /^IN_/ ||
@ -608,7 +614,7 @@ ccflags="$@"
$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)_/ ||
$2 ~ /^IOCTL_VM_SOCKETS_/ || $2 ~ /^(IOCTL_VM_SOCKETS_|IOCTL_MEI_)/ ||
$2 ~ /^(TASKSTATS|TS)_/ || $2 ~ /^(TASKSTATS|TS)_/ ||
$2 ~ /^CGROUPSTATS_/ || $2 ~ /^CGROUPSTATS_/ ||
$2 ~ /^GENL_/ || $2 ~ /^GENL_/ ||

View File

@ -602,14 +602,9 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI
return return
} }
// sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error)
const minIovec = 8 const minIovec = 8
func Readv(fd int, iovs [][]byte) (n int, err error) { func Readv(fd int, iovs [][]byte) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec) iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs) iovecs = appendBytes(iovecs, iovs)
n, err = readv(fd, iovecs) n, err = readv(fd, iovecs)
@ -618,9 +613,6 @@ func Readv(fd int, iovs [][]byte) (n int, err error) {
} }
func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) { func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec) iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs) iovecs = appendBytes(iovecs, iovs)
n, err = preadv(fd, iovecs, offset) n, err = preadv(fd, iovecs, offset)
@ -629,10 +621,6 @@ func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
} }
func Writev(fd int, iovs [][]byte) (n int, err error) { func Writev(fd int, iovs [][]byte) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec) iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs) iovecs = appendBytes(iovecs, iovs)
if raceenabled { if raceenabled {
@ -644,10 +632,6 @@ func Writev(fd int, iovs [][]byte) (n int, err error) {
} }
func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) { func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec) iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs) iovecs = appendBytes(iovecs, iovs)
if raceenabled { if raceenabled {
@ -707,45 +691,7 @@ func readvRacedetect(iovecs []Iovec, n int, err error) {
} }
} }
func darwinMajorMinPatch() (maj, min, patch int, err error) { //sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error)
var un Utsname
err = Uname(&un)
if err != nil {
return
}
var mmp [3]int
c := 0
Loop:
for _, b := range un.Release[:] {
switch {
case b >= '0' && b <= '9':
mmp[c] = 10*mmp[c] + int(b-'0')
case b == '.':
c++
if c > 2 {
return 0, 0, 0, ENOTSUP
}
case b == 0:
break Loop
default:
return 0, 0, 0, ENOTSUP
}
}
if c != 2 {
return 0, 0, 0, ENOTSUP
}
return mmp[0], mmp[1], mmp[2], nil
}
func darwinKernelVersionMin(maj, min, patch int) bool {
actualMaj, actualMin, actualPatch, err := darwinMajorMinPatch()
if err != nil {
return false
}
return actualMaj > maj || actualMaj == maj && (actualMin > min || actualMin == min && actualPatch >= patch)
}
//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) //sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error)

View File

@ -801,9 +801,7 @@ func (sa *SockaddrPPPoE) sockaddr() (unsafe.Pointer, _Socklen, error) {
// one. The kernel expects SID to be in network byte order. // one. The kernel expects SID to be in network byte order.
binary.BigEndian.PutUint16(sa.raw[6:8], sa.SID) binary.BigEndian.PutUint16(sa.raw[6:8], sa.SID)
copy(sa.raw[8:14], sa.Remote) copy(sa.raw[8:14], sa.Remote)
for i := 14; i < 14+IFNAMSIZ; i++ { clear(sa.raw[14 : 14+IFNAMSIZ])
sa.raw[i] = 0
}
copy(sa.raw[14:], sa.Dev) copy(sa.raw[14:], sa.Dev)
return unsafe.Pointer(&sa.raw), SizeofSockaddrPPPoX, nil return unsafe.Pointer(&sa.raw), SizeofSockaddrPPPoX, nil
} }
@ -2645,3 +2643,9 @@ func SchedGetAttr(pid int, flags uint) (*SchedAttr, error) {
//sys Cachestat(fd uint, crange *CachestatRange, cstat *Cachestat_t, flags uint) (err error) //sys Cachestat(fd uint, crange *CachestatRange, cstat *Cachestat_t, flags uint) (err error)
//sys Mseal(b []byte, flags uint) (err error) //sys Mseal(b []byte, flags uint) (err error)
//sys setMemPolicy(mode int, mask *CPUSet, size int) (err error) = SYS_SET_MEMPOLICY
func SetMemPolicy(mode int, mask *CPUSet) error {
return setMemPolicy(mode, mask, _CPU_SETSIZE)
}

View File

@ -248,6 +248,23 @@ func Statvfs(path string, buf *Statvfs_t) (err error) {
return Statvfs1(path, buf, ST_WAIT) return Statvfs1(path, buf, ST_WAIT)
} }
func Getvfsstat(buf []Statvfs_t, flags int) (n int, err error) {
var (
_p0 unsafe.Pointer
bufsize uintptr
)
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
bufsize = unsafe.Sizeof(Statvfs_t{}) * uintptr(len(buf))
}
r0, _, e1 := Syscall(SYS_GETVFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
n = int(r0)
if e1 != 0 {
err = e1
}
return
}
/* /*
* Exposed directly * Exposed directly
*/ */

View File

@ -629,7 +629,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sys Kill(pid int, signum syscall.Signal) (err error) //sys Kill(pid int, signum syscall.Signal) (err error)
//sys Lchown(path string, uid int, gid int) (err error) //sys Lchown(path string, uid int, gid int) (err error)
//sys Link(path string, link string) (err error) //sys Link(path string, link string) (err error)
//sys Listen(s int, backlog int) (err error) = libsocket.__xnet_llisten //sys Listen(s int, backlog int) (err error) = libsocket.__xnet_listen
//sys Lstat(path string, stat *Stat_t) (err error) //sys Lstat(path string, stat *Stat_t) (err error)
//sys Madvise(b []byte, advice int) (err error) //sys Madvise(b []byte, advice int) (err error)
//sys Mkdir(path string, mode uint32) (err error) //sys Mkdir(path string, mode uint32) (err error)

View File

@ -319,6 +319,7 @@ const (
AUDIT_INTEGRITY_POLICY_RULE = 0x70f AUDIT_INTEGRITY_POLICY_RULE = 0x70f
AUDIT_INTEGRITY_RULE = 0x70d AUDIT_INTEGRITY_RULE = 0x70d
AUDIT_INTEGRITY_STATUS = 0x70a AUDIT_INTEGRITY_STATUS = 0x70a
AUDIT_INTEGRITY_USERSPACE = 0x710
AUDIT_IPC = 0x517 AUDIT_IPC = 0x517
AUDIT_IPC_SET_PERM = 0x51f AUDIT_IPC_SET_PERM = 0x51f
AUDIT_IPE_ACCESS = 0x58c AUDIT_IPE_ACCESS = 0x58c
@ -327,6 +328,8 @@ const (
AUDIT_KERNEL = 0x7d0 AUDIT_KERNEL = 0x7d0
AUDIT_KERNEL_OTHER = 0x524 AUDIT_KERNEL_OTHER = 0x524
AUDIT_KERN_MODULE = 0x532 AUDIT_KERN_MODULE = 0x532
AUDIT_LANDLOCK_ACCESS = 0x58f
AUDIT_LANDLOCK_DOMAIN = 0x590
AUDIT_LAST_FEATURE = 0x1 AUDIT_LAST_FEATURE = 0x1
AUDIT_LAST_KERN_ANOM_MSG = 0x707 AUDIT_LAST_KERN_ANOM_MSG = 0x707
AUDIT_LAST_USER_MSG = 0x4af AUDIT_LAST_USER_MSG = 0x4af
@ -491,6 +494,7 @@ const (
BPF_F_BEFORE = 0x8 BPF_F_BEFORE = 0x8
BPF_F_ID = 0x20 BPF_F_ID = 0x20
BPF_F_NETFILTER_IP_DEFRAG = 0x1 BPF_F_NETFILTER_IP_DEFRAG = 0x1
BPF_F_PREORDER = 0x40
BPF_F_QUERY_EFFECTIVE = 0x1 BPF_F_QUERY_EFFECTIVE = 0x1
BPF_F_REDIRECT_FLAGS = 0x19 BPF_F_REDIRECT_FLAGS = 0x19
BPF_F_REPLACE = 0x4 BPF_F_REPLACE = 0x4
@ -527,6 +531,7 @@ const (
BPF_LDX = 0x1 BPF_LDX = 0x1
BPF_LEN = 0x80 BPF_LEN = 0x80
BPF_LL_OFF = -0x200000 BPF_LL_OFF = -0x200000
BPF_LOAD_ACQ = 0x100
BPF_LSH = 0x60 BPF_LSH = 0x60
BPF_MAJOR_VERSION = 0x1 BPF_MAJOR_VERSION = 0x1
BPF_MAXINSNS = 0x1000 BPF_MAXINSNS = 0x1000
@ -554,6 +559,7 @@ const (
BPF_RET = 0x6 BPF_RET = 0x6
BPF_RSH = 0x70 BPF_RSH = 0x70
BPF_ST = 0x2 BPF_ST = 0x2
BPF_STORE_REL = 0x110
BPF_STX = 0x3 BPF_STX = 0x3
BPF_SUB = 0x10 BPF_SUB = 0x10
BPF_TAG_SIZE = 0x8 BPF_TAG_SIZE = 0x8
@ -843,24 +849,90 @@ const (
DM_UUID_FLAG = 0x4000 DM_UUID_FLAG = 0x4000
DM_UUID_LEN = 0x81 DM_UUID_LEN = 0x81
DM_VERSION = 0xc138fd00 DM_VERSION = 0xc138fd00
DM_VERSION_EXTRA = "-ioctl (2023-03-01)" DM_VERSION_EXTRA = "-ioctl (2025-04-28)"
DM_VERSION_MAJOR = 0x4 DM_VERSION_MAJOR = 0x4
DM_VERSION_MINOR = 0x30 DM_VERSION_MINOR = 0x32
DM_VERSION_PATCHLEVEL = 0x0 DM_VERSION_PATCHLEVEL = 0x0
DT_ADDRRNGHI = 0x6ffffeff
DT_ADDRRNGLO = 0x6ffffe00
DT_BLK = 0x6 DT_BLK = 0x6
DT_CHR = 0x2 DT_CHR = 0x2
DT_DEBUG = 0x15
DT_DIR = 0x4 DT_DIR = 0x4
DT_ENCODING = 0x20
DT_FIFO = 0x1 DT_FIFO = 0x1
DT_FINI = 0xd
DT_FLAGS_1 = 0x6ffffffb
DT_GNU_HASH = 0x6ffffef5
DT_HASH = 0x4
DT_HIOS = 0x6ffff000
DT_HIPROC = 0x7fffffff
DT_INIT = 0xc
DT_JMPREL = 0x17
DT_LNK = 0xa DT_LNK = 0xa
DT_LOOS = 0x6000000d
DT_LOPROC = 0x70000000
DT_NEEDED = 0x1
DT_NULL = 0x0
DT_PLTGOT = 0x3
DT_PLTREL = 0x14
DT_PLTRELSZ = 0x2
DT_REG = 0x8 DT_REG = 0x8
DT_REL = 0x11
DT_RELA = 0x7
DT_RELACOUNT = 0x6ffffff9
DT_RELAENT = 0x9
DT_RELASZ = 0x8
DT_RELCOUNT = 0x6ffffffa
DT_RELENT = 0x13
DT_RELSZ = 0x12
DT_RPATH = 0xf
DT_SOCK = 0xc DT_SOCK = 0xc
DT_SONAME = 0xe
DT_STRSZ = 0xa
DT_STRTAB = 0x5
DT_SYMBOLIC = 0x10
DT_SYMENT = 0xb
DT_SYMTAB = 0x6
DT_TEXTREL = 0x16
DT_UNKNOWN = 0x0 DT_UNKNOWN = 0x0
DT_VALRNGHI = 0x6ffffdff
DT_VALRNGLO = 0x6ffffd00
DT_VERDEF = 0x6ffffffc
DT_VERDEFNUM = 0x6ffffffd
DT_VERNEED = 0x6ffffffe
DT_VERNEEDNUM = 0x6fffffff
DT_VERSYM = 0x6ffffff0
DT_WHT = 0xe DT_WHT = 0xe
ECHO = 0x8 ECHO = 0x8
ECRYPTFS_SUPER_MAGIC = 0xf15f ECRYPTFS_SUPER_MAGIC = 0xf15f
EFD_SEMAPHORE = 0x1 EFD_SEMAPHORE = 0x1
EFIVARFS_MAGIC = 0xde5e81e4 EFIVARFS_MAGIC = 0xde5e81e4
EFS_SUPER_MAGIC = 0x414a53 EFS_SUPER_MAGIC = 0x414a53
EI_CLASS = 0x4
EI_DATA = 0x5
EI_MAG0 = 0x0
EI_MAG1 = 0x1
EI_MAG2 = 0x2
EI_MAG3 = 0x3
EI_NIDENT = 0x10
EI_OSABI = 0x7
EI_PAD = 0x8
EI_VERSION = 0x6
ELFCLASS32 = 0x1
ELFCLASS64 = 0x2
ELFCLASSNONE = 0x0
ELFCLASSNUM = 0x3
ELFDATA2LSB = 0x1
ELFDATA2MSB = 0x2
ELFDATANONE = 0x0
ELFMAG = "\177ELF"
ELFMAG0 = 0x7f
ELFMAG1 = 'E'
ELFMAG2 = 'L'
ELFMAG3 = 'F'
ELFOSABI_LINUX = 0x3
ELFOSABI_NONE = 0x0
EM_386 = 0x3 EM_386 = 0x3
EM_486 = 0x6 EM_486 = 0x6
EM_68K = 0x4 EM_68K = 0x4
@ -936,11 +1008,10 @@ const (
EPOLL_CTL_MOD = 0x3 EPOLL_CTL_MOD = 0x3
EPOLL_IOC_TYPE = 0x8a EPOLL_IOC_TYPE = 0x8a
EROFS_SUPER_MAGIC_V1 = 0xe0f5e1e2 EROFS_SUPER_MAGIC_V1 = 0xe0f5e1e2
ESP_V4_FLOW = 0xa
ESP_V6_FLOW = 0xc
ETHER_FLOW = 0x12
ETHTOOL_BUSINFO_LEN = 0x20 ETHTOOL_BUSINFO_LEN = 0x20
ETHTOOL_EROMVERS_LEN = 0x20 ETHTOOL_EROMVERS_LEN = 0x20
ETHTOOL_FAMILY_NAME = "ethtool"
ETHTOOL_FAMILY_VERSION = 0x1
ETHTOOL_FEC_AUTO = 0x2 ETHTOOL_FEC_AUTO = 0x2
ETHTOOL_FEC_BASER = 0x10 ETHTOOL_FEC_BASER = 0x10
ETHTOOL_FEC_LLRS = 0x20 ETHTOOL_FEC_LLRS = 0x20
@ -1147,14 +1218,24 @@ const (
ETH_P_WCCP = 0x883e ETH_P_WCCP = 0x883e
ETH_P_X25 = 0x805 ETH_P_X25 = 0x805
ETH_P_XDSA = 0xf8 ETH_P_XDSA = 0xf8
ET_CORE = 0x4
ET_DYN = 0x3
ET_EXEC = 0x2
ET_HIPROC = 0xffff
ET_LOPROC = 0xff00
ET_NONE = 0x0
ET_REL = 0x1
EV_ABS = 0x3 EV_ABS = 0x3
EV_CNT = 0x20 EV_CNT = 0x20
EV_CURRENT = 0x1
EV_FF = 0x15 EV_FF = 0x15
EV_FF_STATUS = 0x17 EV_FF_STATUS = 0x17
EV_KEY = 0x1 EV_KEY = 0x1
EV_LED = 0x11 EV_LED = 0x11
EV_MAX = 0x1f EV_MAX = 0x1f
EV_MSC = 0x4 EV_MSC = 0x4
EV_NONE = 0x0
EV_NUM = 0x2
EV_PWR = 0x16 EV_PWR = 0x16
EV_REL = 0x2 EV_REL = 0x2
EV_REP = 0x14 EV_REP = 0x14
@ -1203,13 +1284,18 @@ const (
FAN_DENY = 0x2 FAN_DENY = 0x2
FAN_ENABLE_AUDIT = 0x40 FAN_ENABLE_AUDIT = 0x40
FAN_EPIDFD = -0x2 FAN_EPIDFD = -0x2
FAN_ERRNO_BITS = 0x8
FAN_ERRNO_MASK = 0xff
FAN_ERRNO_SHIFT = 0x18
FAN_EVENT_INFO_TYPE_DFID = 0x3 FAN_EVENT_INFO_TYPE_DFID = 0x3
FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2 FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2
FAN_EVENT_INFO_TYPE_ERROR = 0x5 FAN_EVENT_INFO_TYPE_ERROR = 0x5
FAN_EVENT_INFO_TYPE_FID = 0x1 FAN_EVENT_INFO_TYPE_FID = 0x1
FAN_EVENT_INFO_TYPE_MNT = 0x7
FAN_EVENT_INFO_TYPE_NEW_DFID_NAME = 0xc FAN_EVENT_INFO_TYPE_NEW_DFID_NAME = 0xc
FAN_EVENT_INFO_TYPE_OLD_DFID_NAME = 0xa FAN_EVENT_INFO_TYPE_OLD_DFID_NAME = 0xa
FAN_EVENT_INFO_TYPE_PIDFD = 0x4 FAN_EVENT_INFO_TYPE_PIDFD = 0x4
FAN_EVENT_INFO_TYPE_RANGE = 0x6
FAN_EVENT_METADATA_LEN = 0x18 FAN_EVENT_METADATA_LEN = 0x18
FAN_EVENT_ON_CHILD = 0x8000000 FAN_EVENT_ON_CHILD = 0x8000000
FAN_FS_ERROR = 0x8000 FAN_FS_ERROR = 0x8000
@ -1224,9 +1310,12 @@ const (
FAN_MARK_IGNORED_SURV_MODIFY = 0x40 FAN_MARK_IGNORED_SURV_MODIFY = 0x40
FAN_MARK_IGNORE_SURV = 0x440 FAN_MARK_IGNORE_SURV = 0x440
FAN_MARK_INODE = 0x0 FAN_MARK_INODE = 0x0
FAN_MARK_MNTNS = 0x110
FAN_MARK_MOUNT = 0x10 FAN_MARK_MOUNT = 0x10
FAN_MARK_ONLYDIR = 0x8 FAN_MARK_ONLYDIR = 0x8
FAN_MARK_REMOVE = 0x2 FAN_MARK_REMOVE = 0x2
FAN_MNT_ATTACH = 0x1000000
FAN_MNT_DETACH = 0x2000000
FAN_MODIFY = 0x2 FAN_MODIFY = 0x2
FAN_MOVE = 0xc0 FAN_MOVE = 0xc0
FAN_MOVED_FROM = 0x40 FAN_MOVED_FROM = 0x40
@ -1240,6 +1329,7 @@ const (
FAN_OPEN_EXEC = 0x1000 FAN_OPEN_EXEC = 0x1000
FAN_OPEN_EXEC_PERM = 0x40000 FAN_OPEN_EXEC_PERM = 0x40000
FAN_OPEN_PERM = 0x10000 FAN_OPEN_PERM = 0x10000
FAN_PRE_ACCESS = 0x100000
FAN_Q_OVERFLOW = 0x4000 FAN_Q_OVERFLOW = 0x4000
FAN_RENAME = 0x10000000 FAN_RENAME = 0x10000000
FAN_REPORT_DFID_NAME = 0xc00 FAN_REPORT_DFID_NAME = 0xc00
@ -1247,6 +1337,7 @@ const (
FAN_REPORT_DIR_FID = 0x400 FAN_REPORT_DIR_FID = 0x400
FAN_REPORT_FD_ERROR = 0x2000 FAN_REPORT_FD_ERROR = 0x2000
FAN_REPORT_FID = 0x200 FAN_REPORT_FID = 0x200
FAN_REPORT_MNT = 0x4000
FAN_REPORT_NAME = 0x800 FAN_REPORT_NAME = 0x800
FAN_REPORT_PIDFD = 0x80 FAN_REPORT_PIDFD = 0x80
FAN_REPORT_TARGET_FID = 0x1000 FAN_REPORT_TARGET_FID = 0x1000
@ -1266,6 +1357,7 @@ const (
FIB_RULE_PERMANENT = 0x1 FIB_RULE_PERMANENT = 0x1
FIB_RULE_UNRESOLVED = 0x4 FIB_RULE_UNRESOLVED = 0x4
FIDEDUPERANGE = 0xc0189436 FIDEDUPERANGE = 0xc0189436
FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED = 0x1
FSCRYPT_KEY_DESCRIPTOR_SIZE = 0x8 FSCRYPT_KEY_DESCRIPTOR_SIZE = 0x8
FSCRYPT_KEY_DESC_PREFIX = "fscrypt:" FSCRYPT_KEY_DESC_PREFIX = "fscrypt:"
FSCRYPT_KEY_DESC_PREFIX_SIZE = 0x8 FSCRYPT_KEY_DESC_PREFIX_SIZE = 0x8
@ -1523,6 +1615,8 @@ const (
IN_OPEN = 0x20 IN_OPEN = 0x20
IN_Q_OVERFLOW = 0x4000 IN_Q_OVERFLOW = 0x4000
IN_UNMOUNT = 0x2000 IN_UNMOUNT = 0x2000
IOCTL_MEI_CONNECT_CLIENT = 0xc0104801
IOCTL_MEI_CONNECT_CLIENT_VTAG = 0xc0144804
IPPROTO_AH = 0x33 IPPROTO_AH = 0x33
IPPROTO_BEETPH = 0x5e IPPROTO_BEETPH = 0x5e
IPPROTO_COMP = 0x6c IPPROTO_COMP = 0x6c
@ -1574,7 +1668,6 @@ const (
IPV6_DONTFRAG = 0x3e IPV6_DONTFRAG = 0x3e
IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DROP_MEMBERSHIP = 0x15
IPV6_DSTOPTS = 0x3b IPV6_DSTOPTS = 0x3b
IPV6_FLOW = 0x11
IPV6_FREEBIND = 0x4e IPV6_FREEBIND = 0x4e
IPV6_HDRINCL = 0x24 IPV6_HDRINCL = 0x24
IPV6_HOPLIMIT = 0x34 IPV6_HOPLIMIT = 0x34
@ -1625,7 +1718,6 @@ const (
IPV6_TRANSPARENT = 0x4b IPV6_TRANSPARENT = 0x4b
IPV6_UNICAST_HOPS = 0x10 IPV6_UNICAST_HOPS = 0x10
IPV6_UNICAST_IF = 0x4c IPV6_UNICAST_IF = 0x4c
IPV6_USER_FLOW = 0xe
IPV6_V6ONLY = 0x1a IPV6_V6ONLY = 0x1a
IPV6_VERSION = 0x60 IPV6_VERSION = 0x60
IPV6_VERSION_MASK = 0xf0 IPV6_VERSION_MASK = 0xf0
@ -1687,7 +1779,6 @@ const (
IP_TTL = 0x2 IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25 IP_UNBLOCK_SOURCE = 0x25
IP_UNICAST_IF = 0x32 IP_UNICAST_IF = 0x32
IP_USER_FLOW = 0xd
IP_XFRM_POLICY = 0x11 IP_XFRM_POLICY = 0x11
ISOFS_SUPER_MAGIC = 0x9660 ISOFS_SUPER_MAGIC = 0x9660
ISTRIP = 0x20 ISTRIP = 0x20
@ -1809,7 +1900,11 @@ const (
LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2 LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2
LANDLOCK_ACCESS_NET_BIND_TCP = 0x1 LANDLOCK_ACCESS_NET_BIND_TCP = 0x1
LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2 LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2
LANDLOCK_CREATE_RULESET_ERRATA = 0x2
LANDLOCK_CREATE_RULESET_VERSION = 0x1 LANDLOCK_CREATE_RULESET_VERSION = 0x1
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON = 0x2
LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF = 0x1
LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF = 0x4
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = 0x1 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = 0x1
LANDLOCK_SCOPE_SIGNAL = 0x2 LANDLOCK_SCOPE_SIGNAL = 0x2
LINUX_REBOOT_CMD_CAD_OFF = 0x0 LINUX_REBOOT_CMD_CAD_OFF = 0x0
@ -2259,7 +2354,167 @@ const (
NLM_F_REPLACE = 0x100 NLM_F_REPLACE = 0x100
NLM_F_REQUEST = 0x1 NLM_F_REQUEST = 0x1
NLM_F_ROOT = 0x100 NLM_F_ROOT = 0x100
NN_386_IOPERM = "LINUX"
NN_386_TLS = "LINUX"
NN_ARC_V2 = "LINUX"
NN_ARM_FPMR = "LINUX"
NN_ARM_GCS = "LINUX"
NN_ARM_HW_BREAK = "LINUX"
NN_ARM_HW_WATCH = "LINUX"
NN_ARM_PACA_KEYS = "LINUX"
NN_ARM_PACG_KEYS = "LINUX"
NN_ARM_PAC_ENABLED_KEYS = "LINUX"
NN_ARM_PAC_MASK = "LINUX"
NN_ARM_POE = "LINUX"
NN_ARM_SSVE = "LINUX"
NN_ARM_SVE = "LINUX"
NN_ARM_SYSTEM_CALL = "LINUX"
NN_ARM_TAGGED_ADDR_CTRL = "LINUX"
NN_ARM_TLS = "LINUX"
NN_ARM_VFP = "LINUX"
NN_ARM_ZA = "LINUX"
NN_ARM_ZT = "LINUX"
NN_AUXV = "CORE"
NN_FILE = "CORE"
NN_GNU_PROPERTY_TYPE_0 = "GNU"
NN_LOONGARCH_CPUCFG = "LINUX"
NN_LOONGARCH_CSR = "LINUX"
NN_LOONGARCH_HW_BREAK = "LINUX"
NN_LOONGARCH_HW_WATCH = "LINUX"
NN_LOONGARCH_LASX = "LINUX"
NN_LOONGARCH_LBT = "LINUX"
NN_LOONGARCH_LSX = "LINUX"
NN_MIPS_DSP = "LINUX"
NN_MIPS_FP_MODE = "LINUX"
NN_MIPS_MSA = "LINUX"
NN_PPC_DEXCR = "LINUX"
NN_PPC_DSCR = "LINUX"
NN_PPC_EBB = "LINUX"
NN_PPC_HASHKEYR = "LINUX"
NN_PPC_PKEY = "LINUX"
NN_PPC_PMU = "LINUX"
NN_PPC_PPR = "LINUX"
NN_PPC_SPE = "LINUX"
NN_PPC_TAR = "LINUX"
NN_PPC_TM_CDSCR = "LINUX"
NN_PPC_TM_CFPR = "LINUX"
NN_PPC_TM_CGPR = "LINUX"
NN_PPC_TM_CPPR = "LINUX"
NN_PPC_TM_CTAR = "LINUX"
NN_PPC_TM_CVMX = "LINUX"
NN_PPC_TM_CVSX = "LINUX"
NN_PPC_TM_SPR = "LINUX"
NN_PPC_VMX = "LINUX"
NN_PPC_VSX = "LINUX"
NN_PRFPREG = "CORE"
NN_PRPSINFO = "CORE"
NN_PRSTATUS = "CORE"
NN_PRXFPREG = "LINUX"
NN_RISCV_CSR = "LINUX"
NN_RISCV_TAGGED_ADDR_CTRL = "LINUX"
NN_RISCV_VECTOR = "LINUX"
NN_S390_CTRS = "LINUX"
NN_S390_GS_BC = "LINUX"
NN_S390_GS_CB = "LINUX"
NN_S390_HIGH_GPRS = "LINUX"
NN_S390_LAST_BREAK = "LINUX"
NN_S390_PREFIX = "LINUX"
NN_S390_PV_CPU_DATA = "LINUX"
NN_S390_RI_CB = "LINUX"
NN_S390_SYSTEM_CALL = "LINUX"
NN_S390_TDB = "LINUX"
NN_S390_TIMER = "LINUX"
NN_S390_TODCMP = "LINUX"
NN_S390_TODPREG = "LINUX"
NN_S390_VXRS_HIGH = "LINUX"
NN_S390_VXRS_LOW = "LINUX"
NN_SIGINFO = "CORE"
NN_TASKSTRUCT = "CORE"
NN_VMCOREDD = "LINUX"
NN_X86_SHSTK = "LINUX"
NN_X86_XSAVE_LAYOUT = "LINUX"
NN_X86_XSTATE = "LINUX"
NSFS_MAGIC = 0x6e736673 NSFS_MAGIC = 0x6e736673
NT_386_IOPERM = 0x201
NT_386_TLS = 0x200
NT_ARC_V2 = 0x600
NT_ARM_FPMR = 0x40e
NT_ARM_GCS = 0x410
NT_ARM_HW_BREAK = 0x402
NT_ARM_HW_WATCH = 0x403
NT_ARM_PACA_KEYS = 0x407
NT_ARM_PACG_KEYS = 0x408
NT_ARM_PAC_ENABLED_KEYS = 0x40a
NT_ARM_PAC_MASK = 0x406
NT_ARM_POE = 0x40f
NT_ARM_SSVE = 0x40b
NT_ARM_SVE = 0x405
NT_ARM_SYSTEM_CALL = 0x404
NT_ARM_TAGGED_ADDR_CTRL = 0x409
NT_ARM_TLS = 0x401
NT_ARM_VFP = 0x400
NT_ARM_ZA = 0x40c
NT_ARM_ZT = 0x40d
NT_AUXV = 0x6
NT_FILE = 0x46494c45
NT_GNU_PROPERTY_TYPE_0 = 0x5
NT_LOONGARCH_CPUCFG = 0xa00
NT_LOONGARCH_CSR = 0xa01
NT_LOONGARCH_HW_BREAK = 0xa05
NT_LOONGARCH_HW_WATCH = 0xa06
NT_LOONGARCH_LASX = 0xa03
NT_LOONGARCH_LBT = 0xa04
NT_LOONGARCH_LSX = 0xa02
NT_MIPS_DSP = 0x800
NT_MIPS_FP_MODE = 0x801
NT_MIPS_MSA = 0x802
NT_PPC_DEXCR = 0x111
NT_PPC_DSCR = 0x105
NT_PPC_EBB = 0x106
NT_PPC_HASHKEYR = 0x112
NT_PPC_PKEY = 0x110
NT_PPC_PMU = 0x107
NT_PPC_PPR = 0x104
NT_PPC_SPE = 0x101
NT_PPC_TAR = 0x103
NT_PPC_TM_CDSCR = 0x10f
NT_PPC_TM_CFPR = 0x109
NT_PPC_TM_CGPR = 0x108
NT_PPC_TM_CPPR = 0x10e
NT_PPC_TM_CTAR = 0x10d
NT_PPC_TM_CVMX = 0x10a
NT_PPC_TM_CVSX = 0x10b
NT_PPC_TM_SPR = 0x10c
NT_PPC_VMX = 0x100
NT_PPC_VSX = 0x102
NT_PRFPREG = 0x2
NT_PRPSINFO = 0x3
NT_PRSTATUS = 0x1
NT_PRXFPREG = 0x46e62b7f
NT_RISCV_CSR = 0x900
NT_RISCV_TAGGED_ADDR_CTRL = 0x902
NT_RISCV_VECTOR = 0x901
NT_S390_CTRS = 0x304
NT_S390_GS_BC = 0x30c
NT_S390_GS_CB = 0x30b
NT_S390_HIGH_GPRS = 0x300
NT_S390_LAST_BREAK = 0x306
NT_S390_PREFIX = 0x305
NT_S390_PV_CPU_DATA = 0x30e
NT_S390_RI_CB = 0x30d
NT_S390_SYSTEM_CALL = 0x307
NT_S390_TDB = 0x308
NT_S390_TIMER = 0x301
NT_S390_TODCMP = 0x302
NT_S390_TODPREG = 0x303
NT_S390_VXRS_HIGH = 0x30a
NT_S390_VXRS_LOW = 0x309
NT_SIGINFO = 0x53494749
NT_TASKSTRUCT = 0x4
NT_VMCOREDD = 0x700
NT_X86_SHSTK = 0x204
NT_X86_XSAVE_LAYOUT = 0x205
NT_X86_XSTATE = 0x202
OCFS2_SUPER_MAGIC = 0x7461636f OCFS2_SUPER_MAGIC = 0x7461636f
OCRNL = 0x8 OCRNL = 0x8
OFDEL = 0x80 OFDEL = 0x80
@ -2446,6 +2701,59 @@ const (
PERF_RECORD_MISC_USER = 0x2 PERF_RECORD_MISC_USER = 0x2
PERF_SAMPLE_BRANCH_PLM_ALL = 0x7 PERF_SAMPLE_BRANCH_PLM_ALL = 0x7
PERF_SAMPLE_WEIGHT_TYPE = 0x1004000 PERF_SAMPLE_WEIGHT_TYPE = 0x1004000
PF_ALG = 0x26
PF_APPLETALK = 0x5
PF_ASH = 0x12
PF_ATMPVC = 0x8
PF_ATMSVC = 0x14
PF_AX25 = 0x3
PF_BLUETOOTH = 0x1f
PF_BRIDGE = 0x7
PF_CAIF = 0x25
PF_CAN = 0x1d
PF_DECnet = 0xc
PF_ECONET = 0x13
PF_FILE = 0x1
PF_IB = 0x1b
PF_IEEE802154 = 0x24
PF_INET = 0x2
PF_INET6 = 0xa
PF_IPX = 0x4
PF_IRDA = 0x17
PF_ISDN = 0x22
PF_IUCV = 0x20
PF_KCM = 0x29
PF_KEY = 0xf
PF_LLC = 0x1a
PF_LOCAL = 0x1
PF_MAX = 0x2e
PF_MCTP = 0x2d
PF_MPLS = 0x1c
PF_NETBEUI = 0xd
PF_NETLINK = 0x10
PF_NETROM = 0x6
PF_NFC = 0x27
PF_PACKET = 0x11
PF_PHONET = 0x23
PF_PPPOX = 0x18
PF_QIPCRTR = 0x2a
PF_R = 0x4
PF_RDS = 0x15
PF_ROSE = 0xb
PF_ROUTE = 0x10
PF_RXRPC = 0x21
PF_SECURITY = 0xe
PF_SMC = 0x2b
PF_SNA = 0x16
PF_TIPC = 0x1e
PF_UNIX = 0x1
PF_UNSPEC = 0x0
PF_VSOCK = 0x28
PF_W = 0x2
PF_WANPIPE = 0x19
PF_X = 0x1
PF_X25 = 0x9
PF_XDP = 0x2c
PID_FS_MAGIC = 0x50494446 PID_FS_MAGIC = 0x50494446
PIPEFS_MAGIC = 0x50495045 PIPEFS_MAGIC = 0x50495045
PPPIOCGNPMODE = 0xc008744c PPPIOCGNPMODE = 0xc008744c
@ -2485,6 +2793,10 @@ const (
PR_FP_EXC_UND = 0x40000 PR_FP_EXC_UND = 0x40000
PR_FP_MODE_FR = 0x1 PR_FP_MODE_FR = 0x1
PR_FP_MODE_FRE = 0x2 PR_FP_MODE_FRE = 0x2
PR_FUTEX_HASH = 0x4e
PR_FUTEX_HASH_GET_IMMUTABLE = 0x3
PR_FUTEX_HASH_GET_SLOTS = 0x2
PR_FUTEX_HASH_SET_SLOTS = 0x1
PR_GET_AUXV = 0x41555856 PR_GET_AUXV = 0x41555856
PR_GET_CHILD_SUBREAPER = 0x25 PR_GET_CHILD_SUBREAPER = 0x25
PR_GET_DUMPABLE = 0x3 PR_GET_DUMPABLE = 0x3
@ -2644,6 +2956,10 @@ const (
PR_TAGGED_ADDR_ENABLE = 0x1 PR_TAGGED_ADDR_ENABLE = 0x1
PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_DISABLE = 0x1f
PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TASK_PERF_EVENTS_ENABLE = 0x20
PR_TIMER_CREATE_RESTORE_IDS = 0x4d
PR_TIMER_CREATE_RESTORE_IDS_GET = 0x2
PR_TIMER_CREATE_RESTORE_IDS_OFF = 0x0
PR_TIMER_CREATE_RESTORE_IDS_ON = 0x1
PR_TIMING_STATISTICAL = 0x0 PR_TIMING_STATISTICAL = 0x0
PR_TIMING_TIMESTAMP = 0x1 PR_TIMING_TIMESTAMP = 0x1
PR_TSC_ENABLE = 0x1 PR_TSC_ENABLE = 0x1
@ -2724,6 +3040,7 @@ const (
PTRACE_SETREGSET = 0x4205 PTRACE_SETREGSET = 0x4205
PTRACE_SETSIGINFO = 0x4203 PTRACE_SETSIGINFO = 0x4203
PTRACE_SETSIGMASK = 0x420b PTRACE_SETSIGMASK = 0x420b
PTRACE_SET_SYSCALL_INFO = 0x4212
PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG = 0x4210 PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG = 0x4210
PTRACE_SINGLESTEP = 0x9 PTRACE_SINGLESTEP = 0x9
PTRACE_SYSCALL = 0x18 PTRACE_SYSCALL = 0x18
@ -2732,6 +3049,23 @@ const (
PTRACE_SYSCALL_INFO_NONE = 0x0 PTRACE_SYSCALL_INFO_NONE = 0x0
PTRACE_SYSCALL_INFO_SECCOMP = 0x3 PTRACE_SYSCALL_INFO_SECCOMP = 0x3
PTRACE_TRACEME = 0x0 PTRACE_TRACEME = 0x0
PT_AARCH64_MEMTAG_MTE = 0x70000002
PT_DYNAMIC = 0x2
PT_GNU_EH_FRAME = 0x6474e550
PT_GNU_PROPERTY = 0x6474e553
PT_GNU_RELRO = 0x6474e552
PT_GNU_STACK = 0x6474e551
PT_HIOS = 0x6fffffff
PT_HIPROC = 0x7fffffff
PT_INTERP = 0x3
PT_LOAD = 0x1
PT_LOOS = 0x60000000
PT_LOPROC = 0x70000000
PT_NOTE = 0x4
PT_NULL = 0x0
PT_PHDR = 0x6
PT_SHLIB = 0x5
PT_TLS = 0x7
P_ALL = 0x0 P_ALL = 0x0
P_PGID = 0x2 P_PGID = 0x2
P_PID = 0x1 P_PID = 0x1
@ -2787,7 +3121,7 @@ const (
RTAX_UNSPEC = 0x0 RTAX_UNSPEC = 0x0
RTAX_WINDOW = 0x3 RTAX_WINDOW = 0x3
RTA_ALIGNTO = 0x4 RTA_ALIGNTO = 0x4
RTA_MAX = 0x1e RTA_MAX = 0x1f
RTCF_DIRECTSRC = 0x4000000 RTCF_DIRECTSRC = 0x4000000
RTCF_DOREDIRECT = 0x1000000 RTCF_DOREDIRECT = 0x1000000
RTCF_LOG = 0x2000000 RTCF_LOG = 0x2000000
@ -2864,10 +3198,12 @@ const (
RTM_DELACTION = 0x31 RTM_DELACTION = 0x31
RTM_DELADDR = 0x15 RTM_DELADDR = 0x15
RTM_DELADDRLABEL = 0x49 RTM_DELADDRLABEL = 0x49
RTM_DELANYCAST = 0x3d
RTM_DELCHAIN = 0x65 RTM_DELCHAIN = 0x65
RTM_DELLINK = 0x11 RTM_DELLINK = 0x11
RTM_DELLINKPROP = 0x6d RTM_DELLINKPROP = 0x6d
RTM_DELMDB = 0x55 RTM_DELMDB = 0x55
RTM_DELMULTICAST = 0x39
RTM_DELNEIGH = 0x1d RTM_DELNEIGH = 0x1d
RTM_DELNETCONF = 0x51 RTM_DELNETCONF = 0x51
RTM_DELNEXTHOP = 0x69 RTM_DELNEXTHOP = 0x69
@ -2917,11 +3253,13 @@ const (
RTM_NEWACTION = 0x30 RTM_NEWACTION = 0x30
RTM_NEWADDR = 0x14 RTM_NEWADDR = 0x14
RTM_NEWADDRLABEL = 0x48 RTM_NEWADDRLABEL = 0x48
RTM_NEWANYCAST = 0x3c
RTM_NEWCACHEREPORT = 0x60 RTM_NEWCACHEREPORT = 0x60
RTM_NEWCHAIN = 0x64 RTM_NEWCHAIN = 0x64
RTM_NEWLINK = 0x10 RTM_NEWLINK = 0x10
RTM_NEWLINKPROP = 0x6c RTM_NEWLINKPROP = 0x6c
RTM_NEWMDB = 0x54 RTM_NEWMDB = 0x54
RTM_NEWMULTICAST = 0x38
RTM_NEWNDUSEROPT = 0x44 RTM_NEWNDUSEROPT = 0x44
RTM_NEWNEIGH = 0x1c RTM_NEWNEIGH = 0x1c
RTM_NEWNEIGHTBL = 0x40 RTM_NEWNEIGHTBL = 0x40
@ -2970,6 +3308,7 @@ const (
RTPROT_NTK = 0xf RTPROT_NTK = 0xf
RTPROT_OPENR = 0x63 RTPROT_OPENR = 0x63
RTPROT_OSPF = 0xbc RTPROT_OSPF = 0xbc
RTPROT_OVN = 0x54
RTPROT_RA = 0x9 RTPROT_RA = 0x9
RTPROT_REDIRECT = 0x1 RTPROT_REDIRECT = 0x1
RTPROT_RIP = 0xbd RTPROT_RIP = 0xbd
@ -2987,11 +3326,12 @@ const (
RUSAGE_THREAD = 0x1 RUSAGE_THREAD = 0x1
RWF_APPEND = 0x10 RWF_APPEND = 0x10
RWF_ATOMIC = 0x40 RWF_ATOMIC = 0x40
RWF_DONTCACHE = 0x80
RWF_DSYNC = 0x2 RWF_DSYNC = 0x2
RWF_HIPRI = 0x1 RWF_HIPRI = 0x1
RWF_NOAPPEND = 0x20 RWF_NOAPPEND = 0x20
RWF_NOWAIT = 0x8 RWF_NOWAIT = 0x8
RWF_SUPPORTED = 0x7f RWF_SUPPORTED = 0xff
RWF_SYNC = 0x4 RWF_SYNC = 0x4
RWF_WRITE_LIFE_NOT_SET = 0x0 RWF_WRITE_LIFE_NOT_SET = 0x0
SCHED_BATCH = 0x3 SCHED_BATCH = 0x3
@ -3059,6 +3399,47 @@ const (
SEEK_MAX = 0x4 SEEK_MAX = 0x4
SEEK_SET = 0x0 SEEK_SET = 0x0
SELINUX_MAGIC = 0xf97cff8c SELINUX_MAGIC = 0xf97cff8c
SHF_ALLOC = 0x2
SHF_EXCLUDE = 0x8000000
SHF_EXECINSTR = 0x4
SHF_GROUP = 0x200
SHF_INFO_LINK = 0x40
SHF_LINK_ORDER = 0x80
SHF_MASKOS = 0xff00000
SHF_MASKPROC = 0xf0000000
SHF_MERGE = 0x10
SHF_ORDERED = 0x4000000
SHF_OS_NONCONFORMING = 0x100
SHF_RELA_LIVEPATCH = 0x100000
SHF_RO_AFTER_INIT = 0x200000
SHF_STRINGS = 0x20
SHF_TLS = 0x400
SHF_WRITE = 0x1
SHN_ABS = 0xfff1
SHN_COMMON = 0xfff2
SHN_HIPROC = 0xff1f
SHN_HIRESERVE = 0xffff
SHN_LIVEPATCH = 0xff20
SHN_LOPROC = 0xff00
SHN_LORESERVE = 0xff00
SHN_UNDEF = 0x0
SHT_DYNAMIC = 0x6
SHT_DYNSYM = 0xb
SHT_HASH = 0x5
SHT_HIPROC = 0x7fffffff
SHT_HIUSER = 0xffffffff
SHT_LOPROC = 0x70000000
SHT_LOUSER = 0x80000000
SHT_NOBITS = 0x8
SHT_NOTE = 0x7
SHT_NULL = 0x0
SHT_NUM = 0xc
SHT_PROGBITS = 0x1
SHT_REL = 0x9
SHT_RELA = 0x4
SHT_SHLIB = 0xa
SHT_STRTAB = 0x3
SHT_SYMTAB = 0x2
SHUT_RD = 0x0 SHUT_RD = 0x0
SHUT_RDWR = 0x2 SHUT_RDWR = 0x2
SHUT_WR = 0x1 SHUT_WR = 0x1
@ -3271,6 +3652,7 @@ const (
STATX_BTIME = 0x800 STATX_BTIME = 0x800
STATX_CTIME = 0x80 STATX_CTIME = 0x80
STATX_DIOALIGN = 0x2000 STATX_DIOALIGN = 0x2000
STATX_DIO_READ_ALIGN = 0x20000
STATX_GID = 0x10 STATX_GID = 0x10
STATX_INO = 0x100 STATX_INO = 0x100
STATX_MNT_ID = 0x1000 STATX_MNT_ID = 0x1000
@ -3284,6 +3666,16 @@ const (
STATX_UID = 0x8 STATX_UID = 0x8
STATX_WRITE_ATOMIC = 0x10000 STATX_WRITE_ATOMIC = 0x10000
STATX__RESERVED = 0x80000000 STATX__RESERVED = 0x80000000
STB_GLOBAL = 0x1
STB_LOCAL = 0x0
STB_WEAK = 0x2
STT_COMMON = 0x5
STT_FILE = 0x4
STT_FUNC = 0x2
STT_NOTYPE = 0x0
STT_OBJECT = 0x1
STT_SECTION = 0x3
STT_TLS = 0x6
SYNC_FILE_RANGE_WAIT_AFTER = 0x4 SYNC_FILE_RANGE_WAIT_AFTER = 0x4
SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 SYNC_FILE_RANGE_WAIT_BEFORE = 0x1
SYNC_FILE_RANGE_WRITE = 0x2 SYNC_FILE_RANGE_WRITE = 0x2
@ -3322,7 +3714,7 @@ const (
TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_NAME = "TASKSTATS"
TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_GENL_VERSION = 0x1
TASKSTATS_TYPE_MAX = 0x6 TASKSTATS_TYPE_MAX = 0x6
TASKSTATS_VERSION = 0xe TASKSTATS_VERSION = 0x10
TCIFLUSH = 0x0 TCIFLUSH = 0x0
TCIOFF = 0x2 TCIOFF = 0x2
TCIOFLUSH = 0x2 TCIOFLUSH = 0x2
@ -3392,8 +3784,6 @@ const (
TCP_TX_DELAY = 0x25 TCP_TX_DELAY = 0x25
TCP_ULP = 0x1f TCP_ULP = 0x1f
TCP_USER_TIMEOUT = 0x12 TCP_USER_TIMEOUT = 0x12
TCP_V4_FLOW = 0x1
TCP_V6_FLOW = 0x5
TCP_WINDOW_CLAMP = 0xa TCP_WINDOW_CLAMP = 0xa
TCP_ZEROCOPY_RECEIVE = 0x23 TCP_ZEROCOPY_RECEIVE = 0x23
TFD_TIMER_ABSTIME = 0x1 TFD_TIMER_ABSTIME = 0x1
@ -3503,6 +3893,7 @@ const (
TP_STATUS_WRONG_FORMAT = 0x4 TP_STATUS_WRONG_FORMAT = 0x4
TRACEFS_MAGIC = 0x74726163 TRACEFS_MAGIC = 0x74726163
TS_COMM_LEN = 0x20 TS_COMM_LEN = 0x20
UBI_IOCECNFO = 0xc01c6f06
UDF_SUPER_MAGIC = 0x15013346 UDF_SUPER_MAGIC = 0x15013346
UDP_CORK = 0x1 UDP_CORK = 0x1
UDP_ENCAP = 0x64 UDP_ENCAP = 0x64
@ -3515,14 +3906,14 @@ const (
UDP_NO_CHECK6_RX = 0x66 UDP_NO_CHECK6_RX = 0x66
UDP_NO_CHECK6_TX = 0x65 UDP_NO_CHECK6_TX = 0x65
UDP_SEGMENT = 0x67 UDP_SEGMENT = 0x67
UDP_V4_FLOW = 0x2
UDP_V6_FLOW = 0x6
UMOUNT_NOFOLLOW = 0x8 UMOUNT_NOFOLLOW = 0x8
USBDEVICE_SUPER_MAGIC = 0x9fa2 USBDEVICE_SUPER_MAGIC = 0x9fa2
UTIME_NOW = 0x3fffffff UTIME_NOW = 0x3fffffff
UTIME_OMIT = 0x3ffffffe UTIME_OMIT = 0x3ffffffe
V9FS_MAGIC = 0x1021997 V9FS_MAGIC = 0x1021997
VERASE = 0x2 VERASE = 0x2
VER_FLG_BASE = 0x1
VER_FLG_WEAK = 0x2
VINTR = 0x0 VINTR = 0x0
VKILL = 0x3 VKILL = 0x3
VLNEXT = 0xf VLNEXT = 0xf
@ -3559,7 +3950,7 @@ const (
WDIOS_TEMPPANIC = 0x4 WDIOS_TEMPPANIC = 0x4
WDIOS_UNKNOWN = -0x1 WDIOS_UNKNOWN = -0x1
WEXITED = 0x4 WEXITED = 0x4
WGALLOWEDIP_A_MAX = 0x3 WGALLOWEDIP_A_MAX = 0x4
WGDEVICE_A_MAX = 0x8 WGDEVICE_A_MAX = 0x8
WGPEER_A_MAX = 0xa WGPEER_A_MAX = 0xa
WG_CMD_MAX = 0x1 WG_CMD_MAX = 0x1
@ -3673,6 +4064,7 @@ const (
XDP_SHARED_UMEM = 0x1 XDP_SHARED_UMEM = 0x1
XDP_STATISTICS = 0x7 XDP_STATISTICS = 0x7
XDP_TXMD_FLAGS_CHECKSUM = 0x2 XDP_TXMD_FLAGS_CHECKSUM = 0x2
XDP_TXMD_FLAGS_LAUNCH_TIME = 0x4
XDP_TXMD_FLAGS_TIMESTAMP = 0x1 XDP_TXMD_FLAGS_TIMESTAMP = 0x1
XDP_TX_METADATA = 0x2 XDP_TX_METADATA = 0x2
XDP_TX_RING = 0x3 XDP_TX_RING = 0x3

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -115,6 +116,8 @@ const (
IEXTEN = 0x8000 IEXTEN = 0x8000
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x800 IN_NONBLOCK = 0x800
IOCTL_MEI_NOTIFY_GET = 0x80044803
IOCTL_MEI_NOTIFY_SET = 0x40044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
IPV6_FLOWINFO_MASK = 0xffffff0f IPV6_FLOWINFO_MASK = 0xffffff0f
IPV6_FLOWLABEL_MASK = 0xffff0f00 IPV6_FLOWLABEL_MASK = 0xffff0f00
@ -360,6 +363,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11
@ -372,6 +376,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x12 SO_RCVLOWAT = 0x12
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x14 SO_RCVTIMEO = 0x14
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x14 SO_RCVTIMEO_OLD = 0x14

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -115,6 +116,8 @@ const (
IEXTEN = 0x8000 IEXTEN = 0x8000
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x800 IN_NONBLOCK = 0x800
IOCTL_MEI_NOTIFY_GET = 0x80044803
IOCTL_MEI_NOTIFY_SET = 0x40044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
IPV6_FLOWINFO_MASK = 0xffffff0f IPV6_FLOWINFO_MASK = 0xffffff0f
IPV6_FLOWLABEL_MASK = 0xffff0f00 IPV6_FLOWLABEL_MASK = 0xffff0f00
@ -361,6 +364,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11
@ -373,6 +377,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x12 SO_RCVLOWAT = 0x12
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x14 SO_RCVTIMEO = 0x14
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x14 SO_RCVTIMEO_OLD = 0x14

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -114,6 +115,8 @@ const (
IEXTEN = 0x8000 IEXTEN = 0x8000
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x800 IN_NONBLOCK = 0x800
IOCTL_MEI_NOTIFY_GET = 0x80044803
IOCTL_MEI_NOTIFY_SET = 0x40044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
IPV6_FLOWINFO_MASK = 0xffffff0f IPV6_FLOWINFO_MASK = 0xffffff0f
IPV6_FLOWLABEL_MASK = 0xffff0f00 IPV6_FLOWLABEL_MASK = 0xffff0f00
@ -366,6 +369,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11
@ -378,6 +382,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x12 SO_RCVLOWAT = 0x12
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x14 SO_RCVTIMEO = 0x14
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x14 SO_RCVTIMEO_OLD = 0x14

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -119,6 +120,8 @@ const (
IEXTEN = 0x8000 IEXTEN = 0x8000
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x800 IN_NONBLOCK = 0x800
IOCTL_MEI_NOTIFY_GET = 0x80044803
IOCTL_MEI_NOTIFY_SET = 0x40044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
IPV6_FLOWINFO_MASK = 0xffffff0f IPV6_FLOWINFO_MASK = 0xffffff0f
IPV6_FLOWLABEL_MASK = 0xffff0f00 IPV6_FLOWLABEL_MASK = 0xffff0f00
@ -359,6 +362,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11
@ -371,6 +375,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x12 SO_RCVLOWAT = 0x12
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x14 SO_RCVTIMEO = 0x14
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x14 SO_RCVTIMEO_OLD = 0x14

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -115,6 +116,8 @@ const (
IEXTEN = 0x8000 IEXTEN = 0x8000
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x800 IN_NONBLOCK = 0x800
IOCTL_MEI_NOTIFY_GET = 0x80044803
IOCTL_MEI_NOTIFY_SET = 0x40044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
IPV6_FLOWINFO_MASK = 0xffffff0f IPV6_FLOWINFO_MASK = 0xffffff0f
IPV6_FLOWLABEL_MASK = 0xffff0f00 IPV6_FLOWLABEL_MASK = 0xffff0f00
@ -353,6 +356,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11
@ -365,6 +369,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x12 SO_RCVLOWAT = 0x12
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x14 SO_RCVTIMEO = 0x14
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x14 SO_RCVTIMEO_OLD = 0x14

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -114,6 +115,8 @@ const (
IEXTEN = 0x100 IEXTEN = 0x100
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x80 IN_NONBLOCK = 0x80
IOCTL_MEI_NOTIFY_GET = 0x40044803
IOCTL_MEI_NOTIFY_SET = 0x80044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
IPV6_FLOWINFO_MASK = 0xfffffff IPV6_FLOWINFO_MASK = 0xfffffff
IPV6_FLOWLABEL_MASK = 0xfffff IPV6_FLOWLABEL_MASK = 0xfffff
@ -359,6 +362,7 @@ const (
SO_OOBINLINE = 0x100 SO_OOBINLINE = 0x100
SO_PASSCRED = 0x11 SO_PASSCRED = 0x11
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x12 SO_PEERCRED = 0x12
@ -371,6 +375,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x1004 SO_RCVLOWAT = 0x1004
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x1006 SO_RCVTIMEO = 0x1006
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x1006 SO_RCVTIMEO_OLD = 0x1006

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -114,6 +115,8 @@ const (
IEXTEN = 0x100 IEXTEN = 0x100
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x80 IN_NONBLOCK = 0x80
IOCTL_MEI_NOTIFY_GET = 0x40044803
IOCTL_MEI_NOTIFY_SET = 0x80044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
IPV6_FLOWINFO_MASK = 0xfffffff IPV6_FLOWINFO_MASK = 0xfffffff
IPV6_FLOWLABEL_MASK = 0xfffff IPV6_FLOWLABEL_MASK = 0xfffff
@ -359,6 +362,7 @@ const (
SO_OOBINLINE = 0x100 SO_OOBINLINE = 0x100
SO_PASSCRED = 0x11 SO_PASSCRED = 0x11
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x12 SO_PEERCRED = 0x12
@ -371,6 +375,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x1004 SO_RCVLOWAT = 0x1004
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x1006 SO_RCVTIMEO = 0x1006
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x1006 SO_RCVTIMEO_OLD = 0x1006

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -114,6 +115,8 @@ const (
IEXTEN = 0x100 IEXTEN = 0x100
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x80 IN_NONBLOCK = 0x80
IOCTL_MEI_NOTIFY_GET = 0x40044803
IOCTL_MEI_NOTIFY_SET = 0x80044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
IPV6_FLOWINFO_MASK = 0xffffff0f IPV6_FLOWINFO_MASK = 0xffffff0f
IPV6_FLOWLABEL_MASK = 0xffff0f00 IPV6_FLOWLABEL_MASK = 0xffff0f00
@ -359,6 +362,7 @@ const (
SO_OOBINLINE = 0x100 SO_OOBINLINE = 0x100
SO_PASSCRED = 0x11 SO_PASSCRED = 0x11
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x12 SO_PEERCRED = 0x12
@ -371,6 +375,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x1004 SO_RCVLOWAT = 0x1004
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x1006 SO_RCVTIMEO = 0x1006
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x1006 SO_RCVTIMEO_OLD = 0x1006

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -114,6 +115,8 @@ const (
IEXTEN = 0x100 IEXTEN = 0x100
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x80 IN_NONBLOCK = 0x80
IOCTL_MEI_NOTIFY_GET = 0x40044803
IOCTL_MEI_NOTIFY_SET = 0x80044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
IPV6_FLOWINFO_MASK = 0xffffff0f IPV6_FLOWINFO_MASK = 0xffffff0f
IPV6_FLOWLABEL_MASK = 0xffff0f00 IPV6_FLOWLABEL_MASK = 0xffff0f00
@ -359,6 +362,7 @@ const (
SO_OOBINLINE = 0x100 SO_OOBINLINE = 0x100
SO_PASSCRED = 0x11 SO_PASSCRED = 0x11
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x12 SO_PEERCRED = 0x12
@ -371,6 +375,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x1004 SO_RCVLOWAT = 0x1004
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x1006 SO_RCVTIMEO = 0x1006
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x1006 SO_RCVTIMEO_OLD = 0x1006

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x300 CS8 = 0x300
CSIZE = 0x300 CSIZE = 0x300
CSTOPB = 0x400 CSTOPB = 0x400
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x40 ECHOCTL = 0x40
@ -114,6 +115,8 @@ const (
IEXTEN = 0x400 IEXTEN = 0x400
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x800 IN_NONBLOCK = 0x800
IOCTL_MEI_NOTIFY_GET = 0x40044803
IOCTL_MEI_NOTIFY_SET = 0x80044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
IPV6_FLOWINFO_MASK = 0xfffffff IPV6_FLOWINFO_MASK = 0xfffffff
IPV6_FLOWLABEL_MASK = 0xfffff IPV6_FLOWLABEL_MASK = 0xfffff
@ -414,6 +417,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x14 SO_PASSCRED = 0x14
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x15 SO_PEERCRED = 0x15
@ -426,6 +430,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x10 SO_RCVLOWAT = 0x10
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x12 SO_RCVTIMEO = 0x12
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x12 SO_RCVTIMEO_OLD = 0x12

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x300 CS8 = 0x300
CSIZE = 0x300 CSIZE = 0x300
CSTOPB = 0x400 CSTOPB = 0x400
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x40 ECHOCTL = 0x40
@ -114,6 +115,8 @@ const (
IEXTEN = 0x400 IEXTEN = 0x400
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x800 IN_NONBLOCK = 0x800
IOCTL_MEI_NOTIFY_GET = 0x40044803
IOCTL_MEI_NOTIFY_SET = 0x80044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
IPV6_FLOWINFO_MASK = 0xfffffff IPV6_FLOWINFO_MASK = 0xfffffff
IPV6_FLOWLABEL_MASK = 0xfffff IPV6_FLOWLABEL_MASK = 0xfffff
@ -418,6 +421,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x14 SO_PASSCRED = 0x14
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x15 SO_PEERCRED = 0x15
@ -430,6 +434,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x10 SO_RCVLOWAT = 0x10
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x12 SO_RCVTIMEO = 0x12
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x12 SO_RCVTIMEO_OLD = 0x12

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x300 CS8 = 0x300
CSIZE = 0x300 CSIZE = 0x300
CSTOPB = 0x400 CSTOPB = 0x400
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x40 ECHOCTL = 0x40
@ -114,6 +115,8 @@ const (
IEXTEN = 0x400 IEXTEN = 0x400
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x800 IN_NONBLOCK = 0x800
IOCTL_MEI_NOTIFY_GET = 0x40044803
IOCTL_MEI_NOTIFY_SET = 0x80044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
IPV6_FLOWINFO_MASK = 0xffffff0f IPV6_FLOWINFO_MASK = 0xffffff0f
IPV6_FLOWLABEL_MASK = 0xffff0f00 IPV6_FLOWLABEL_MASK = 0xffff0f00
@ -418,6 +421,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x14 SO_PASSCRED = 0x14
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x15 SO_PEERCRED = 0x15
@ -430,6 +434,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x10 SO_RCVLOWAT = 0x10
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x12 SO_RCVTIMEO = 0x12
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x12 SO_RCVTIMEO_OLD = 0x12

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -114,6 +115,8 @@ const (
IEXTEN = 0x8000 IEXTEN = 0x8000
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x800 IN_NONBLOCK = 0x800
IOCTL_MEI_NOTIFY_GET = 0x80044803
IOCTL_MEI_NOTIFY_SET = 0x40044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
IPV6_FLOWINFO_MASK = 0xffffff0f IPV6_FLOWINFO_MASK = 0xffffff0f
IPV6_FLOWLABEL_MASK = 0xffff0f00 IPV6_FLOWLABEL_MASK = 0xffff0f00
@ -350,6 +353,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11
@ -362,6 +366,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x12 SO_RCVLOWAT = 0x12
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x14 SO_RCVTIMEO = 0x14
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x14 SO_RCVTIMEO_OLD = 0x14

View File

@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -114,6 +115,8 @@ const (
IEXTEN = 0x8000 IEXTEN = 0x8000
IN_CLOEXEC = 0x80000 IN_CLOEXEC = 0x80000
IN_NONBLOCK = 0x800 IN_NONBLOCK = 0x800
IOCTL_MEI_NOTIFY_GET = 0x80044803
IOCTL_MEI_NOTIFY_SET = 0x40044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
IPV6_FLOWINFO_MASK = 0xfffffff IPV6_FLOWINFO_MASK = 0xfffffff
IPV6_FLOWLABEL_MASK = 0xfffff IPV6_FLOWLABEL_MASK = 0xfffff
@ -422,6 +425,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11
@ -434,6 +438,7 @@ const (
SO_RCVBUFFORCE = 0x21 SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x12 SO_RCVLOWAT = 0x12
SO_RCVMARK = 0x4b SO_RCVMARK = 0x4b
SO_RCVPRIORITY = 0x52
SO_RCVTIMEO = 0x14 SO_RCVTIMEO = 0x14
SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_NEW = 0x42
SO_RCVTIMEO_OLD = 0x14 SO_RCVTIMEO_OLD = 0x14

View File

@ -71,6 +71,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@ -118,6 +119,8 @@ const (
IEXTEN = 0x8000 IEXTEN = 0x8000
IN_CLOEXEC = 0x400000 IN_CLOEXEC = 0x400000
IN_NONBLOCK = 0x4000 IN_NONBLOCK = 0x4000
IOCTL_MEI_NOTIFY_GET = 0x40044803
IOCTL_MEI_NOTIFY_SET = 0x80044802
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
IPV6_FLOWINFO_MASK = 0xfffffff IPV6_FLOWINFO_MASK = 0xfffffff
IPV6_FLOWLABEL_MASK = 0xfffff IPV6_FLOWLABEL_MASK = 0xfffff
@ -461,6 +464,7 @@ const (
SO_OOBINLINE = 0x100 SO_OOBINLINE = 0x100
SO_PASSCRED = 0x2 SO_PASSCRED = 0x2
SO_PASSPIDFD = 0x55 SO_PASSPIDFD = 0x55
SO_PASSRIGHTS = 0x5c
SO_PASSSEC = 0x1f SO_PASSSEC = 0x1f
SO_PEEK_OFF = 0x26 SO_PEEK_OFF = 0x26
SO_PEERCRED = 0x40 SO_PEERCRED = 0x40
@ -473,6 +477,7 @@ const (
SO_RCVBUFFORCE = 0x100b SO_RCVBUFFORCE = 0x100b
SO_RCVLOWAT = 0x800 SO_RCVLOWAT = 0x800
SO_RCVMARK = 0x54 SO_RCVMARK = 0x54
SO_RCVPRIORITY = 0x5b
SO_RCVTIMEO = 0x2000 SO_RCVTIMEO = 0x2000
SO_RCVTIMEO_NEW = 0x44 SO_RCVTIMEO_NEW = 0x44
SO_RCVTIMEO_OLD = 0x2000 SO_RCVTIMEO_OLD = 0x2000

View File

@ -2238,3 +2238,13 @@ func Mseal(b []byte, flags uint) (err error) {
} }
return return
} }
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func setMemPolicy(mode int, mask *CPUSet, size int) (err error) {
_, _, e1 := Syscall(SYS_SET_MEMPOLICY, uintptr(mode), uintptr(unsafe.Pointer(mask)), uintptr(size))
if e1 != 0 {
err = errnoErr(e1)
}
return
}

View File

@ -72,7 +72,7 @@ import (
//go:cgo_import_dynamic libc_kill kill "libc.so" //go:cgo_import_dynamic libc_kill kill "libc.so"
//go:cgo_import_dynamic libc_lchown lchown "libc.so" //go:cgo_import_dynamic libc_lchown lchown "libc.so"
//go:cgo_import_dynamic libc_link link "libc.so" //go:cgo_import_dynamic libc_link link "libc.so"
//go:cgo_import_dynamic libc___xnet_llisten __xnet_llisten "libsocket.so" //go:cgo_import_dynamic libc___xnet_listen __xnet_listen "libsocket.so"
//go:cgo_import_dynamic libc_lstat lstat "libc.so" //go:cgo_import_dynamic libc_lstat lstat "libc.so"
//go:cgo_import_dynamic libc_madvise madvise "libc.so" //go:cgo_import_dynamic libc_madvise madvise "libc.so"
//go:cgo_import_dynamic libc_mkdir mkdir "libc.so" //go:cgo_import_dynamic libc_mkdir mkdir "libc.so"
@ -221,7 +221,7 @@ import (
//go:linkname procKill libc_kill //go:linkname procKill libc_kill
//go:linkname procLchown libc_lchown //go:linkname procLchown libc_lchown
//go:linkname procLink libc_link //go:linkname procLink libc_link
//go:linkname proc__xnet_llisten libc___xnet_llisten //go:linkname proc__xnet_listen libc___xnet_listen
//go:linkname procLstat libc_lstat //go:linkname procLstat libc_lstat
//go:linkname procMadvise libc_madvise //go:linkname procMadvise libc_madvise
//go:linkname procMkdir libc_mkdir //go:linkname procMkdir libc_mkdir
@ -371,7 +371,7 @@ var (
procKill, procKill,
procLchown, procLchown,
procLink, procLink,
proc__xnet_llisten, proc__xnet_listen,
procLstat, procLstat,
procMadvise, procMadvise,
procMkdir, procMkdir,
@ -1178,7 +1178,7 @@ func Link(path string, link string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Listen(s int, backlog int) (err error) { func Listen(s int, backlog int) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_llisten)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0) _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
if e1 != 0 { if e1 != 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }

View File

@ -462,4 +462,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@ -385,4 +385,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@ -426,4 +426,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@ -329,4 +329,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@ -325,4 +325,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

Some files were not shown because too many files have changed in this diff Show More