Merge pull request #7443 from dcantah/bump-winio-0.6
go.mod: Bump go-winio to v0.6.0
This commit is contained in:
commit
7374e0a330
7
go.mod
7
go.mod
@ -5,7 +5,7 @@ go 1.18
|
|||||||
require (
|
require (
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20220903154154-e8044f6e4c72
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20220903154154-e8044f6e4c72
|
||||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20220912195655-e1f97a00006b
|
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20220912195655-e1f97a00006b
|
||||||
github.com/Microsoft/go-winio v0.5.2
|
github.com/Microsoft/go-winio v0.6.0
|
||||||
github.com/Microsoft/hcsshim v0.10.0-rc.1
|
github.com/Microsoft/hcsshim v0.10.0-rc.1
|
||||||
github.com/container-orchestrated-devices/container-device-interface v0.5.1
|
github.com/container-orchestrated-devices/container-device-interface v0.5.1
|
||||||
github.com/containerd/aufs v1.0.0
|
github.com/containerd/aufs v1.0.0
|
||||||
@ -78,6 +78,11 @@ require (
|
|||||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
|
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||||
|
golang.org/x/tools v0.1.12 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||||
|
8
go.sum
8
go.sum
@ -73,8 +73,8 @@ github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JP
|
|||||||
github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||||
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||||
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||||
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
|
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
|
||||||
@ -1095,6 +1095,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
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=
|
||||||
@ -1378,6 +1380,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||||
|
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -23,7 +23,7 @@ require github.com/AdaLogics/go-fuzz-headers v0.0.0-20220903154154-e8044f6e4c72
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20220912195655-e1f97a00006b // indirect
|
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20220912195655-e1f97a00006b // indirect
|
||||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||||
github.com/cilium/ebpf v0.9.1 // indirect
|
github.com/cilium/ebpf v0.9.1 // indirect
|
||||||
github.com/container-orchestrated-devices/container-device-interface v0.5.1 // indirect
|
github.com/container-orchestrated-devices/container-device-interface v0.5.1 // indirect
|
||||||
@ -60,9 +60,11 @@ require (
|
|||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
go.opencensus.io v0.23.0 // indirect
|
go.opencensus.io v0.23.0 // indirect
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect
|
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
|
golang.org/x/tools v0.1.12 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect
|
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect
|
||||||
google.golang.org/grpc v1.47.0 // indirect
|
google.golang.org/grpc v1.47.0 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // indirect
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
|
@ -58,8 +58,9 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB
|
|||||||
github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
|
||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
|
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||||
|
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||||
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
|
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
|
||||||
github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
||||||
github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
|
github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
|
||||||
@ -685,6 +686,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||||
@ -788,6 +790,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
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=
|
||||||
@ -1048,6 +1052,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||||
|
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
1
vendor/github.com/Microsoft/go-winio/.gitattributes
generated
vendored
Normal file
1
vendor/github.com/Microsoft/go-winio/.gitattributes
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
* text=auto eol=lf
|
9
vendor/github.com/Microsoft/go-winio/.gitignore
generated
vendored
9
vendor/github.com/Microsoft/go-winio/.gitignore
generated
vendored
@ -1 +1,10 @@
|
|||||||
|
.vscode/
|
||||||
|
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
|
# testing
|
||||||
|
testdata
|
||||||
|
|
||||||
|
# go workspaces
|
||||||
|
go.work
|
||||||
|
go.work.sum
|
||||||
|
144
vendor/github.com/Microsoft/go-winio/.golangci.yml
generated
vendored
Normal file
144
vendor/github.com/Microsoft/go-winio/.golangci.yml
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
run:
|
||||||
|
skip-dirs:
|
||||||
|
- pkg/etw/sample
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
# style
|
||||||
|
- containedctx # struct contains a context
|
||||||
|
- dupl # duplicate code
|
||||||
|
- errname # erorrs are named correctly
|
||||||
|
- goconst # strings that should be constants
|
||||||
|
- godot # comments end in a period
|
||||||
|
- misspell
|
||||||
|
- nolintlint # "//nolint" directives are properly explained
|
||||||
|
- revive # golint replacement
|
||||||
|
- stylecheck # golint replacement, less configurable than revive
|
||||||
|
- unconvert # unnecessary conversions
|
||||||
|
- wastedassign
|
||||||
|
|
||||||
|
# bugs, performance, unused, etc ...
|
||||||
|
- contextcheck # function uses a non-inherited context
|
||||||
|
- errorlint # errors not wrapped for 1.13
|
||||||
|
- exhaustive # check exhaustiveness of enum switch statements
|
||||||
|
- gofmt # files are gofmt'ed
|
||||||
|
- gosec # security
|
||||||
|
- nestif # deeply nested ifs
|
||||||
|
- nilerr # returns nil even with non-nil error
|
||||||
|
- prealloc # slices that can be pre-allocated
|
||||||
|
- structcheck # unused struct fields
|
||||||
|
- unparam # unused function params
|
||||||
|
|
||||||
|
issues:
|
||||||
|
exclude-rules:
|
||||||
|
# err is very often shadowed in nested scopes
|
||||||
|
- linters:
|
||||||
|
- govet
|
||||||
|
text: '^shadow: declaration of "err" shadows declaration'
|
||||||
|
|
||||||
|
# ignore long lines for skip autogen directives
|
||||||
|
- linters:
|
||||||
|
- revive
|
||||||
|
text: "^line-length-limit: "
|
||||||
|
source: "^//(go:generate|sys) "
|
||||||
|
|
||||||
|
# allow unjustified ignores of error checks in defer statements
|
||||||
|
- linters:
|
||||||
|
- nolintlint
|
||||||
|
text: "^directive `//nolint:errcheck` should provide explanation"
|
||||||
|
source: '^\s*defer '
|
||||||
|
|
||||||
|
# allow unjustified ignores of error lints for io.EOF
|
||||||
|
- linters:
|
||||||
|
- nolintlint
|
||||||
|
text: "^directive `//nolint:errorlint` should provide explanation"
|
||||||
|
source: '[=|!]= io.EOF'
|
||||||
|
|
||||||
|
|
||||||
|
linters-settings:
|
||||||
|
govet:
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
# struct order is often for Win32 compat
|
||||||
|
# also, ignore pointer bytes/GC issues for now until performance becomes an issue
|
||||||
|
- fieldalignment
|
||||||
|
check-shadowing: true
|
||||||
|
nolintlint:
|
||||||
|
allow-leading-space: false
|
||||||
|
require-explanation: true
|
||||||
|
require-specific: true
|
||||||
|
revive:
|
||||||
|
# revive is more configurable than static check, so likely the preferred alternative to static-check
|
||||||
|
# (once the perf issue is solved: https://github.com/golangci/golangci-lint/issues/2997)
|
||||||
|
enable-all-rules:
|
||||||
|
true
|
||||||
|
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
|
||||||
|
rules:
|
||||||
|
# rules with required arguments
|
||||||
|
- name: argument-limit
|
||||||
|
disabled: true
|
||||||
|
- name: banned-characters
|
||||||
|
disabled: true
|
||||||
|
- name: cognitive-complexity
|
||||||
|
disabled: true
|
||||||
|
- name: cyclomatic
|
||||||
|
disabled: true
|
||||||
|
- name: file-header
|
||||||
|
disabled: true
|
||||||
|
- name: function-length
|
||||||
|
disabled: true
|
||||||
|
- name: function-result-limit
|
||||||
|
disabled: true
|
||||||
|
- name: max-public-structs
|
||||||
|
disabled: true
|
||||||
|
# geneally annoying rules
|
||||||
|
- name: add-constant # complains about any and all strings and integers
|
||||||
|
disabled: true
|
||||||
|
- name: confusing-naming # we frequently use "Foo()" and "foo()" together
|
||||||
|
disabled: true
|
||||||
|
- name: flag-parameter # excessive, and a common idiom we use
|
||||||
|
disabled: true
|
||||||
|
# general config
|
||||||
|
- name: line-length-limit
|
||||||
|
arguments:
|
||||||
|
- 140
|
||||||
|
- name: var-naming
|
||||||
|
arguments:
|
||||||
|
- []
|
||||||
|
- - CID
|
||||||
|
- CRI
|
||||||
|
- CTRD
|
||||||
|
- DACL
|
||||||
|
- DLL
|
||||||
|
- DOS
|
||||||
|
- ETW
|
||||||
|
- FSCTL
|
||||||
|
- GCS
|
||||||
|
- GMSA
|
||||||
|
- HCS
|
||||||
|
- HV
|
||||||
|
- IO
|
||||||
|
- LCOW
|
||||||
|
- LDAP
|
||||||
|
- LPAC
|
||||||
|
- LTSC
|
||||||
|
- MMIO
|
||||||
|
- NT
|
||||||
|
- OCI
|
||||||
|
- PMEM
|
||||||
|
- PWSH
|
||||||
|
- RX
|
||||||
|
- SACl
|
||||||
|
- SID
|
||||||
|
- SMB
|
||||||
|
- TX
|
||||||
|
- VHD
|
||||||
|
- VHDX
|
||||||
|
- VMID
|
||||||
|
- VPCI
|
||||||
|
- WCOW
|
||||||
|
- WIM
|
||||||
|
stylecheck:
|
||||||
|
checks:
|
||||||
|
- "all"
|
||||||
|
- "-ST1003" # use revive's var naming
|
74
vendor/github.com/Microsoft/go-winio/README.md
generated
vendored
74
vendor/github.com/Microsoft/go-winio/README.md
generated
vendored
@ -13,16 +13,60 @@ Please see the LICENSE file for licensing information.
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA)
|
This project welcomes contributions and suggestions.
|
||||||
declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that
|
||||||
|
you have the right to, and actually do, grant us the rights to use your contribution.
|
||||||
|
For details, visit [Microsoft CLA](https://cla.microsoft.com).
|
||||||
|
|
||||||
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR
|
When you submit a pull request, a CLA-bot will automatically determine whether you need to
|
||||||
appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
|
provide a CLA and decorate the PR appropriately (e.g., label, comment).
|
||||||
|
Simply follow the instructions provided by the bot.
|
||||||
|
You will only need to do this once across all repos using our CLA.
|
||||||
|
|
||||||
We also require that contributors sign their commits using git commit -s or git commit --signoff to certify they either authored the work themselves
|
Additionally, the pull request pipeline requires the following steps to be performed before
|
||||||
or otherwise have permission to use it in this project. Please see https://developercertificate.org/ for more info, as well as to make sure that you can
|
mergining.
|
||||||
attest to the rules listed. Our CI uses the DCO Github app to ensure that all commits in a given PR are signed-off.
|
|
||||||
|
|
||||||
|
### Code Sign-Off
|
||||||
|
|
||||||
|
We require that contributors sign their commits using [`git commit --signoff`][git-commit-s]
|
||||||
|
to certify they either authored the work themselves or otherwise have permission to use it in this project.
|
||||||
|
|
||||||
|
A range of commits can be signed off using [`git rebase --signoff`][git-rebase-s].
|
||||||
|
|
||||||
|
Please see [the developer certificate](https://developercertificate.org) for more info,
|
||||||
|
as well as to make sure that you can attest to the rules listed.
|
||||||
|
Our CI uses the DCO Github app to ensure that all commits in a given PR are signed-off.
|
||||||
|
|
||||||
|
### Linting
|
||||||
|
|
||||||
|
Code must pass a linting stage, which uses [`golangci-lint`][lint].
|
||||||
|
The linting settings are stored in [`.golangci.yaml`](./.golangci.yaml), and can be run
|
||||||
|
automatically with VSCode by adding the following to your workspace or folder settings:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"go.lintTool": "golangci-lint",
|
||||||
|
"go.lintOnSave": "package",
|
||||||
|
```
|
||||||
|
|
||||||
|
Additional editor [integrations options are also available][lint-ide].
|
||||||
|
|
||||||
|
Alternatively, `golangci-lint` can be [installed locally][lint-install] and run from the repo root:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# use . or specify a path to only lint a package
|
||||||
|
# to show all lint errors, use flags "--max-issues-per-linter=0 --max-same-issues=0"
|
||||||
|
> golangci-lint run ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Go Generate
|
||||||
|
|
||||||
|
The pipeline checks that auto-generated code, via `go generate`, are up to date.
|
||||||
|
|
||||||
|
This can be done for the entire repo:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
> go generate ./...
|
||||||
|
```
|
||||||
|
|
||||||
## Code of Conduct
|
## Code of Conduct
|
||||||
|
|
||||||
@ -30,8 +74,16 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
|
|||||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Special Thanks
|
## Special Thanks
|
||||||
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
|
|
||||||
for another named pipe implementation.
|
Thanks to [natefinch][natefinch] for the inspiration for this library.
|
||||||
|
See [npipe](https://github.com/natefinch/npipe) for another named pipe implementation.
|
||||||
|
|
||||||
|
[lint]: https://golangci-lint.run/
|
||||||
|
[lint-ide]: https://golangci-lint.run/usage/integrations/#editor-integration
|
||||||
|
[lint-install]: https://golangci-lint.run/usage/install/#local-installation
|
||||||
|
|
||||||
|
[git-commit-s]: https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s
|
||||||
|
[git-rebase-s]: https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---signoff
|
||||||
|
|
||||||
|
[natefinch]: https://github.com/natefinch
|
||||||
|
41
vendor/github.com/Microsoft/go-winio/SECURITY.md
generated
vendored
Normal file
41
vendor/github.com/Microsoft/go-winio/SECURITY.md
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||||
|
|
||||||
|
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
|
||||||
|
|
||||||
|
## Reporting Security Issues
|
||||||
|
|
||||||
|
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||||
|
|
||||||
|
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
|
||||||
|
|
||||||
|
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
|
||||||
|
|
||||||
|
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
|
||||||
|
|
||||||
|
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||||
|
|
||||||
|
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||||
|
* Full paths of source file(s) related to the manifestation of the issue
|
||||||
|
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||||
|
* Any special configuration required to reproduce the issue
|
||||||
|
* Step-by-step instructions to reproduce the issue
|
||||||
|
* Proof-of-concept or exploit code (if possible)
|
||||||
|
* Impact of the issue, including how an attacker might exploit the issue
|
||||||
|
|
||||||
|
This information will help us triage your report more quickly.
|
||||||
|
|
||||||
|
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
|
||||||
|
|
||||||
|
## Preferred Languages
|
||||||
|
|
||||||
|
We prefer all communications to be in English.
|
||||||
|
|
||||||
|
## Policy
|
||||||
|
|
||||||
|
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
|
||||||
|
|
||||||
|
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
48
vendor/github.com/Microsoft/go-winio/backup.go
generated
vendored
48
vendor/github.com/Microsoft/go-winio/backup.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
@ -7,11 +8,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
|
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
|
||||||
@ -24,7 +26,7 @@ const (
|
|||||||
BackupAlternateData
|
BackupAlternateData
|
||||||
BackupLink
|
BackupLink
|
||||||
BackupPropertyData
|
BackupPropertyData
|
||||||
BackupObjectId
|
BackupObjectId //revive:disable-line:var-naming ID, not Id
|
||||||
BackupReparseData
|
BackupReparseData
|
||||||
BackupSparseBlock
|
BackupSparseBlock
|
||||||
BackupTxfsData
|
BackupTxfsData
|
||||||
@ -34,14 +36,16 @@ const (
|
|||||||
StreamSparseAttributes = uint32(8)
|
StreamSparseAttributes = uint32(8)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:revive // var-naming: ALL_CAPS
|
||||||
const (
|
const (
|
||||||
WRITE_DAC = 0x40000
|
WRITE_DAC = windows.WRITE_DAC
|
||||||
WRITE_OWNER = 0x80000
|
WRITE_OWNER = windows.WRITE_OWNER
|
||||||
ACCESS_SYSTEM_SECURITY = 0x1000000
|
ACCESS_SYSTEM_SECURITY = windows.ACCESS_SYSTEM_SECURITY
|
||||||
)
|
)
|
||||||
|
|
||||||
// BackupHeader represents a backup stream of a file.
|
// BackupHeader represents a backup stream of a file.
|
||||||
type BackupHeader struct {
|
type BackupHeader struct {
|
||||||
|
//revive:disable-next-line:var-naming ID, not Id
|
||||||
Id uint32 // The backup stream ID
|
Id uint32 // The backup stream ID
|
||||||
Attributes uint32 // Stream attributes
|
Attributes uint32 // Stream attributes
|
||||||
Size int64 // The size of the stream in bytes
|
Size int64 // The size of the stream in bytes
|
||||||
@ -49,8 +53,8 @@ type BackupHeader struct {
|
|||||||
Offset int64 // The offset of the stream in the file (for BackupSparseBlock only).
|
Offset int64 // The offset of the stream in the file (for BackupSparseBlock only).
|
||||||
}
|
}
|
||||||
|
|
||||||
type win32StreamId struct {
|
type win32StreamID struct {
|
||||||
StreamId uint32
|
StreamID uint32
|
||||||
Attributes uint32
|
Attributes uint32
|
||||||
Size uint64
|
Size uint64
|
||||||
NameSize uint32
|
NameSize uint32
|
||||||
@ -71,7 +75,7 @@ func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
|
|||||||
// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if
|
// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if
|
||||||
// it was not completely read.
|
// it was not completely read.
|
||||||
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
|
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
|
||||||
if r.bytesLeft > 0 {
|
if r.bytesLeft > 0 { //nolint:nestif // todo: flatten this
|
||||||
if s, ok := r.r.(io.Seeker); ok {
|
if s, ok := r.r.(io.Seeker); ok {
|
||||||
// Make sure Seek on io.SeekCurrent sometimes succeeds
|
// Make sure Seek on io.SeekCurrent sometimes succeeds
|
||||||
// before trying the actual seek.
|
// before trying the actual seek.
|
||||||
@ -82,16 +86,16 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
|
|||||||
r.bytesLeft = 0
|
r.bytesLeft = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(ioutil.Discard, r); err != nil {
|
if _, err := io.Copy(io.Discard, r); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var wsi win32StreamId
|
var wsi win32StreamID
|
||||||
if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
|
if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
hdr := &BackupHeader{
|
hdr := &BackupHeader{
|
||||||
Id: wsi.StreamId,
|
Id: wsi.StreamID,
|
||||||
Attributes: wsi.Attributes,
|
Attributes: wsi.Attributes,
|
||||||
Size: int64(wsi.Size),
|
Size: int64(wsi.Size),
|
||||||
}
|
}
|
||||||
@ -102,7 +106,7 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
|
|||||||
}
|
}
|
||||||
hdr.Name = syscall.UTF16ToString(name)
|
hdr.Name = syscall.UTF16ToString(name)
|
||||||
}
|
}
|
||||||
if wsi.StreamId == BackupSparseBlock {
|
if wsi.StreamID == BackupSparseBlock {
|
||||||
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
|
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -147,8 +151,8 @@ func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
|
|||||||
return fmt.Errorf("missing %d bytes", w.bytesLeft)
|
return fmt.Errorf("missing %d bytes", w.bytesLeft)
|
||||||
}
|
}
|
||||||
name := utf16.Encode([]rune(hdr.Name))
|
name := utf16.Encode([]rune(hdr.Name))
|
||||||
wsi := win32StreamId{
|
wsi := win32StreamID{
|
||||||
StreamId: hdr.Id,
|
StreamID: hdr.Id,
|
||||||
Attributes: hdr.Attributes,
|
Attributes: hdr.Attributes,
|
||||||
Size: uint64(hdr.Size),
|
Size: uint64(hdr.Size),
|
||||||
NameSize: uint32(len(name) * 2),
|
NameSize: uint32(len(name) * 2),
|
||||||
@ -203,7 +207,7 @@ func (r *BackupFileReader) Read(b []byte) (int, error) {
|
|||||||
var bytesRead uint32
|
var bytesRead uint32
|
||||||
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
|
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, &os.PathError{"BackupRead", r.f.Name(), err}
|
return 0, &os.PathError{Op: "BackupRead", Path: r.f.Name(), Err: err}
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(r.f)
|
runtime.KeepAlive(r.f)
|
||||||
if bytesRead == 0 {
|
if bytesRead == 0 {
|
||||||
@ -216,7 +220,7 @@ func (r *BackupFileReader) Read(b []byte) (int, error) {
|
|||||||
// the underlying file.
|
// the underlying file.
|
||||||
func (r *BackupFileReader) Close() error {
|
func (r *BackupFileReader) Close() error {
|
||||||
if r.ctx != 0 {
|
if r.ctx != 0 {
|
||||||
backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
|
_ = backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
|
||||||
runtime.KeepAlive(r.f)
|
runtime.KeepAlive(r.f)
|
||||||
r.ctx = 0
|
r.ctx = 0
|
||||||
}
|
}
|
||||||
@ -242,7 +246,7 @@ func (w *BackupFileWriter) Write(b []byte) (int, error) {
|
|||||||
var bytesWritten uint32
|
var bytesWritten uint32
|
||||||
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
|
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
|
return 0, &os.PathError{Op: "BackupWrite", Path: w.f.Name(), Err: err}
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(w.f)
|
runtime.KeepAlive(w.f)
|
||||||
if int(bytesWritten) != len(b) {
|
if int(bytesWritten) != len(b) {
|
||||||
@ -255,7 +259,7 @@ func (w *BackupFileWriter) Write(b []byte) (int, error) {
|
|||||||
// close the underlying file.
|
// close the underlying file.
|
||||||
func (w *BackupFileWriter) Close() error {
|
func (w *BackupFileWriter) Close() error {
|
||||||
if w.ctx != 0 {
|
if w.ctx != 0 {
|
||||||
backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
|
_ = backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
|
||||||
runtime.KeepAlive(w.f)
|
runtime.KeepAlive(w.f)
|
||||||
w.ctx = 0
|
w.ctx = 0
|
||||||
}
|
}
|
||||||
@ -271,7 +275,13 @@ func OpenForBackup(path string, access uint32, share uint32, createmode uint32)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0)
|
h, err := syscall.CreateFile(&winPath[0],
|
||||||
|
access,
|
||||||
|
share,
|
||||||
|
nil,
|
||||||
|
createmode,
|
||||||
|
syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT,
|
||||||
|
0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = &os.PathError{Op: "open", Path: path, Err: err}
|
err = &os.PathError{Op: "open", Path: path, Err: err}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
// +build !windows
|
|
||||||
// This file only exists to allow go get on non-Windows platforms.
|
// This file only exists to allow go get on non-Windows platforms.
|
||||||
|
|
||||||
package backuptar
|
package backuptar
|
2
vendor/github.com/Microsoft/go-winio/backuptar/strconv.go
generated
vendored
2
vendor/github.com/Microsoft/go-winio/backuptar/strconv.go
generated
vendored
@ -1,3 +1,5 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
package backuptar
|
package backuptar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
146
vendor/github.com/Microsoft/go-winio/backuptar/tar.go
generated
vendored
146
vendor/github.com/Microsoft/go-winio/backuptar/tar.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package backuptar
|
package backuptar
|
||||||
@ -7,7 +8,6 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -18,17 +18,18 @@ import (
|
|||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:deadcode,varcheck // keep unused constants for potential future use
|
||||||
const (
|
const (
|
||||||
c_ISUID = 04000 // Set uid
|
cISUID = 0004000 // Set uid
|
||||||
c_ISGID = 02000 // Set gid
|
cISGID = 0002000 // Set gid
|
||||||
c_ISVTX = 01000 // Save text (sticky bit)
|
cISVTX = 0001000 // Save text (sticky bit)
|
||||||
c_ISDIR = 040000 // Directory
|
cISDIR = 0040000 // Directory
|
||||||
c_ISFIFO = 010000 // FIFO
|
cISFIFO = 0010000 // FIFO
|
||||||
c_ISREG = 0100000 // Regular file
|
cISREG = 0100000 // Regular file
|
||||||
c_ISLNK = 0120000 // Symbolic link
|
cISLNK = 0120000 // Symbolic link
|
||||||
c_ISBLK = 060000 // Block special file
|
cISBLK = 0060000 // Block special file
|
||||||
c_ISCHR = 020000 // Character special file
|
cISCHR = 0020000 // Character special file
|
||||||
c_ISSOCK = 0140000 // Socket
|
cISSOCK = 0140000 // Socket
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -44,7 +45,7 @@ const (
|
|||||||
// zeroReader is an io.Reader that always returns 0s.
|
// zeroReader is an io.Reader that always returns 0s.
|
||||||
type zeroReader struct{}
|
type zeroReader struct{}
|
||||||
|
|
||||||
func (zr zeroReader) Read(b []byte) (int, error) {
|
func (zeroReader) Read(b []byte) (int, error) {
|
||||||
for i := range b {
|
for i := range b {
|
||||||
b[i] = 0
|
b[i] = 0
|
||||||
}
|
}
|
||||||
@ -55,7 +56,7 @@ func copySparse(t *tar.Writer, br *winio.BackupStreamReader) error {
|
|||||||
curOffset := int64(0)
|
curOffset := int64(0)
|
||||||
for {
|
for {
|
||||||
bhdr, err := br.Next()
|
bhdr, err := br.Next()
|
||||||
if err == io.EOF {
|
if err == io.EOF { //nolint:errorlint
|
||||||
err = io.ErrUnexpectedEOF
|
err = io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -71,8 +72,8 @@ func copySparse(t *tar.Writer, br *winio.BackupStreamReader) error {
|
|||||||
}
|
}
|
||||||
// archive/tar does not support writing sparse files
|
// archive/tar does not support writing sparse files
|
||||||
// so just write zeroes to catch up to the current offset.
|
// so just write zeroes to catch up to the current offset.
|
||||||
if _, err := io.CopyN(t, zeroReader{}, bhdr.Offset-curOffset); err != nil {
|
if _, err = io.CopyN(t, zeroReader{}, bhdr.Offset-curOffset); err != nil {
|
||||||
return fmt.Errorf("seek to offset %d: %s", bhdr.Offset, err)
|
return fmt.Errorf("seek to offset %d: %w", bhdr.Offset, err)
|
||||||
}
|
}
|
||||||
if bhdr.Size == 0 {
|
if bhdr.Size == 0 {
|
||||||
// A sparse block with size = 0 is used to mark the end of the sparse blocks.
|
// A sparse block with size = 0 is used to mark the end of the sparse blocks.
|
||||||
@ -106,7 +107,7 @@ func BasicInfoHeader(name string, size int64, fileInfo *winio.FileBasicInfo) *ta
|
|||||||
hdr.PAXRecords[hdrCreationTime] = formatPAXTime(time.Unix(0, fileInfo.CreationTime.Nanoseconds()))
|
hdr.PAXRecords[hdrCreationTime] = formatPAXTime(time.Unix(0, fileInfo.CreationTime.Nanoseconds()))
|
||||||
|
|
||||||
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
|
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
|
||||||
hdr.Mode |= c_ISDIR
|
hdr.Mode |= cISDIR
|
||||||
hdr.Size = 0
|
hdr.Size = 0
|
||||||
hdr.Typeflag = tar.TypeDir
|
hdr.Typeflag = tar.TypeDir
|
||||||
}
|
}
|
||||||
@ -116,32 +117,29 @@ func BasicInfoHeader(name string, size int64, fileInfo *winio.FileBasicInfo) *ta
|
|||||||
// SecurityDescriptorFromTarHeader reads the SDDL associated with the header of the current file
|
// SecurityDescriptorFromTarHeader reads the SDDL associated with the header of the current file
|
||||||
// from the tar header and returns the security descriptor into a byte slice.
|
// from the tar header and returns the security descriptor into a byte slice.
|
||||||
func SecurityDescriptorFromTarHeader(hdr *tar.Header) ([]byte, error) {
|
func SecurityDescriptorFromTarHeader(hdr *tar.Header) ([]byte, error) {
|
||||||
// Maintaining old SDDL-based behavior for backward
|
|
||||||
// compatibility. All new tar headers written by this library
|
|
||||||
// will have raw binary for the security descriptor.
|
|
||||||
var sd []byte
|
|
||||||
var err error
|
|
||||||
if sddl, ok := hdr.PAXRecords[hdrSecurityDescriptor]; ok {
|
|
||||||
sd, err = winio.SddlToSecurityDescriptor(sddl)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sdraw, ok := hdr.PAXRecords[hdrRawSecurityDescriptor]; ok {
|
if sdraw, ok := hdr.PAXRecords[hdrRawSecurityDescriptor]; ok {
|
||||||
sd, err = base64.StdEncoding.DecodeString(sdraw)
|
sd, err := base64.StdEncoding.DecodeString(sdraw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Not returning sd as-is in the error-case, as base64.DecodeString
|
||||||
|
// may return partially decoded data (not nil or empty slice) in case
|
||||||
|
// of a failure: https://github.com/golang/go/blob/go1.17.7/src/encoding/base64/base64.go#L382-L387
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return sd, nil
|
||||||
}
|
}
|
||||||
return sd, nil
|
// Maintaining old SDDL-based behavior for backward compatibility. All new
|
||||||
|
// tar headers written by this library will have raw binary for the security
|
||||||
|
// descriptor.
|
||||||
|
if sddl, ok := hdr.PAXRecords[hdrSecurityDescriptor]; ok {
|
||||||
|
return winio.SddlToSecurityDescriptor(sddl)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtendedAttributesFromTarHeader reads the EAs associated with the header of the
|
// ExtendedAttributesFromTarHeader reads the EAs associated with the header of the
|
||||||
// current file from the tar header and returns it as a byte slice.
|
// current file from the tar header and returns it as a byte slice.
|
||||||
func ExtendedAttributesFromTarHeader(hdr *tar.Header) ([]byte, error) {
|
func ExtendedAttributesFromTarHeader(hdr *tar.Header) ([]byte, error) {
|
||||||
var eas []winio.ExtendedAttribute
|
var eas []winio.ExtendedAttribute //nolint:prealloc // len(eas) <= len(hdr.PAXRecords); prealloc is wasteful
|
||||||
var eadata []byte
|
|
||||||
var err error
|
|
||||||
for k, v := range hdr.PAXRecords {
|
for k, v := range hdr.PAXRecords {
|
||||||
if !strings.HasPrefix(k, hdrEaPrefix) {
|
if !strings.HasPrefix(k, hdrEaPrefix) {
|
||||||
continue
|
continue
|
||||||
@ -155,13 +153,15 @@ func ExtendedAttributesFromTarHeader(hdr *tar.Header) ([]byte, error) {
|
|||||||
Value: data,
|
Value: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
var eaData []byte
|
||||||
|
var err error
|
||||||
if len(eas) != 0 {
|
if len(eas) != 0 {
|
||||||
eadata, err = winio.EncodeExtendedAttributes(eas)
|
eaData, err = winio.EncodeExtendedAttributes(eas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return eadata, nil
|
return eaData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeReparsePointFromTarHeader reads the ReparsePoint structure from the tar header
|
// EncodeReparsePointFromTarHeader reads the ReparsePoint structure from the tar header
|
||||||
@ -182,11 +182,9 @@ func EncodeReparsePointFromTarHeader(hdr *tar.Header) []byte {
|
|||||||
//
|
//
|
||||||
// The additional Win32 metadata is:
|
// The additional Win32 metadata is:
|
||||||
//
|
//
|
||||||
// MSWINDOWS.fileattr: The Win32 file attributes, as a decimal value
|
// - MSWINDOWS.fileattr: The Win32 file attributes, as a decimal value
|
||||||
//
|
// - MSWINDOWS.rawsd: The Win32 security descriptor, in raw binary format
|
||||||
// MSWINDOWS.rawsd: The Win32 security descriptor, in raw binary format
|
// - MSWINDOWS.mountpoint: If present, this is a mount point and not a symlink, even though the type is '2' (symlink)
|
||||||
//
|
|
||||||
// MSWINDOWS.mountpoint: If present, this is a mount point and not a symlink, even though the type is '2' (symlink)
|
|
||||||
func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size int64, fileInfo *winio.FileBasicInfo) error {
|
func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size int64, fileInfo *winio.FileBasicInfo) error {
|
||||||
name = filepath.ToSlash(name)
|
name = filepath.ToSlash(name)
|
||||||
hdr := BasicInfoHeader(name, size, fileInfo)
|
hdr := BasicInfoHeader(name, size, fileInfo)
|
||||||
@ -209,7 +207,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
|
|||||||
var dataHdr *winio.BackupHeader
|
var dataHdr *winio.BackupHeader
|
||||||
for dataHdr == nil {
|
for dataHdr == nil {
|
||||||
bhdr, err := br.Next()
|
bhdr, err := br.Next()
|
||||||
if err == io.EOF {
|
if err == io.EOF { //nolint:errorlint
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -217,21 +215,21 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
|
|||||||
}
|
}
|
||||||
switch bhdr.Id {
|
switch bhdr.Id {
|
||||||
case winio.BackupData:
|
case winio.BackupData:
|
||||||
hdr.Mode |= c_ISREG
|
hdr.Mode |= cISREG
|
||||||
if !readTwice {
|
if !readTwice {
|
||||||
dataHdr = bhdr
|
dataHdr = bhdr
|
||||||
}
|
}
|
||||||
case winio.BackupSecurity:
|
case winio.BackupSecurity:
|
||||||
sd, err := ioutil.ReadAll(br)
|
sd, err := io.ReadAll(br)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hdr.PAXRecords[hdrRawSecurityDescriptor] = base64.StdEncoding.EncodeToString(sd)
|
hdr.PAXRecords[hdrRawSecurityDescriptor] = base64.StdEncoding.EncodeToString(sd)
|
||||||
|
|
||||||
case winio.BackupReparseData:
|
case winio.BackupReparseData:
|
||||||
hdr.Mode |= c_ISLNK
|
hdr.Mode |= cISLNK
|
||||||
hdr.Typeflag = tar.TypeSymlink
|
hdr.Typeflag = tar.TypeSymlink
|
||||||
reparseBuffer, err := ioutil.ReadAll(br)
|
reparseBuffer, _ := io.ReadAll(br)
|
||||||
rp, err := winio.DecodeReparsePoint(reparseBuffer)
|
rp, err := winio.DecodeReparsePoint(reparseBuffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -242,7 +240,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
|
|||||||
hdr.Linkname = rp.Target
|
hdr.Linkname = rp.Target
|
||||||
|
|
||||||
case winio.BackupEaData:
|
case winio.BackupEaData:
|
||||||
eab, err := ioutil.ReadAll(br)
|
eab, err := io.ReadAll(br)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -276,7 +274,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
|
|||||||
}
|
}
|
||||||
for dataHdr == nil {
|
for dataHdr == nil {
|
||||||
bhdr, err := br.Next()
|
bhdr, err := br.Next()
|
||||||
if err == io.EOF {
|
if err == io.EOF { //nolint:errorlint
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -311,7 +309,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
|
|||||||
// range of the file containing the range contents. Finally there is a sparse block stream with
|
// range of the file containing the range contents. Finally there is a sparse block stream with
|
||||||
// size = 0 and offset = <file size>.
|
// size = 0 and offset = <file size>.
|
||||||
|
|
||||||
if dataHdr != nil {
|
if dataHdr != nil { //nolint:nestif // todo: reduce nesting complexity
|
||||||
// A data stream was found. Copy the data.
|
// A data stream was found. Copy the data.
|
||||||
// We assume that we will either have a data stream size > 0 XOR have sparse block streams.
|
// We assume that we will either have a data stream size > 0 XOR have sparse block streams.
|
||||||
if dataHdr.Size > 0 || (dataHdr.Attributes&winio.StreamSparseAttributes) == 0 {
|
if dataHdr.Size > 0 || (dataHdr.Attributes&winio.StreamSparseAttributes) == 0 {
|
||||||
@ -319,13 +317,13 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
|
|||||||
return fmt.Errorf("%s: mismatch between file size %d and header size %d", name, size, dataHdr.Size)
|
return fmt.Errorf("%s: mismatch between file size %d and header size %d", name, size, dataHdr.Size)
|
||||||
}
|
}
|
||||||
if _, err = io.Copy(t, br); err != nil {
|
if _, err = io.Copy(t, br); err != nil {
|
||||||
return fmt.Errorf("%s: copying contents from data stream: %s", name, err)
|
return fmt.Errorf("%s: copying contents from data stream: %w", name, err)
|
||||||
}
|
}
|
||||||
} else if size > 0 {
|
} else if size > 0 {
|
||||||
// As of a recent OS change, BackupRead now returns a data stream for empty sparse files.
|
// As of a recent OS change, BackupRead now returns a data stream for empty sparse files.
|
||||||
// These files have no sparse block streams, so skip the copySparse call if file size = 0.
|
// These files have no sparse block streams, so skip the copySparse call if file size = 0.
|
||||||
if err = copySparse(t, br); err != nil {
|
if err = copySparse(t, br); err != nil {
|
||||||
return fmt.Errorf("%s: copying contents from sparse block stream: %s", name, err)
|
return fmt.Errorf("%s: copying contents from sparse block stream: %w", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,7 +333,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
|
|||||||
// been written. In practice, this means that we don't get EA or TXF metadata.
|
// been written. In practice, this means that we don't get EA or TXF metadata.
|
||||||
for {
|
for {
|
||||||
bhdr, err := br.Next()
|
bhdr, err := br.Next()
|
||||||
if err == io.EOF {
|
if err == io.EOF { //nolint:errorlint
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -343,35 +341,30 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
|
|||||||
}
|
}
|
||||||
switch bhdr.Id {
|
switch bhdr.Id {
|
||||||
case winio.BackupAlternateData:
|
case winio.BackupAlternateData:
|
||||||
altName := bhdr.Name
|
if (bhdr.Attributes & winio.StreamSparseAttributes) != 0 {
|
||||||
if strings.HasSuffix(altName, ":$DATA") {
|
|
||||||
altName = altName[:len(altName)-len(":$DATA")]
|
|
||||||
}
|
|
||||||
if (bhdr.Attributes & winio.StreamSparseAttributes) == 0 {
|
|
||||||
hdr = &tar.Header{
|
|
||||||
Format: hdr.Format,
|
|
||||||
Name: name + altName,
|
|
||||||
Mode: hdr.Mode,
|
|
||||||
Typeflag: tar.TypeReg,
|
|
||||||
Size: bhdr.Size,
|
|
||||||
ModTime: hdr.ModTime,
|
|
||||||
AccessTime: hdr.AccessTime,
|
|
||||||
ChangeTime: hdr.ChangeTime,
|
|
||||||
}
|
|
||||||
err = t.WriteHeader(hdr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = io.Copy(t, br)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Unsupported for now, since the size of the alternate stream is not present
|
// Unsupported for now, since the size of the alternate stream is not present
|
||||||
// in the backup stream until after the data has been read.
|
// in the backup stream until after the data has been read.
|
||||||
return fmt.Errorf("%s: tar of sparse alternate data streams is unsupported", name)
|
return fmt.Errorf("%s: tar of sparse alternate data streams is unsupported", name)
|
||||||
}
|
}
|
||||||
|
altName := strings.TrimSuffix(bhdr.Name, ":$DATA")
|
||||||
|
hdr = &tar.Header{
|
||||||
|
Format: hdr.Format,
|
||||||
|
Name: name + altName,
|
||||||
|
Mode: hdr.Mode,
|
||||||
|
Typeflag: tar.TypeReg,
|
||||||
|
Size: bhdr.Size,
|
||||||
|
ModTime: hdr.ModTime,
|
||||||
|
AccessTime: hdr.AccessTime,
|
||||||
|
ChangeTime: hdr.ChangeTime,
|
||||||
|
}
|
||||||
|
err = t.WriteHeader(hdr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(t, br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
case winio.BackupEaData, winio.BackupLink, winio.BackupPropertyData, winio.BackupObjectId, winio.BackupTxfsData:
|
case winio.BackupEaData, winio.BackupLink, winio.BackupPropertyData, winio.BackupObjectId, winio.BackupTxfsData:
|
||||||
// ignore these streams
|
// ignore these streams
|
||||||
default:
|
default:
|
||||||
@ -413,7 +406,7 @@ func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *win
|
|||||||
}
|
}
|
||||||
fileInfo.CreationTime = windows.NsecToFiletime(creationTime.UnixNano())
|
fileInfo.CreationTime = windows.NsecToFiletime(creationTime.UnixNano())
|
||||||
}
|
}
|
||||||
return
|
return name, size, fileInfo, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteBackupStreamFromTarFile writes a Win32 backup stream from the current tar file. Since this function may process multiple
|
// WriteBackupStreamFromTarFile writes a Win32 backup stream from the current tar file. Since this function may process multiple
|
||||||
@ -474,7 +467,6 @@ func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA {
|
if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA {
|
||||||
|
22
vendor/github.com/Microsoft/go-winio/doc.go
generated
vendored
Normal file
22
vendor/github.com/Microsoft/go-winio/doc.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// This package provides utilities for efficiently performing Win32 IO operations in Go.
|
||||||
|
// Currently, this package is provides support for genreal IO and management of
|
||||||
|
// - named pipes
|
||||||
|
// - files
|
||||||
|
// - [Hyper-V sockets]
|
||||||
|
//
|
||||||
|
// This code is similar to Go's [net] package, and uses IO completion ports to avoid
|
||||||
|
// blocking IO on system threads, allowing Go to reuse the thread to schedule other goroutines.
|
||||||
|
//
|
||||||
|
// This limits support to Windows Vista and newer operating systems.
|
||||||
|
//
|
||||||
|
// Additionally, this package provides support for:
|
||||||
|
// - creating and managing GUIDs
|
||||||
|
// - writing to [ETW]
|
||||||
|
// - opening and manageing VHDs
|
||||||
|
// - parsing [Windows Image files]
|
||||||
|
// - auto-generating Win32 API code
|
||||||
|
//
|
||||||
|
// [Hyper-V sockets]: https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service
|
||||||
|
// [ETW]: https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-
|
||||||
|
// [Windows Image files]: https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/work-with-windows-images
|
||||||
|
package winio
|
8
vendor/github.com/Microsoft/go-winio/ea.go
generated
vendored
8
vendor/github.com/Microsoft/go-winio/ea.go
generated
vendored
@ -33,7 +33,7 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
|
|||||||
err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
|
err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errInvalidEaBuffer
|
err = errInvalidEaBuffer
|
||||||
return
|
return ea, nb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nameOffset := fileFullEaInformationSize
|
nameOffset := fileFullEaInformationSize
|
||||||
@ -43,7 +43,7 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
|
|||||||
nextOffset := int(info.NextEntryOffset)
|
nextOffset := int(info.NextEntryOffset)
|
||||||
if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
|
if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
|
||||||
err = errInvalidEaBuffer
|
err = errInvalidEaBuffer
|
||||||
return
|
return ea, nb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ea.Name = string(b[nameOffset : nameOffset+nameLen])
|
ea.Name = string(b[nameOffset : nameOffset+nameLen])
|
||||||
@ -52,7 +52,7 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
|
|||||||
if info.NextEntryOffset != 0 {
|
if info.NextEntryOffset != 0 {
|
||||||
nb = b[info.NextEntryOffset:]
|
nb = b[info.NextEntryOffset:]
|
||||||
}
|
}
|
||||||
return
|
return ea, nb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
|
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
|
||||||
@ -67,7 +67,7 @@ func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
|
|||||||
eas = append(eas, ea)
|
eas = append(eas, ea)
|
||||||
b = nb
|
b = nb
|
||||||
}
|
}
|
||||||
return
|
return eas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
|
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
|
||||||
|
66
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
66
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
@ -11,6 +11,8 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
|
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
|
||||||
@ -24,6 +26,8 @@ type atomicBool int32
|
|||||||
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
|
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
|
||||||
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
|
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
|
||||||
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
|
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
|
||||||
|
|
||||||
|
//revive:disable-next-line:predeclared Keep "new" to maintain consistency with "atomic" pkg
|
||||||
func (b *atomicBool) swap(new bool) bool {
|
func (b *atomicBool) swap(new bool) bool {
|
||||||
var newInt int32
|
var newInt int32
|
||||||
if new {
|
if new {
|
||||||
@ -32,11 +36,6 @@ func (b *atomicBool) swap(new bool) bool {
|
|||||||
return atomic.SwapInt32((*int32)(b), newInt) == 1
|
return atomic.SwapInt32((*int32)(b), newInt) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
|
|
||||||
cFILE_SKIP_SET_EVENT_ON_HANDLE = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrFileClosed = errors.New("file has already been closed")
|
ErrFileClosed = errors.New("file has already been closed")
|
||||||
ErrTimeout = &timeoutError{}
|
ErrTimeout = &timeoutError{}
|
||||||
@ -44,28 +43,28 @@ var (
|
|||||||
|
|
||||||
type timeoutError struct{}
|
type timeoutError struct{}
|
||||||
|
|
||||||
func (e *timeoutError) Error() string { return "i/o timeout" }
|
func (*timeoutError) Error() string { return "i/o timeout" }
|
||||||
func (e *timeoutError) Timeout() bool { return true }
|
func (*timeoutError) Timeout() bool { return true }
|
||||||
func (e *timeoutError) Temporary() bool { return true }
|
func (*timeoutError) Temporary() bool { return true }
|
||||||
|
|
||||||
type timeoutChan chan struct{}
|
type timeoutChan chan struct{}
|
||||||
|
|
||||||
var ioInitOnce sync.Once
|
var ioInitOnce sync.Once
|
||||||
var ioCompletionPort syscall.Handle
|
var ioCompletionPort syscall.Handle
|
||||||
|
|
||||||
// ioResult contains the result of an asynchronous IO operation
|
// ioResult contains the result of an asynchronous IO operation.
|
||||||
type ioResult struct {
|
type ioResult struct {
|
||||||
bytes uint32
|
bytes uint32
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ioOperation represents an outstanding asynchronous Win32 IO
|
// ioOperation represents an outstanding asynchronous Win32 IO.
|
||||||
type ioOperation struct {
|
type ioOperation struct {
|
||||||
o syscall.Overlapped
|
o syscall.Overlapped
|
||||||
ch chan ioResult
|
ch chan ioResult
|
||||||
}
|
}
|
||||||
|
|
||||||
func initIo() {
|
func initIO() {
|
||||||
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
|
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -94,15 +93,15 @@ type deadlineHandler struct {
|
|||||||
timedout atomicBool
|
timedout atomicBool
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeWin32File makes a new win32File from an existing file handle
|
// makeWin32File makes a new win32File from an existing file handle.
|
||||||
func makeWin32File(h syscall.Handle) (*win32File, error) {
|
func makeWin32File(h syscall.Handle) (*win32File, error) {
|
||||||
f := &win32File{handle: h}
|
f := &win32File{handle: h}
|
||||||
ioInitOnce.Do(initIo)
|
ioInitOnce.Do(initIO)
|
||||||
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
|
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
|
err = setFileCompletionNotificationModes(h, windows.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS|windows.FILE_SKIP_SET_EVENT_ON_HANDLE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -121,14 +120,14 @@ func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
|
|||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// closeHandle closes the resources associated with a Win32 handle
|
// closeHandle closes the resources associated with a Win32 handle.
|
||||||
func (f *win32File) closeHandle() {
|
func (f *win32File) closeHandle() {
|
||||||
f.wgLock.Lock()
|
f.wgLock.Lock()
|
||||||
// Atomically set that we are closing, releasing the resources only once.
|
// Atomically set that we are closing, releasing the resources only once.
|
||||||
if !f.closing.swap(true) {
|
if !f.closing.swap(true) {
|
||||||
f.wgLock.Unlock()
|
f.wgLock.Unlock()
|
||||||
// cancel all IO and wait for it to complete
|
// cancel all IO and wait for it to complete
|
||||||
cancelIoEx(f.handle, nil)
|
_ = cancelIoEx(f.handle, nil)
|
||||||
f.wg.Wait()
|
f.wg.Wait()
|
||||||
// at this point, no new IO can start
|
// at this point, no new IO can start
|
||||||
syscall.Close(f.handle)
|
syscall.Close(f.handle)
|
||||||
@ -144,14 +143,14 @@ func (f *win32File) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsClosed checks if the file has been closed
|
// IsClosed checks if the file has been closed.
|
||||||
func (f *win32File) IsClosed() bool {
|
func (f *win32File) IsClosed() bool {
|
||||||
return f.closing.isSet()
|
return f.closing.isSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepareIo prepares for a new IO operation.
|
// prepareIO prepares for a new IO operation.
|
||||||
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
|
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
|
||||||
func (f *win32File) prepareIo() (*ioOperation, error) {
|
func (f *win32File) prepareIO() (*ioOperation, error) {
|
||||||
f.wgLock.RLock()
|
f.wgLock.RLock()
|
||||||
if f.closing.isSet() {
|
if f.closing.isSet() {
|
||||||
f.wgLock.RUnlock()
|
f.wgLock.RUnlock()
|
||||||
@ -164,7 +163,7 @@ func (f *win32File) prepareIo() (*ioOperation, error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ioCompletionProcessor processes completed async IOs forever
|
// ioCompletionProcessor processes completed async IOs forever.
|
||||||
func ioCompletionProcessor(h syscall.Handle) {
|
func ioCompletionProcessor(h syscall.Handle) {
|
||||||
for {
|
for {
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
@ -178,15 +177,17 @@ func ioCompletionProcessor(h syscall.Handle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
|
// todo: helsaawy - create an asyncIO version that takes a context
|
||||||
|
|
||||||
|
// asyncIO processes the return value from ReadFile or WriteFile, blocking until
|
||||||
// the operation has actually completed.
|
// the operation has actually completed.
|
||||||
func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
|
func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
|
||||||
if err != syscall.ERROR_IO_PENDING {
|
if err != syscall.ERROR_IO_PENDING { //nolint:errorlint // err is Errno
|
||||||
return int(bytes), err
|
return int(bytes), err
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.closing.isSet() {
|
if f.closing.isSet() {
|
||||||
cancelIoEx(f.handle, &c.o)
|
_ = cancelIoEx(f.handle, &c.o)
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeout timeoutChan
|
var timeout timeoutChan
|
||||||
@ -200,7 +201,7 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
|||||||
select {
|
select {
|
||||||
case r = <-c.ch:
|
case r = <-c.ch:
|
||||||
err = r.err
|
err = r.err
|
||||||
if err == syscall.ERROR_OPERATION_ABORTED {
|
if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
|
||||||
if f.closing.isSet() {
|
if f.closing.isSet() {
|
||||||
err = ErrFileClosed
|
err = ErrFileClosed
|
||||||
}
|
}
|
||||||
@ -210,10 +211,10 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
|||||||
err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
|
err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
|
||||||
}
|
}
|
||||||
case <-timeout:
|
case <-timeout:
|
||||||
cancelIoEx(f.handle, &c.o)
|
_ = cancelIoEx(f.handle, &c.o)
|
||||||
r = <-c.ch
|
r = <-c.ch
|
||||||
err = r.err
|
err = r.err
|
||||||
if err == syscall.ERROR_OPERATION_ABORTED {
|
if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
|
||||||
err = ErrTimeout
|
err = ErrTimeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,13 +222,14 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
|||||||
// runtime.KeepAlive is needed, as c is passed via native
|
// runtime.KeepAlive is needed, as c is passed via native
|
||||||
// code to ioCompletionProcessor, c must remain alive
|
// code to ioCompletionProcessor, c must remain alive
|
||||||
// until the channel read is complete.
|
// until the channel read is complete.
|
||||||
|
// todo: (de)allocate *ioOperation via win32 heap functions, instead of needing to KeepAlive?
|
||||||
runtime.KeepAlive(c)
|
runtime.KeepAlive(c)
|
||||||
return int(r.bytes), err
|
return int(r.bytes), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read reads from a file handle.
|
// Read reads from a file handle.
|
||||||
func (f *win32File) Read(b []byte) (int, error) {
|
func (f *win32File) Read(b []byte) (int, error) {
|
||||||
c, err := f.prepareIo()
|
c, err := f.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -239,13 +241,13 @@ func (f *win32File) Read(b []byte) (int, error) {
|
|||||||
|
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
|
err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
|
||||||
n, err := f.asyncIo(c, &f.readDeadline, bytes, err)
|
n, err := f.asyncIO(c, &f.readDeadline, bytes, err)
|
||||||
runtime.KeepAlive(b)
|
runtime.KeepAlive(b)
|
||||||
|
|
||||||
// Handle EOF conditions.
|
// Handle EOF conditions.
|
||||||
if err == nil && n == 0 && len(b) != 0 {
|
if err == nil && n == 0 && len(b) != 0 {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
} else if err == syscall.ERROR_BROKEN_PIPE {
|
} else if err == syscall.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
} else {
|
} else {
|
||||||
return n, err
|
return n, err
|
||||||
@ -254,7 +256,7 @@ func (f *win32File) Read(b []byte) (int, error) {
|
|||||||
|
|
||||||
// Write writes to a file handle.
|
// Write writes to a file handle.
|
||||||
func (f *win32File) Write(b []byte) (int, error) {
|
func (f *win32File) Write(b []byte) (int, error) {
|
||||||
c, err := f.prepareIo()
|
c, err := f.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -266,7 +268,7 @@ func (f *win32File) Write(b []byte) (int, error) {
|
|||||||
|
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
|
err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
|
||||||
n, err := f.asyncIo(c, &f.writeDeadline, bytes, err)
|
n, err := f.asyncIO(c, &f.writeDeadline, bytes, err)
|
||||||
runtime.KeepAlive(b)
|
runtime.KeepAlive(b)
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
29
vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
29
vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
@ -14,13 +15,18 @@ import (
|
|||||||
type FileBasicInfo struct {
|
type FileBasicInfo struct {
|
||||||
CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime
|
CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime
|
||||||
FileAttributes uint32
|
FileAttributes uint32
|
||||||
pad uint32 // padding
|
_ uint32 // padding
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFileBasicInfo retrieves times and attributes for a file.
|
// GetFileBasicInfo retrieves times and attributes for a file.
|
||||||
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
||||||
bi := &FileBasicInfo{}
|
bi := &FileBasicInfo{}
|
||||||
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
|
if err := windows.GetFileInformationByHandleEx(
|
||||||
|
windows.Handle(f.Fd()),
|
||||||
|
windows.FileBasicInfo,
|
||||||
|
(*byte)(unsafe.Pointer(bi)),
|
||||||
|
uint32(unsafe.Sizeof(*bi)),
|
||||||
|
); err != nil {
|
||||||
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(f)
|
runtime.KeepAlive(f)
|
||||||
@ -29,7 +35,12 @@ func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
|||||||
|
|
||||||
// SetFileBasicInfo sets times and attributes for a file.
|
// SetFileBasicInfo sets times and attributes for a file.
|
||||||
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
|
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
|
||||||
if err := windows.SetFileInformationByHandle(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
|
if err := windows.SetFileInformationByHandle(
|
||||||
|
windows.Handle(f.Fd()),
|
||||||
|
windows.FileBasicInfo,
|
||||||
|
(*byte)(unsafe.Pointer(bi)),
|
||||||
|
uint32(unsafe.Sizeof(*bi)),
|
||||||
|
); err != nil {
|
||||||
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
|
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(f)
|
runtime.KeepAlive(f)
|
||||||
@ -48,7 +59,10 @@ type FileStandardInfo struct {
|
|||||||
// GetFileStandardInfo retrieves ended information for the file.
|
// GetFileStandardInfo retrieves ended information for the file.
|
||||||
func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) {
|
func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) {
|
||||||
si := &FileStandardInfo{}
|
si := &FileStandardInfo{}
|
||||||
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileStandardInfo, (*byte)(unsafe.Pointer(si)), uint32(unsafe.Sizeof(*si))); err != nil {
|
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()),
|
||||||
|
windows.FileStandardInfo,
|
||||||
|
(*byte)(unsafe.Pointer(si)),
|
||||||
|
uint32(unsafe.Sizeof(*si))); err != nil {
|
||||||
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(f)
|
runtime.KeepAlive(f)
|
||||||
@ -65,7 +79,12 @@ type FileIDInfo struct {
|
|||||||
// GetFileID retrieves the unique (volume, file ID) pair for a file.
|
// GetFileID retrieves the unique (volume, file ID) pair for a file.
|
||||||
func GetFileID(f *os.File) (*FileIDInfo, error) {
|
func GetFileID(f *os.File) (*FileIDInfo, error) {
|
||||||
fileID := &FileIDInfo{}
|
fileID := &FileIDInfo{}
|
||||||
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileIdInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
|
if err := windows.GetFileInformationByHandleEx(
|
||||||
|
windows.Handle(f.Fd()),
|
||||||
|
windows.FileIdInfo,
|
||||||
|
(*byte)(unsafe.Pointer(fileID)),
|
||||||
|
uint32(unsafe.Sizeof(*fileID)),
|
||||||
|
); err != nil {
|
||||||
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(f)
|
runtime.KeepAlive(f)
|
||||||
|
345
vendor/github.com/Microsoft/go-winio/hvsock.go
generated
vendored
345
vendor/github.com/Microsoft/go-winio/hvsock.go
generated
vendored
@ -4,6 +4,8 @@
|
|||||||
package winio
|
package winio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -12,16 +14,87 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
|
||||||
|
"github.com/Microsoft/go-winio/internal/socket"
|
||||||
"github.com/Microsoft/go-winio/pkg/guid"
|
"github.com/Microsoft/go-winio/pkg/guid"
|
||||||
)
|
)
|
||||||
|
|
||||||
//sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
|
const afHVSock = 34 // AF_HYPERV
|
||||||
|
|
||||||
const (
|
// Well known Service and VM IDs
|
||||||
afHvSock = 34 // AF_HYPERV
|
//https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
|
||||||
|
|
||||||
socketError = ^uintptr(0)
|
// HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions.
|
||||||
)
|
func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
|
||||||
|
return guid.GUID{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions.
|
||||||
|
func HvsockGUIDBroadcast() guid.GUID { //ffffffff-ffff-ffff-ffff-ffffffffffff
|
||||||
|
return guid.GUID{
|
||||||
|
Data1: 0xffffffff,
|
||||||
|
Data2: 0xffff,
|
||||||
|
Data3: 0xffff,
|
||||||
|
Data4: [8]uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HvsockGUIDLoopback is the Loopback VmId for accepting connections to the same partition as the connector.
|
||||||
|
func HvsockGUIDLoopback() guid.GUID { // e0e16197-dd56-4a10-9195-5ee7a155a838
|
||||||
|
return guid.GUID{
|
||||||
|
Data1: 0xe0e16197,
|
||||||
|
Data2: 0xdd56,
|
||||||
|
Data3: 0x4a10,
|
||||||
|
Data4: [8]uint8{0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HvsockGUIDSiloHost is the address of a silo's host partition:
|
||||||
|
// - The silo host of a hosted silo is the utility VM.
|
||||||
|
// - The silo host of a silo on a physical host is the physical host.
|
||||||
|
func HvsockGUIDSiloHost() guid.GUID { // 36bd0c5c-7276-4223-88ba-7d03b654c568
|
||||||
|
return guid.GUID{
|
||||||
|
Data1: 0x36bd0c5c,
|
||||||
|
Data2: 0x7276,
|
||||||
|
Data3: 0x4223,
|
||||||
|
Data4: [8]byte{0x88, 0xba, 0x7d, 0x03, 0xb6, 0x54, 0xc5, 0x68},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HvsockGUIDChildren is the wildcard VmId for accepting connections from the connector's child partitions.
|
||||||
|
func HvsockGUIDChildren() guid.GUID { // 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd
|
||||||
|
return guid.GUID{
|
||||||
|
Data1: 0x90db8b89,
|
||||||
|
Data2: 0xd35,
|
||||||
|
Data3: 0x4f79,
|
||||||
|
Data4: [8]uint8{0x8c, 0xe9, 0x49, 0xea, 0xa, 0xc8, 0xb7, 0xcd},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HvsockGUIDParent is the wildcard VmId for accepting connections from the connector's parent partition.
|
||||||
|
// Listening on this VmId accepts connection from:
|
||||||
|
// - Inside silos: silo host partition.
|
||||||
|
// - Inside hosted silo: host of the VM.
|
||||||
|
// - Inside VM: VM host.
|
||||||
|
// - Physical host: Not supported.
|
||||||
|
func HvsockGUIDParent() guid.GUID { // a42e7cda-d03f-480c-9cc2-a4de20abb878
|
||||||
|
return guid.GUID{
|
||||||
|
Data1: 0xa42e7cda,
|
||||||
|
Data2: 0xd03f,
|
||||||
|
Data3: 0x480c,
|
||||||
|
Data4: [8]uint8{0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hvsockVsockServiceTemplate is the Service GUID used for the VSOCK protocol.
|
||||||
|
func hvsockVsockServiceTemplate() guid.GUID { // 00000000-facb-11e6-bd58-64006a7986d3
|
||||||
|
return guid.GUID{
|
||||||
|
Data2: 0xfacb,
|
||||||
|
Data3: 0x11e6,
|
||||||
|
Data4: [8]uint8{0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// An HvsockAddr is an address for a AF_HYPERV socket.
|
// An HvsockAddr is an address for a AF_HYPERV socket.
|
||||||
type HvsockAddr struct {
|
type HvsockAddr struct {
|
||||||
@ -36,8 +109,10 @@ type rawHvsockAddr struct {
|
|||||||
ServiceID guid.GUID
|
ServiceID guid.GUID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ socket.RawSockaddr = &rawHvsockAddr{}
|
||||||
|
|
||||||
// Network returns the address's network name, "hvsock".
|
// Network returns the address's network name, "hvsock".
|
||||||
func (addr *HvsockAddr) Network() string {
|
func (*HvsockAddr) Network() string {
|
||||||
return "hvsock"
|
return "hvsock"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,14 +122,14 @@ func (addr *HvsockAddr) String() string {
|
|||||||
|
|
||||||
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
|
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
|
||||||
func VsockServiceID(port uint32) guid.GUID {
|
func VsockServiceID(port uint32) guid.GUID {
|
||||||
g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3")
|
g := hvsockVsockServiceTemplate() // make a copy
|
||||||
g.Data1 = port
|
g.Data1 = port
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (addr *HvsockAddr) raw() rawHvsockAddr {
|
func (addr *HvsockAddr) raw() rawHvsockAddr {
|
||||||
return rawHvsockAddr{
|
return rawHvsockAddr{
|
||||||
Family: afHvSock,
|
Family: afHVSock,
|
||||||
VMID: addr.VMID,
|
VMID: addr.VMID,
|
||||||
ServiceID: addr.ServiceID,
|
ServiceID: addr.ServiceID,
|
||||||
}
|
}
|
||||||
@ -65,20 +140,48 @@ func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
|
|||||||
addr.ServiceID = raw.ServiceID
|
addr.ServiceID = raw.ServiceID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sockaddr returns a pointer to and the size of this struct.
|
||||||
|
//
|
||||||
|
// Implements the [socket.RawSockaddr] interface, and allows use in
|
||||||
|
// [socket.Bind] and [socket.ConnectEx].
|
||||||
|
func (r *rawHvsockAddr) Sockaddr() (unsafe.Pointer, int32, error) {
|
||||||
|
return unsafe.Pointer(r), int32(unsafe.Sizeof(rawHvsockAddr{})), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sockaddr interface allows use with `sockets.Bind()` and `.ConnectEx()`.
|
||||||
|
func (r *rawHvsockAddr) FromBytes(b []byte) error {
|
||||||
|
n := int(unsafe.Sizeof(rawHvsockAddr{}))
|
||||||
|
|
||||||
|
if len(b) < n {
|
||||||
|
return fmt.Errorf("got %d, want %d: %w", len(b), n, socket.ErrBufferSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(unsafe.Slice((*byte)(unsafe.Pointer(r)), n), b[:n])
|
||||||
|
if r.Family != afHVSock {
|
||||||
|
return fmt.Errorf("got %d, want %d: %w", r.Family, afHVSock, socket.ErrAddrFamily)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// HvsockListener is a socket listener for the AF_HYPERV address family.
|
// HvsockListener is a socket listener for the AF_HYPERV address family.
|
||||||
type HvsockListener struct {
|
type HvsockListener struct {
|
||||||
sock *win32File
|
sock *win32File
|
||||||
addr HvsockAddr
|
addr HvsockAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ net.Listener = &HvsockListener{}
|
||||||
|
|
||||||
// HvsockConn is a connected socket of the AF_HYPERV address family.
|
// HvsockConn is a connected socket of the AF_HYPERV address family.
|
||||||
type HvsockConn struct {
|
type HvsockConn struct {
|
||||||
sock *win32File
|
sock *win32File
|
||||||
local, remote HvsockAddr
|
local, remote HvsockAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHvSocket() (*win32File, error) {
|
var _ net.Conn = &HvsockConn{}
|
||||||
fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1)
|
|
||||||
|
func newHVSocket() (*win32File, error) {
|
||||||
|
fd, err := syscall.Socket(afHVSock, syscall.SOCK_STREAM, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, os.NewSyscallError("socket", err)
|
return nil, os.NewSyscallError("socket", err)
|
||||||
}
|
}
|
||||||
@ -94,12 +197,12 @@ func newHvSocket() (*win32File, error) {
|
|||||||
// ListenHvsock listens for connections on the specified hvsock address.
|
// ListenHvsock listens for connections on the specified hvsock address.
|
||||||
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
|
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
|
||||||
l := &HvsockListener{addr: *addr}
|
l := &HvsockListener{addr: *addr}
|
||||||
sock, err := newHvSocket()
|
sock, err := newHVSocket()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, l.opErr("listen", err)
|
return nil, l.opErr("listen", err)
|
||||||
}
|
}
|
||||||
sa := addr.raw()
|
sa := addr.raw()
|
||||||
err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa)))
|
err = socket.Bind(windows.Handle(sock.handle), &sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, l.opErr("listen", os.NewSyscallError("socket", err))
|
return nil, l.opErr("listen", os.NewSyscallError("socket", err))
|
||||||
}
|
}
|
||||||
@ -121,7 +224,7 @@ func (l *HvsockListener) Addr() net.Addr {
|
|||||||
|
|
||||||
// Accept waits for the next connection and returns it.
|
// Accept waits for the next connection and returns it.
|
||||||
func (l *HvsockListener) Accept() (_ net.Conn, err error) {
|
func (l *HvsockListener) Accept() (_ net.Conn, err error) {
|
||||||
sock, err := newHvSocket()
|
sock, err := newHVSocket()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, l.opErr("accept", err)
|
return nil, l.opErr("accept", err)
|
||||||
}
|
}
|
||||||
@ -130,27 +233,42 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
|
|||||||
sock.Close()
|
sock.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
c, err := l.sock.prepareIo()
|
c, err := l.sock.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, l.opErr("accept", err)
|
return nil, l.opErr("accept", err)
|
||||||
}
|
}
|
||||||
defer l.sock.wg.Done()
|
defer l.sock.wg.Done()
|
||||||
|
|
||||||
// AcceptEx, per documentation, requires an extra 16 bytes per address.
|
// AcceptEx, per documentation, requires an extra 16 bytes per address.
|
||||||
|
//
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-acceptex
|
||||||
const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
|
const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
|
||||||
var addrbuf [addrlen * 2]byte
|
var addrbuf [addrlen * 2]byte
|
||||||
|
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
|
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /*rxdatalen*/, addrlen, addrlen, &bytes, &c.o)
|
||||||
_, err = l.sock.asyncIo(c, nil, bytes, err)
|
if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
|
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := &HvsockConn{
|
conn := &HvsockConn{
|
||||||
sock: sock,
|
sock: sock,
|
||||||
}
|
}
|
||||||
|
// The local address returned in the AcceptEx buffer is the same as the Listener socket's
|
||||||
|
// address. However, the service GUID reported by GetSockName is different from the Listeners
|
||||||
|
// socket, and is sometimes the same as the local address of the socket that dialed the
|
||||||
|
// address, with the service GUID.Data1 incremented, but othertimes is different.
|
||||||
|
// todo: does the local address matter? is the listener's address or the actual address appropriate?
|
||||||
conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
|
conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
|
||||||
conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
|
conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
|
||||||
|
|
||||||
|
// initialize the accepted socket and update its properties with those of the listening socket
|
||||||
|
if err = windows.Setsockopt(windows.Handle(sock.handle),
|
||||||
|
windows.SOL_SOCKET, windows.SO_UPDATE_ACCEPT_CONTEXT,
|
||||||
|
(*byte)(unsafe.Pointer(&l.sock.handle)), int32(unsafe.Sizeof(l.sock.handle))); err != nil {
|
||||||
|
return nil, conn.opErr("accept", os.NewSyscallError("setsockopt", err))
|
||||||
|
}
|
||||||
|
|
||||||
sock = nil
|
sock = nil
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
@ -160,43 +278,171 @@ func (l *HvsockListener) Close() error {
|
|||||||
return l.sock.Close()
|
return l.sock.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Need to finish ConnectEx handling
|
// HvsockDialer configures and dials a Hyper-V Socket (ie, [HvsockConn]).
|
||||||
func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) {
|
type HvsockDialer struct {
|
||||||
sock, err := newHvSocket()
|
// Deadline is the time the Dial operation must connect before erroring.
|
||||||
|
Deadline time.Time
|
||||||
|
|
||||||
|
// Retries is the number of additional connects to try if the connection times out, is refused,
|
||||||
|
// or the host is unreachable
|
||||||
|
Retries uint
|
||||||
|
|
||||||
|
// RetryWait is the time to wait after a connection error to retry
|
||||||
|
RetryWait time.Duration
|
||||||
|
|
||||||
|
rt *time.Timer // redial wait timer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial the Hyper-V socket at addr.
|
||||||
|
//
|
||||||
|
// See [HvsockDialer.Dial] for more information.
|
||||||
|
func Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) {
|
||||||
|
return (&HvsockDialer{}).Dial(ctx, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial attempts to connect to the Hyper-V socket at addr, and returns a connection if successful.
|
||||||
|
// Will attempt (HvsockDialer).Retries if dialing fails, waiting (HvsockDialer).RetryWait between
|
||||||
|
// retries.
|
||||||
|
//
|
||||||
|
// Dialing can be cancelled either by providing (HvsockDialer).Deadline, or cancelling ctx.
|
||||||
|
func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) {
|
||||||
|
op := "dial"
|
||||||
|
// create the conn early to use opErr()
|
||||||
|
conn = &HvsockConn{
|
||||||
|
remote: *addr,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !d.Deadline.IsZero() {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = context.WithDeadline(ctx, d.Deadline)
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// preemptive timeout/cancellation check
|
||||||
|
if err = ctx.Err(); err != nil {
|
||||||
|
return nil, conn.opErr(op, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sock, err := newHVSocket()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, conn.opErr(op, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if sock != nil {
|
if sock != nil {
|
||||||
sock.Close()
|
sock.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
c, err := sock.prepareIo()
|
|
||||||
|
sa := addr.raw()
|
||||||
|
err = socket.Bind(windows.Handle(sock.handle), &sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, conn.opErr(op, os.NewSyscallError("bind", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := sock.prepareIO()
|
||||||
|
if err != nil {
|
||||||
|
return nil, conn.opErr(op, err)
|
||||||
}
|
}
|
||||||
defer sock.wg.Done()
|
defer sock.wg.Done()
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o)
|
for i := uint(0); i <= d.Retries; i++ {
|
||||||
_, err = sock.asyncIo(ctx, c, nil, bytes, err)
|
err = socket.ConnectEx(
|
||||||
|
windows.Handle(sock.handle),
|
||||||
|
&sa,
|
||||||
|
nil, // sendBuf
|
||||||
|
0, // sendDataLen
|
||||||
|
&bytes,
|
||||||
|
(*windows.Overlapped)(unsafe.Pointer(&c.o)))
|
||||||
|
_, err = sock.asyncIO(c, nil, bytes, err)
|
||||||
|
if i < d.Retries && canRedial(err) {
|
||||||
|
if err = d.redialWait(ctx); err == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, conn.opErr(op, os.NewSyscallError("connectex", err))
|
||||||
}
|
}
|
||||||
conn := &HvsockConn{
|
|
||||||
sock: sock,
|
// update the connection properties, so shutdown can be used
|
||||||
remote: *addr,
|
if err = windows.Setsockopt(
|
||||||
|
windows.Handle(sock.handle),
|
||||||
|
windows.SOL_SOCKET,
|
||||||
|
windows.SO_UPDATE_CONNECT_CONTEXT,
|
||||||
|
nil, // optvalue
|
||||||
|
0, // optlen
|
||||||
|
); err != nil {
|
||||||
|
return nil, conn.opErr(op, os.NewSyscallError("setsockopt", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the local name
|
||||||
|
var sal rawHvsockAddr
|
||||||
|
err = socket.GetSockName(windows.Handle(sock.handle), &sal)
|
||||||
|
if err != nil {
|
||||||
|
return nil, conn.opErr(op, os.NewSyscallError("getsockname", err))
|
||||||
|
}
|
||||||
|
conn.local.fromRaw(&sal)
|
||||||
|
|
||||||
|
// one last check for timeout, since asyncIO doesn't check the context
|
||||||
|
if err = ctx.Err(); err != nil {
|
||||||
|
return nil, conn.opErr(op, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.sock = sock
|
||||||
sock = nil
|
sock = nil
|
||||||
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
// redialWait waits before attempting to redial, resetting the timer as appropriate.
|
||||||
|
func (d *HvsockDialer) redialWait(ctx context.Context) (err error) {
|
||||||
|
if d.RetryWait == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.rt == nil {
|
||||||
|
d.rt = time.NewTimer(d.RetryWait)
|
||||||
|
} else {
|
||||||
|
// should already be stopped and drained
|
||||||
|
d.rt.Reset(d.RetryWait)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
case <-d.rt.C:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop and drain the timer
|
||||||
|
if !d.rt.Stop() {
|
||||||
|
<-d.rt.C
|
||||||
|
}
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// assumes error is a plain, unwrapped syscall.Errno provided by direct syscall.
|
||||||
|
func canRedial(err error) bool {
|
||||||
|
//nolint:errorlint // guaranteed to be an Errno
|
||||||
|
switch err {
|
||||||
|
case windows.WSAECONNREFUSED, windows.WSAENETUNREACH, windows.WSAETIMEDOUT,
|
||||||
|
windows.ERROR_CONNECTION_REFUSED, windows.ERROR_CONNECTION_UNAVAIL:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (conn *HvsockConn) opErr(op string, err error) error {
|
func (conn *HvsockConn) opErr(op string, err error) error {
|
||||||
|
// translate from "file closed" to "socket closed"
|
||||||
|
if errors.Is(err, ErrFileClosed) {
|
||||||
|
err = socket.ErrSocketClosed
|
||||||
|
}
|
||||||
return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
|
return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *HvsockConn) Read(b []byte) (int, error) {
|
func (conn *HvsockConn) Read(b []byte) (int, error) {
|
||||||
c, err := conn.sock.prepareIo()
|
c, err := conn.sock.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, conn.opErr("read", err)
|
return 0, conn.opErr("read", err)
|
||||||
}
|
}
|
||||||
@ -204,10 +450,11 @@ func (conn *HvsockConn) Read(b []byte) (int, error) {
|
|||||||
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||||
var flags, bytes uint32
|
var flags, bytes uint32
|
||||||
err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
|
err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
|
||||||
n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err)
|
n, err := conn.sock.asyncIO(c, &conn.sock.readDeadline, bytes, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(syscall.Errno); ok {
|
var eno windows.Errno
|
||||||
err = os.NewSyscallError("wsarecv", err)
|
if errors.As(err, &eno) {
|
||||||
|
err = os.NewSyscallError("wsarecv", eno)
|
||||||
}
|
}
|
||||||
return 0, conn.opErr("read", err)
|
return 0, conn.opErr("read", err)
|
||||||
} else if n == 0 {
|
} else if n == 0 {
|
||||||
@ -230,7 +477,7 @@ func (conn *HvsockConn) Write(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (conn *HvsockConn) write(b []byte) (int, error) {
|
func (conn *HvsockConn) write(b []byte) (int, error) {
|
||||||
c, err := conn.sock.prepareIo()
|
c, err := conn.sock.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, conn.opErr("write", err)
|
return 0, conn.opErr("write", err)
|
||||||
}
|
}
|
||||||
@ -238,10 +485,11 @@ func (conn *HvsockConn) write(b []byte) (int, error) {
|
|||||||
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
|
err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
|
||||||
n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err)
|
n, err := conn.sock.asyncIO(c, &conn.sock.writeDeadline, bytes, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(syscall.Errno); ok {
|
var eno windows.Errno
|
||||||
err = os.NewSyscallError("wsasend", err)
|
if errors.As(err, &eno) {
|
||||||
|
err = os.NewSyscallError("wsasend", eno)
|
||||||
}
|
}
|
||||||
return 0, conn.opErr("write", err)
|
return 0, conn.opErr("write", err)
|
||||||
}
|
}
|
||||||
@ -257,13 +505,19 @@ func (conn *HvsockConn) IsClosed() bool {
|
|||||||
return conn.sock.IsClosed()
|
return conn.sock.IsClosed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shutdown disables sending or receiving on a socket.
|
||||||
func (conn *HvsockConn) shutdown(how int) error {
|
func (conn *HvsockConn) shutdown(how int) error {
|
||||||
if conn.IsClosed() {
|
if conn.IsClosed() {
|
||||||
return ErrFileClosed
|
return socket.ErrSocketClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
err := syscall.Shutdown(conn.sock.handle, how)
|
err := syscall.Shutdown(conn.sock.handle, how)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// If the connection was closed, shutdowns fail with "not connected"
|
||||||
|
if errors.Is(err, windows.WSAENOTCONN) ||
|
||||||
|
errors.Is(err, windows.WSAESHUTDOWN) {
|
||||||
|
err = socket.ErrSocketClosed
|
||||||
|
}
|
||||||
return os.NewSyscallError("shutdown", err)
|
return os.NewSyscallError("shutdown", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -273,7 +527,7 @@ func (conn *HvsockConn) shutdown(how int) error {
|
|||||||
func (conn *HvsockConn) CloseRead() error {
|
func (conn *HvsockConn) CloseRead() error {
|
||||||
err := conn.shutdown(syscall.SHUT_RD)
|
err := conn.shutdown(syscall.SHUT_RD)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return conn.opErr("close", err)
|
return conn.opErr("closeread", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -283,7 +537,7 @@ func (conn *HvsockConn) CloseRead() error {
|
|||||||
func (conn *HvsockConn) CloseWrite() error {
|
func (conn *HvsockConn) CloseWrite() error {
|
||||||
err := conn.shutdown(syscall.SHUT_WR)
|
err := conn.shutdown(syscall.SHUT_WR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return conn.opErr("close", err)
|
return conn.opErr("closewrite", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -300,8 +554,13 @@ func (conn *HvsockConn) RemoteAddr() net.Addr {
|
|||||||
|
|
||||||
// SetDeadline implements the net.Conn SetDeadline method.
|
// SetDeadline implements the net.Conn SetDeadline method.
|
||||||
func (conn *HvsockConn) SetDeadline(t time.Time) error {
|
func (conn *HvsockConn) SetDeadline(t time.Time) error {
|
||||||
conn.SetReadDeadline(t)
|
// todo: implement `SetDeadline` for `win32File`
|
||||||
conn.SetWriteDeadline(t)
|
if err := conn.SetReadDeadline(t); err != nil {
|
||||||
|
return fmt.Errorf("set read deadline: %w", err)
|
||||||
|
}
|
||||||
|
if err := conn.SetWriteDeadline(t); err != nil {
|
||||||
|
return fmt.Errorf("set write deadline: %w", err)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go
generated
vendored
Normal file
20
vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package socket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RawSockaddr allows structs to be used with [Bind] and [ConnectEx]. The
|
||||||
|
// struct must meet the Win32 sockaddr requirements specified here:
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/winsock/sockaddr-2
|
||||||
|
//
|
||||||
|
// Specifically, the struct size must be least larger than an int16 (unsigned short)
|
||||||
|
// for the address family.
|
||||||
|
type RawSockaddr interface {
|
||||||
|
// Sockaddr returns a pointer to the RawSockaddr and its struct size, allowing
|
||||||
|
// for the RawSockaddr's data to be overwritten by syscalls (if necessary).
|
||||||
|
//
|
||||||
|
// It is the callers responsibility to validate that the values are valid; invalid
|
||||||
|
// pointers or size can cause a panic.
|
||||||
|
Sockaddr() (unsafe.Pointer, int32, error)
|
||||||
|
}
|
179
vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
generated
vendored
Normal file
179
vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
generated
vendored
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package socket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/Microsoft/go-winio/pkg/guid"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go socket.go
|
||||||
|
|
||||||
|
//sys getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getsockname
|
||||||
|
//sys getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getpeername
|
||||||
|
//sys bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
|
||||||
|
|
||||||
|
const socketError = uintptr(^uint32(0))
|
||||||
|
|
||||||
|
var (
|
||||||
|
// todo(helsaawy): create custom error types to store the desired vs actual size and addr family?
|
||||||
|
|
||||||
|
ErrBufferSize = errors.New("buffer size")
|
||||||
|
ErrAddrFamily = errors.New("address family")
|
||||||
|
ErrInvalidPointer = errors.New("invalid pointer")
|
||||||
|
ErrSocketClosed = fmt.Errorf("socket closed: %w", net.ErrClosed)
|
||||||
|
)
|
||||||
|
|
||||||
|
// todo(helsaawy): replace these with generics, ie: GetSockName[S RawSockaddr](s windows.Handle) (S, error)
|
||||||
|
|
||||||
|
// GetSockName writes the local address of socket s to the [RawSockaddr] rsa.
|
||||||
|
// If rsa is not large enough, the [windows.WSAEFAULT] is returned.
|
||||||
|
func GetSockName(s windows.Handle, rsa RawSockaddr) error {
|
||||||
|
ptr, l, err := rsa.Sockaddr()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// although getsockname returns WSAEFAULT if the buffer is too small, it does not set
|
||||||
|
// &l to the correct size, so--apart from doubling the buffer repeatedly--there is no remedy
|
||||||
|
return getsockname(s, ptr, &l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPeerName returns the remote address the socket is connected to.
|
||||||
|
//
|
||||||
|
// See [GetSockName] for more information.
|
||||||
|
func GetPeerName(s windows.Handle, rsa RawSockaddr) error {
|
||||||
|
ptr, l, err := rsa.Sockaddr()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return getpeername(s, ptr, &l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bind(s windows.Handle, rsa RawSockaddr) (err error) {
|
||||||
|
ptr, l, err := rsa.Sockaddr()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bind(s, ptr, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// "golang.org/x/sys/windows".ConnectEx and .Bind only accept internal implementations of the
|
||||||
|
// their sockaddr interface, so they cannot be used with HvsockAddr
|
||||||
|
// Replicate functionality here from
|
||||||
|
// https://cs.opensource.google/go/x/sys/+/master:windows/syscall_windows.go
|
||||||
|
|
||||||
|
// The function pointers to `AcceptEx`, `ConnectEx` and `GetAcceptExSockaddrs` must be loaded at
|
||||||
|
// runtime via a WSAIoctl call:
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/Mswsock/nc-mswsock-lpfn_connectex#remarks
|
||||||
|
|
||||||
|
type runtimeFunc struct {
|
||||||
|
id guid.GUID
|
||||||
|
once sync.Once
|
||||||
|
addr uintptr
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *runtimeFunc) Load() error {
|
||||||
|
f.once.Do(func() {
|
||||||
|
var s windows.Handle
|
||||||
|
s, f.err = windows.Socket(windows.AF_INET, windows.SOCK_STREAM, windows.IPPROTO_TCP)
|
||||||
|
if f.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer windows.CloseHandle(s) //nolint:errcheck
|
||||||
|
|
||||||
|
var n uint32
|
||||||
|
f.err = windows.WSAIoctl(s,
|
||||||
|
windows.SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||||
|
(*byte)(unsafe.Pointer(&f.id)),
|
||||||
|
uint32(unsafe.Sizeof(f.id)),
|
||||||
|
(*byte)(unsafe.Pointer(&f.addr)),
|
||||||
|
uint32(unsafe.Sizeof(f.addr)),
|
||||||
|
&n,
|
||||||
|
nil, //overlapped
|
||||||
|
0, //completionRoutine
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return f.err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// todo: add `AcceptEx` and `GetAcceptExSockaddrs`
|
||||||
|
WSAID_CONNECTEX = guid.GUID{ //revive:disable-line:var-naming ALL_CAPS
|
||||||
|
Data1: 0x25a207b9,
|
||||||
|
Data2: 0xddf3,
|
||||||
|
Data3: 0x4660,
|
||||||
|
Data4: [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
|
||||||
|
}
|
||||||
|
|
||||||
|
connectExFunc = runtimeFunc{id: WSAID_CONNECTEX}
|
||||||
|
)
|
||||||
|
|
||||||
|
func ConnectEx(
|
||||||
|
fd windows.Handle,
|
||||||
|
rsa RawSockaddr,
|
||||||
|
sendBuf *byte,
|
||||||
|
sendDataLen uint32,
|
||||||
|
bytesSent *uint32,
|
||||||
|
overlapped *windows.Overlapped,
|
||||||
|
) error {
|
||||||
|
if err := connectExFunc.Load(); err != nil {
|
||||||
|
return fmt.Errorf("failed to load ConnectEx function pointer: %w", err)
|
||||||
|
}
|
||||||
|
ptr, n, err := rsa.Sockaddr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BOOL LpfnConnectex(
|
||||||
|
// [in] SOCKET s,
|
||||||
|
// [in] const sockaddr *name,
|
||||||
|
// [in] int namelen,
|
||||||
|
// [in, optional] PVOID lpSendBuffer,
|
||||||
|
// [in] DWORD dwSendDataLength,
|
||||||
|
// [out] LPDWORD lpdwBytesSent,
|
||||||
|
// [in] LPOVERLAPPED lpOverlapped
|
||||||
|
// )
|
||||||
|
|
||||||
|
func connectEx(
|
||||||
|
s windows.Handle,
|
||||||
|
name unsafe.Pointer,
|
||||||
|
namelen int32,
|
||||||
|
sendBuf *byte,
|
||||||
|
sendDataLen uint32,
|
||||||
|
bytesSent *uint32,
|
||||||
|
overlapped *windows.Overlapped,
|
||||||
|
) (err error) {
|
||||||
|
// todo: after upgrading to 1.18, switch from syscall.Syscall9 to syscall.SyscallN
|
||||||
|
r1, _, e1 := syscall.Syscall9(connectExFunc.addr,
|
||||||
|
7,
|
||||||
|
uintptr(s),
|
||||||
|
uintptr(name),
|
||||||
|
uintptr(namelen),
|
||||||
|
uintptr(unsafe.Pointer(sendBuf)),
|
||||||
|
uintptr(sendDataLen),
|
||||||
|
uintptr(unsafe.Pointer(bytesSent)),
|
||||||
|
uintptr(unsafe.Pointer(overlapped)),
|
||||||
|
0,
|
||||||
|
0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = error(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
72
vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
generated
vendored
Normal file
72
vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package socket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
errERROR_EINVAL error = syscall.EINVAL
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return errERROR_EINVAL
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
|
||||||
|
|
||||||
|
procbind = modws2_32.NewProc("bind")
|
||||||
|
procgetpeername = modws2_32.NewProc("getpeername")
|
||||||
|
procgetsockname = modws2_32.NewProc("getsockname")
|
||||||
|
)
|
||||||
|
|
||||||
|
func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
|
||||||
|
if r1 == socketError {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
|
||||||
|
if r1 == socketError {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
|
||||||
|
if r1 == socketError {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
124
vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
124
vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
@ -13,6 +14,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
|
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
|
||||||
@ -21,10 +24,10 @@ import (
|
|||||||
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
|
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
|
||||||
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
|
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
|
||||||
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
|
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
|
||||||
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) = ntdll.NtCreateNamedPipeFile
|
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) = ntdll.NtCreateNamedPipeFile
|
||||||
//sys rtlNtStatusToDosError(status ntstatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
|
//sys rtlNtStatusToDosError(status ntStatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
|
||||||
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U
|
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) = ntdll.RtlDosPathNameToNtPathName_U
|
||||||
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl
|
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) = ntdll.RtlDefaultNpAcl
|
||||||
|
|
||||||
type ioStatusBlock struct {
|
type ioStatusBlock struct {
|
||||||
Status, Information uintptr
|
Status, Information uintptr
|
||||||
@ -51,45 +54,22 @@ type securityDescriptor struct {
|
|||||||
Control uint16
|
Control uint16
|
||||||
Owner uintptr
|
Owner uintptr
|
||||||
Group uintptr
|
Group uintptr
|
||||||
Sacl uintptr
|
Sacl uintptr //revive:disable-line:var-naming SACL, not Sacl
|
||||||
Dacl uintptr
|
Dacl uintptr //revive:disable-line:var-naming DACL, not Dacl
|
||||||
}
|
}
|
||||||
|
|
||||||
type ntstatus int32
|
type ntStatus int32
|
||||||
|
|
||||||
func (status ntstatus) Err() error {
|
func (status ntStatus) Err() error {
|
||||||
if status >= 0 {
|
if status >= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return rtlNtStatusToDosError(status)
|
return rtlNtStatusToDosError(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
cERROR_PIPE_BUSY = syscall.Errno(231)
|
|
||||||
cERROR_NO_DATA = syscall.Errno(232)
|
|
||||||
cERROR_PIPE_CONNECTED = syscall.Errno(535)
|
|
||||||
cERROR_SEM_TIMEOUT = syscall.Errno(121)
|
|
||||||
|
|
||||||
cSECURITY_SQOS_PRESENT = 0x100000
|
|
||||||
cSECURITY_ANONYMOUS = 0
|
|
||||||
|
|
||||||
cPIPE_TYPE_MESSAGE = 4
|
|
||||||
|
|
||||||
cPIPE_READMODE_MESSAGE = 2
|
|
||||||
|
|
||||||
cFILE_OPEN = 1
|
|
||||||
cFILE_CREATE = 2
|
|
||||||
|
|
||||||
cFILE_PIPE_MESSAGE_TYPE = 1
|
|
||||||
cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2
|
|
||||||
|
|
||||||
cSE_DACL_PRESENT = 4
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
|
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
|
||||||
// This error should match net.errClosing since docker takes a dependency on its text.
|
ErrPipeListenerClosed = net.ErrClosed
|
||||||
ErrPipeListenerClosed = errors.New("use of closed network connection")
|
|
||||||
|
|
||||||
errPipeWriteClosed = errors.New("pipe has been closed for write")
|
errPipeWriteClosed = errors.New("pipe has been closed for write")
|
||||||
)
|
)
|
||||||
@ -116,9 +96,10 @@ func (f *win32Pipe) RemoteAddr() net.Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *win32Pipe) SetDeadline(t time.Time) error {
|
func (f *win32Pipe) SetDeadline(t time.Time) error {
|
||||||
f.SetReadDeadline(t)
|
if err := f.SetReadDeadline(t); err != nil {
|
||||||
f.SetWriteDeadline(t)
|
return err
|
||||||
return nil
|
}
|
||||||
|
return f.SetWriteDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloseWrite closes the write side of a message pipe in byte mode.
|
// CloseWrite closes the write side of a message pipe in byte mode.
|
||||||
@ -157,14 +138,14 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
|
|||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
n, err := f.win32File.Read(b)
|
n, err := f.win32File.Read(b)
|
||||||
if err == io.EOF {
|
if err == io.EOF { //nolint:errorlint
|
||||||
// If this was the result of a zero-byte read, then
|
// If this was the result of a zero-byte read, then
|
||||||
// it is possible that the read was due to a zero-size
|
// it is possible that the read was due to a zero-size
|
||||||
// message. Since we are simulating CloseWrite with a
|
// message. Since we are simulating CloseWrite with a
|
||||||
// zero-byte message, ensure that all future Read() calls
|
// zero-byte message, ensure that all future Read() calls
|
||||||
// also return EOF.
|
// also return EOF.
|
||||||
f.readEOF = true
|
f.readEOF = true
|
||||||
} else if err == syscall.ERROR_MORE_DATA {
|
} else if err == syscall.ERROR_MORE_DATA { //nolint:errorlint // err is Errno
|
||||||
// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
|
// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
|
||||||
// and the message still has more bytes. Treat this as a success, since
|
// and the message still has more bytes. Treat this as a success, since
|
||||||
// this package presents all named pipes as byte streams.
|
// this package presents all named pipes as byte streams.
|
||||||
@ -173,7 +154,7 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
|
|||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s pipeAddress) Network() string {
|
func (pipeAddress) Network() string {
|
||||||
return "pipe"
|
return "pipe"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,16 +165,21 @@ func (s pipeAddress) String() string {
|
|||||||
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
|
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
|
||||||
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
|
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
|
||||||
for {
|
for {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return syscall.Handle(0), ctx.Err()
|
return syscall.Handle(0), ctx.Err()
|
||||||
default:
|
default:
|
||||||
h, err := createFile(*path, access, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
|
h, err := createFile(*path,
|
||||||
|
access,
|
||||||
|
0,
|
||||||
|
nil,
|
||||||
|
syscall.OPEN_EXISTING,
|
||||||
|
windows.FILE_FLAG_OVERLAPPED|windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS,
|
||||||
|
0)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
if err != cERROR_PIPE_BUSY {
|
if err != windows.ERROR_PIPE_BUSY { //nolint:errorlint // err is Errno
|
||||||
return h, &os.PathError{Err: err, Op: "open", Path: *path}
|
return h, &os.PathError{Err: err, Op: "open", Path: *path}
|
||||||
}
|
}
|
||||||
// Wait 10 msec and try again. This is a rather simplistic
|
// Wait 10 msec and try again. This is a rather simplistic
|
||||||
@ -213,9 +199,10 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
|
|||||||
} else {
|
} else {
|
||||||
absTimeout = time.Now().Add(2 * time.Second)
|
absTimeout = time.Now().Add(2 * time.Second)
|
||||||
}
|
}
|
||||||
ctx, _ := context.WithDeadline(context.Background(), absTimeout)
|
ctx, cancel := context.WithDeadline(context.Background(), absTimeout)
|
||||||
|
defer cancel()
|
||||||
conn, err := DialPipeContext(ctx, path)
|
conn, err := DialPipeContext(ctx, path)
|
||||||
if err == context.DeadlineExceeded {
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
return nil, ErrTimeout
|
return nil, ErrTimeout
|
||||||
}
|
}
|
||||||
return conn, err
|
return conn, err
|
||||||
@ -251,7 +238,7 @@ func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn,
|
|||||||
|
|
||||||
// If the pipe is in message mode, return a message byte pipe, which
|
// If the pipe is in message mode, return a message byte pipe, which
|
||||||
// supports CloseWrite().
|
// supports CloseWrite().
|
||||||
if flags&cPIPE_TYPE_MESSAGE != 0 {
|
if flags&windows.PIPE_TYPE_MESSAGE != 0 {
|
||||||
return &win32MessageBytePipe{
|
return &win32MessageBytePipe{
|
||||||
win32Pipe: win32Pipe{win32File: f, path: path},
|
win32Pipe: win32Pipe{win32File: f, path: path},
|
||||||
}, nil
|
}, nil
|
||||||
@ -283,7 +270,11 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
|
|||||||
oa.Length = unsafe.Sizeof(oa)
|
oa.Length = unsafe.Sizeof(oa)
|
||||||
|
|
||||||
var ntPath unicodeString
|
var ntPath unicodeString
|
||||||
if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil {
|
if err := rtlDosPathNameToNtPathName(&path16[0],
|
||||||
|
&ntPath,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
).Err(); err != nil {
|
||||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||||
}
|
}
|
||||||
defer localFree(ntPath.Buffer)
|
defer localFree(ntPath.Buffer)
|
||||||
@ -292,8 +283,8 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
|
|||||||
// The security descriptor is only needed for the first pipe.
|
// The security descriptor is only needed for the first pipe.
|
||||||
if first {
|
if first {
|
||||||
if sd != nil {
|
if sd != nil {
|
||||||
len := uint32(len(sd))
|
l := uint32(len(sd))
|
||||||
sdb := localAlloc(0, len)
|
sdb := localAlloc(0, l)
|
||||||
defer localFree(sdb)
|
defer localFree(sdb)
|
||||||
copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
|
copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
|
||||||
oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
|
oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
|
||||||
@ -301,28 +292,28 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
|
|||||||
// Construct the default named pipe security descriptor.
|
// Construct the default named pipe security descriptor.
|
||||||
var dacl uintptr
|
var dacl uintptr
|
||||||
if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
|
if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
|
||||||
return 0, fmt.Errorf("getting default named pipe ACL: %s", err)
|
return 0, fmt.Errorf("getting default named pipe ACL: %w", err)
|
||||||
}
|
}
|
||||||
defer localFree(dacl)
|
defer localFree(dacl)
|
||||||
|
|
||||||
sdb := &securityDescriptor{
|
sdb := &securityDescriptor{
|
||||||
Revision: 1,
|
Revision: 1,
|
||||||
Control: cSE_DACL_PRESENT,
|
Control: windows.SE_DACL_PRESENT,
|
||||||
Dacl: dacl,
|
Dacl: dacl,
|
||||||
}
|
}
|
||||||
oa.SecurityDescriptor = sdb
|
oa.SecurityDescriptor = sdb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS)
|
typ := uint32(windows.FILE_PIPE_REJECT_REMOTE_CLIENTS)
|
||||||
if c.MessageMode {
|
if c.MessageMode {
|
||||||
typ |= cFILE_PIPE_MESSAGE_TYPE
|
typ |= windows.FILE_PIPE_MESSAGE_TYPE
|
||||||
}
|
}
|
||||||
|
|
||||||
disposition := uint32(cFILE_OPEN)
|
disposition := uint32(windows.FILE_OPEN)
|
||||||
access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE)
|
access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE)
|
||||||
if first {
|
if first {
|
||||||
disposition = cFILE_CREATE
|
disposition = windows.FILE_CREATE
|
||||||
// By not asking for read or write access, the named pipe file system
|
// By not asking for read or write access, the named pipe file system
|
||||||
// will put this pipe into an initially disconnected state, blocking
|
// will put this pipe into an initially disconnected state, blocking
|
||||||
// client connections until the next call with first == false.
|
// client connections until the next call with first == false.
|
||||||
@ -335,7 +326,20 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
|
|||||||
h syscall.Handle
|
h syscall.Handle
|
||||||
iosb ioStatusBlock
|
iosb ioStatusBlock
|
||||||
)
|
)
|
||||||
err = ntCreateNamedPipeFile(&h, access, &oa, &iosb, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, disposition, 0, typ, 0, 0, 0xffffffff, uint32(c.InputBufferSize), uint32(c.OutputBufferSize), &timeout).Err()
|
err = ntCreateNamedPipeFile(&h,
|
||||||
|
access,
|
||||||
|
&oa,
|
||||||
|
&iosb,
|
||||||
|
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE,
|
||||||
|
disposition,
|
||||||
|
0,
|
||||||
|
typ,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0xffffffff,
|
||||||
|
uint32(c.InputBufferSize),
|
||||||
|
uint32(c.OutputBufferSize),
|
||||||
|
&timeout).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||||
}
|
}
|
||||||
@ -380,7 +384,7 @@ func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) {
|
|||||||
p.Close()
|
p.Close()
|
||||||
p = nil
|
p = nil
|
||||||
err = <-ch
|
err = <-ch
|
||||||
if err == nil || err == ErrFileClosed {
|
if err == nil || err == ErrFileClosed { //nolint:errorlint // err is Errno
|
||||||
err = ErrPipeListenerClosed
|
err = ErrPipeListenerClosed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -402,12 +406,12 @@ func (l *win32PipeListener) listenerRoutine() {
|
|||||||
p, err = l.makeConnectedServerPipe()
|
p, err = l.makeConnectedServerPipe()
|
||||||
// If the connection was immediately closed by the client, try
|
// If the connection was immediately closed by the client, try
|
||||||
// again.
|
// again.
|
||||||
if err != cERROR_NO_DATA {
|
if err != windows.ERROR_NO_DATA { //nolint:errorlint // err is Errno
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
responseCh <- acceptResponse{p, err}
|
responseCh <- acceptResponse{p, err}
|
||||||
closed = err == ErrPipeListenerClosed
|
closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syscall.Close(l.firstHandle)
|
syscall.Close(l.firstHandle)
|
||||||
@ -469,15 +473,15 @@ func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func connectPipe(p *win32File) error {
|
func connectPipe(p *win32File) error {
|
||||||
c, err := p.prepareIo()
|
c, err := p.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer p.wg.Done()
|
defer p.wg.Done()
|
||||||
|
|
||||||
err = connectNamedPipe(p.handle, &c.o)
|
err = connectNamedPipe(p.handle, &c.o)
|
||||||
_, err = p.asyncIo(c, nil, 0, err)
|
_, err = p.asyncIO(c, nil, 0, err)
|
||||||
if err != nil && err != cERROR_PIPE_CONNECTED {
|
if err != nil && err != windows.ERROR_PIPE_CONNECTED { //nolint:errorlint // err is Errno
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
8
vendor/github.com/Microsoft/go-winio/pkg/etw/doc.go
generated
vendored
Normal file
8
vendor/github.com/Microsoft/go-winio/pkg/etw/doc.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Package etw provides support for TraceLogging-based ETW (Event Tracing
|
||||||
|
// for Windows). TraceLogging is a format of ETW events that are self-describing
|
||||||
|
// (the event contains information on its own schema). This allows them to be
|
||||||
|
// decoded without needing a separate manifest with event information. The
|
||||||
|
// implementation here is based on the information found in
|
||||||
|
// TraceLoggingProvider.h in the Windows SDK, which implements TraceLogging as a
|
||||||
|
// set of C macros.
|
||||||
|
package etw
|
27
vendor/github.com/Microsoft/go-winio/pkg/etw/eventdata.go
generated
vendored
27
vendor/github.com/Microsoft/go-winio/pkg/etw/eventdata.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
@ -14,60 +15,60 @@ type eventData struct {
|
|||||||
buffer bytes.Buffer
|
buffer bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// bytes returns the raw binary data containing the event data. The returned
|
// toBytes returns the raw binary data containing the event data. The returned
|
||||||
// value is not copied from the internal buffer, so it can be mutated by the
|
// value is not copied from the internal buffer, so it can be mutated by the
|
||||||
// eventData object after it is returned.
|
// eventData object after it is returned.
|
||||||
func (ed *eventData) bytes() []byte {
|
func (ed *eventData) toBytes() []byte {
|
||||||
return ed.buffer.Bytes()
|
return ed.buffer.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeString appends a string, including the null terminator, to the buffer.
|
// writeString appends a string, including the null terminator, to the buffer.
|
||||||
func (ed *eventData) writeString(data string) {
|
func (ed *eventData) writeString(data string) {
|
||||||
ed.buffer.WriteString(data)
|
_, _ = ed.buffer.WriteString(data)
|
||||||
ed.buffer.WriteByte(0)
|
_ = ed.buffer.WriteByte(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeInt8 appends a int8 to the buffer.
|
// writeInt8 appends a int8 to the buffer.
|
||||||
func (ed *eventData) writeInt8(value int8) {
|
func (ed *eventData) writeInt8(value int8) {
|
||||||
ed.buffer.WriteByte(uint8(value))
|
_ = ed.buffer.WriteByte(uint8(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeInt16 appends a int16 to the buffer.
|
// writeInt16 appends a int16 to the buffer.
|
||||||
func (ed *eventData) writeInt16(value int16) {
|
func (ed *eventData) writeInt16(value int16) {
|
||||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
_ = binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeInt32 appends a int32 to the buffer.
|
// writeInt32 appends a int32 to the buffer.
|
||||||
func (ed *eventData) writeInt32(value int32) {
|
func (ed *eventData) writeInt32(value int32) {
|
||||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
_ = binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeInt64 appends a int64 to the buffer.
|
// writeInt64 appends a int64 to the buffer.
|
||||||
func (ed *eventData) writeInt64(value int64) {
|
func (ed *eventData) writeInt64(value int64) {
|
||||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
_ = binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeUint8 appends a uint8 to the buffer.
|
// writeUint8 appends a uint8 to the buffer.
|
||||||
func (ed *eventData) writeUint8(value uint8) {
|
func (ed *eventData) writeUint8(value uint8) {
|
||||||
ed.buffer.WriteByte(value)
|
_ = ed.buffer.WriteByte(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeUint16 appends a uint16 to the buffer.
|
// writeUint16 appends a uint16 to the buffer.
|
||||||
func (ed *eventData) writeUint16(value uint16) {
|
func (ed *eventData) writeUint16(value uint16) {
|
||||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
_ = binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeUint32 appends a uint32 to the buffer.
|
// writeUint32 appends a uint32 to the buffer.
|
||||||
func (ed *eventData) writeUint32(value uint32) {
|
func (ed *eventData) writeUint32(value uint32) {
|
||||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
_ = binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeUint64 appends a uint64 to the buffer.
|
// writeUint64 appends a uint64 to the buffer.
|
||||||
func (ed *eventData) writeUint64(value uint64) {
|
func (ed *eventData) writeUint64(value uint64) {
|
||||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
_ = binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeFiletime appends a FILETIME to the buffer.
|
// writeFiletime appends a FILETIME to the buffer.
|
||||||
func (ed *eventData) writeFiletime(value syscall.Filetime) {
|
func (ed *eventData) writeFiletime(value syscall.Filetime) {
|
||||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
_ = binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
}
|
}
|
||||||
|
12
vendor/github.com/Microsoft/go-winio/pkg/etw/eventdatadescriptor.go
generated
vendored
12
vendor/github.com/Microsoft/go-winio/pkg/etw/eventdatadescriptor.go
generated
vendored
@ -1,3 +1,5 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -13,11 +15,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type eventDataDescriptor struct {
|
type eventDataDescriptor struct {
|
||||||
ptr ptr64
|
ptr ptr64
|
||||||
size uint32
|
size uint32
|
||||||
dataType eventDataDescriptorType
|
dataType eventDataDescriptorType
|
||||||
reserved1 uint8
|
_ uint8
|
||||||
reserved2 uint16
|
_ uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEventDataDescriptor(dataType eventDataDescriptorType, buffer []byte) eventDataDescriptor {
|
func newEventDataDescriptor(dataType eventDataDescriptorType, buffer []byte) eventDataDescriptor {
|
||||||
|
8
vendor/github.com/Microsoft/go-winio/pkg/etw/eventdescriptor.go
generated
vendored
8
vendor/github.com/Microsoft/go-winio/pkg/etw/eventdescriptor.go
generated
vendored
@ -1,3 +1,5 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
|
|
||||||
// Channel represents the ETW logging channel that is used. It can be used by
|
// Channel represents the ETW logging channel that is used. It can be used by
|
||||||
@ -45,6 +47,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// EventDescriptor represents various metadata for an ETW event.
|
// EventDescriptor represents various metadata for an ETW event.
|
||||||
|
//
|
||||||
|
//nolint:structcheck // task is currently unused
|
||||||
type eventDescriptor struct {
|
type eventDescriptor struct {
|
||||||
id uint16
|
id uint16
|
||||||
version uint8
|
version uint8
|
||||||
@ -70,6 +74,8 @@ func newEventDescriptor() *eventDescriptor {
|
|||||||
// should uniquely identify the other event metadata (contained in
|
// should uniquely identify the other event metadata (contained in
|
||||||
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
|
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
|
||||||
// are relevant.
|
// are relevant.
|
||||||
|
//
|
||||||
|
//nolint:unused // keep for future use
|
||||||
func (ed *eventDescriptor) identity() uint32 {
|
func (ed *eventDescriptor) identity() uint32 {
|
||||||
return (uint32(ed.version) << 16) | uint32(ed.id)
|
return (uint32(ed.version) << 16) | uint32(ed.id)
|
||||||
}
|
}
|
||||||
@ -78,6 +84,8 @@ func (ed *eventDescriptor) identity() uint32 {
|
|||||||
// should uniquely identify the other event metadata (contained in
|
// should uniquely identify the other event metadata (contained in
|
||||||
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
|
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
|
||||||
// are relevant.
|
// are relevant.
|
||||||
|
//
|
||||||
|
//nolint:unused // keep for future use
|
||||||
func (ed *eventDescriptor) setIdentity(identity uint32) {
|
func (ed *eventDescriptor) setIdentity(identity uint32) {
|
||||||
ed.id = uint16(identity)
|
ed.id = uint16(identity)
|
||||||
ed.version = uint8(identity >> 16)
|
ed.version = uint8(identity >> 16)
|
||||||
|
22
vendor/github.com/Microsoft/go-winio/pkg/etw/eventmetadata.go
generated
vendored
22
vendor/github.com/Microsoft/go-winio/pkg/etw/eventmetadata.go
generated
vendored
@ -1,3 +1,5 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -10,6 +12,8 @@ type inType byte
|
|||||||
|
|
||||||
// Various inType definitions for TraceLogging. These must match the definitions
|
// Various inType definitions for TraceLogging. These must match the definitions
|
||||||
// found in TraceLoggingProvider.h in the Windows SDK.
|
// found in TraceLoggingProvider.h in the Windows SDK.
|
||||||
|
//
|
||||||
|
//nolint:deadcode,varcheck // keep unused constants for potential future use
|
||||||
const (
|
const (
|
||||||
inTypeNull inType = iota
|
inTypeNull inType = iota
|
||||||
inTypeUnicodeString
|
inTypeUnicodeString
|
||||||
@ -47,6 +51,8 @@ type outType byte
|
|||||||
|
|
||||||
// Various outType definitions for TraceLogging. These must match the
|
// Various outType definitions for TraceLogging. These must match the
|
||||||
// definitions found in TraceLoggingProvider.h in the Windows SDK.
|
// definitions found in TraceLoggingProvider.h in the Windows SDK.
|
||||||
|
//
|
||||||
|
//nolint:deadcode,varcheck // keep unused constants for potential future use
|
||||||
const (
|
const (
|
||||||
// outTypeDefault indicates that the default formatting for the inType will
|
// outTypeDefault indicates that the default formatting for the inType will
|
||||||
// be used by the event decoder.
|
// be used by the event decoder.
|
||||||
@ -81,11 +87,11 @@ type eventMetadata struct {
|
|||||||
buffer bytes.Buffer
|
buffer bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// bytes returns the raw binary data containing the event metadata. Before being
|
// toBytes returns the raw binary data containing the event metadata. Before being
|
||||||
// returned, the current size of the buffer is written to the start of the
|
// returned, the current size of the buffer is written to the start of the
|
||||||
// buffer. The returned value is not copied from the internal buffer, so it can
|
// buffer. The returned value is not copied from the internal buffer, so it can
|
||||||
// be mutated by the eventMetadata object after it is returned.
|
// be mutated by the eventMetadata object after it is returned.
|
||||||
func (em *eventMetadata) bytes() []byte {
|
func (em *eventMetadata) toBytes() []byte {
|
||||||
// Finalize the event metadata buffer by filling in the buffer length at the
|
// Finalize the event metadata buffer by filling in the buffer length at the
|
||||||
// beginning.
|
// beginning.
|
||||||
binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len()))
|
binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len()))
|
||||||
@ -95,7 +101,7 @@ func (em *eventMetadata) bytes() []byte {
|
|||||||
// writeEventHeader writes the metadata for the start of an event to the buffer.
|
// writeEventHeader writes the metadata for the start of an event to the buffer.
|
||||||
// This specifies the event name and tags.
|
// This specifies the event name and tags.
|
||||||
func (em *eventMetadata) writeEventHeader(name string, tags uint32) {
|
func (em *eventMetadata) writeEventHeader(name string, tags uint32) {
|
||||||
binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
|
_ = binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
|
||||||
em.writeTags(tags)
|
em.writeTags(tags)
|
||||||
em.buffer.WriteString(name)
|
em.buffer.WriteString(name)
|
||||||
em.buffer.WriteByte(0) // Null terminator for name
|
em.buffer.WriteByte(0) // Null terminator for name
|
||||||
@ -118,7 +124,7 @@ func (em *eventMetadata) writeFieldInner(name string, inType inType, outType out
|
|||||||
}
|
}
|
||||||
|
|
||||||
if arrSize != 0 {
|
if arrSize != 0 {
|
||||||
binary.Write(&em.buffer, binary.LittleEndian, arrSize)
|
_ = binary.Write(&em.buffer, binary.LittleEndian, arrSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,13 +157,17 @@ func (em *eventMetadata) writeTags(tags uint32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// writeField writes the metadata for a simple field to the buffer.
|
// writeField writes the metadata for a simple field to the buffer.
|
||||||
|
//
|
||||||
|
//nolint:unparam // tags is currently always 0, may change in the future
|
||||||
func (em *eventMetadata) writeField(name string, inType inType, outType outType, tags uint32) {
|
func (em *eventMetadata) writeField(name string, inType inType, outType outType, tags uint32) {
|
||||||
em.writeFieldInner(name, inType, outType, tags, 0)
|
em.writeFieldInner(name, inType, outType, tags, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeArray writes the metadata for an array field to the buffer. The number
|
// writeArray writes the metadata for an array field to the buffer. The number
|
||||||
// of elements in the array must be written as a uint16 in the event data,
|
// of elements in the array must be written as a uint16 in the event data,
|
||||||
// immediately preceeding the event data.
|
// immediately preceding the event data.
|
||||||
|
//
|
||||||
|
//nolint:unparam // tags is currently always 0, may change in the future
|
||||||
func (em *eventMetadata) writeArray(name string, inType inType, outType outType, tags uint32) {
|
func (em *eventMetadata) writeArray(name string, inType inType, outType outType, tags uint32) {
|
||||||
em.writeFieldInner(name, inType|inTypeArray, outType, tags, 0)
|
em.writeFieldInner(name, inType|inTypeArray, outType, tags, 0)
|
||||||
}
|
}
|
||||||
@ -165,6 +175,8 @@ func (em *eventMetadata) writeArray(name string, inType inType, outType outType,
|
|||||||
// writeCountedArray writes the metadata for an array field to the buffer. The
|
// writeCountedArray writes the metadata for an array field to the buffer. The
|
||||||
// size of a counted array is fixed, and the size is written into the metadata
|
// size of a counted array is fixed, and the size is written into the metadata
|
||||||
// directly.
|
// directly.
|
||||||
|
//
|
||||||
|
//nolint:unused // keep for future use
|
||||||
func (em *eventMetadata) writeCountedArray(name string, count uint16, inType inType, outType outType, tags uint32) {
|
func (em *eventMetadata) writeCountedArray(name string, count uint16, inType inType, outType outType, tags uint32) {
|
||||||
em.writeFieldInner(name, inType|inTypeCountedArray, outType, tags, count)
|
em.writeFieldInner(name, inType|inTypeCountedArray, outType, tags, count)
|
||||||
}
|
}
|
||||||
|
1
vendor/github.com/Microsoft/go-winio/pkg/etw/eventopt.go
generated
vendored
1
vendor/github.com/Microsoft/go-winio/pkg/etw/eventopt.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
|
10
vendor/github.com/Microsoft/go-winio/pkg/etw/fieldopt.go
generated
vendored
10
vendor/github.com/Microsoft/go-winio/pkg/etw/fieldopt.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
@ -481,7 +482,7 @@ func SmartField(name string, v interface{}) FieldOpt {
|
|||||||
case reflect.Int32:
|
case reflect.Int32:
|
||||||
return SmartField(name, int32(rv.Int()))
|
return SmartField(name, int32(rv.Int()))
|
||||||
case reflect.Int64:
|
case reflect.Int64:
|
||||||
return SmartField(name, int64(rv.Int()))
|
return SmartField(name, int64(rv.Int())) //nolint:unconvert // make look consistent
|
||||||
case reflect.Uint:
|
case reflect.Uint:
|
||||||
return SmartField(name, uint(rv.Uint()))
|
return SmartField(name, uint(rv.Uint()))
|
||||||
case reflect.Uint8:
|
case reflect.Uint8:
|
||||||
@ -491,13 +492,13 @@ func SmartField(name string, v interface{}) FieldOpt {
|
|||||||
case reflect.Uint32:
|
case reflect.Uint32:
|
||||||
return SmartField(name, uint32(rv.Uint()))
|
return SmartField(name, uint32(rv.Uint()))
|
||||||
case reflect.Uint64:
|
case reflect.Uint64:
|
||||||
return SmartField(name, uint64(rv.Uint()))
|
return SmartField(name, uint64(rv.Uint())) //nolint:unconvert // make look consistent
|
||||||
case reflect.Uintptr:
|
case reflect.Uintptr:
|
||||||
return SmartField(name, uintptr(rv.Uint()))
|
return SmartField(name, uintptr(rv.Uint()))
|
||||||
case reflect.Float32:
|
case reflect.Float32:
|
||||||
return SmartField(name, float32(rv.Float()))
|
return SmartField(name, float32(rv.Float()))
|
||||||
case reflect.Float64:
|
case reflect.Float64:
|
||||||
return SmartField(name, float64(rv.Float()))
|
return SmartField(name, float64(rv.Float())) //nolint:unconvert // make look consistent
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return SmartField(name, rv.String())
|
return SmartField(name, rv.String())
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
@ -509,6 +510,9 @@ func SmartField(name string, v interface{}) FieldOpt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Struct(name, fields...)
|
return Struct(name, fields...)
|
||||||
|
case reflect.Array, reflect.Chan, reflect.Complex128, reflect.Complex64,
|
||||||
|
reflect.Func, reflect.Interface, reflect.Invalid, reflect.Map, reflect.Ptr,
|
||||||
|
reflect.Slice, reflect.UnsafePointer:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider.go
generated
vendored
15
vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows && (amd64 || arm64 || 386)
|
||||||
// +build windows
|
// +build windows
|
||||||
// +build amd64 arm64 386
|
// +build amd64 arm64 386
|
||||||
|
|
||||||
@ -45,18 +46,18 @@ func NewProviderWithOptions(name string, options ...ProviderOpt) (provider *Prov
|
|||||||
|
|
||||||
trait := &bytes.Buffer{}
|
trait := &bytes.Buffer{}
|
||||||
if opts.group != (guid.GUID{}) {
|
if opts.group != (guid.GUID{}) {
|
||||||
binary.Write(trait, binary.LittleEndian, uint16(0)) // Write empty size for buffer (update later)
|
_ = binary.Write(trait, binary.LittleEndian, uint16(0)) // Write empty size for buffer (update later)
|
||||||
binary.Write(trait, binary.LittleEndian, uint8(1)) // EtwProviderTraitTypeGroup
|
_ = binary.Write(trait, binary.LittleEndian, uint8(1)) // EtwProviderTraitTypeGroup
|
||||||
traitArray := opts.group.ToWindowsArray() // Append group guid
|
traitArray := opts.group.ToWindowsArray() // Append group guid
|
||||||
trait.Write(traitArray[:])
|
trait.Write(traitArray[:])
|
||||||
binary.LittleEndian.PutUint16(trait.Bytes(), uint16(trait.Len())) // Update size
|
binary.LittleEndian.PutUint16(trait.Bytes(), uint16(trait.Len())) // Update size
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata := &bytes.Buffer{}
|
metadata := &bytes.Buffer{}
|
||||||
binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
|
_ = binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
|
||||||
metadata.WriteString(name)
|
metadata.WriteString(name)
|
||||||
metadata.WriteByte(0) // Null terminator for name
|
metadata.WriteByte(0) // Null terminator for name
|
||||||
trait.WriteTo(metadata) // Add traits if applicable
|
_, _ = trait.WriteTo(metadata) // Add traits if applicable
|
||||||
binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
|
binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
|
||||||
provider.metadata = metadata.Bytes()
|
provider.metadata = metadata.Bytes()
|
||||||
|
|
||||||
@ -64,8 +65,8 @@ func NewProviderWithOptions(name string, options ...ProviderOpt) (provider *Prov
|
|||||||
provider.handle,
|
provider.handle,
|
||||||
eventInfoClassProviderSetTraits,
|
eventInfoClassProviderSetTraits,
|
||||||
uintptr(unsafe.Pointer(&provider.metadata[0])),
|
uintptr(unsafe.Pointer(&provider.metadata[0])),
|
||||||
uint32(len(provider.metadata))); err != nil {
|
uint32(len(provider.metadata)),
|
||||||
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider_unsupported.go
generated
vendored
4
vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider_unsupported.go
generated
vendored
@ -1,5 +1,5 @@
|
|||||||
// +build windows
|
//go:build windows && arm
|
||||||
// +build arm
|
// +build windows,arm
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
|
|
||||||
|
76
vendor/github.com/Microsoft/go-winio/pkg/etw/provider.go
generated
vendored
76
vendor/github.com/Microsoft/go-winio/pkg/etw/provider.go
generated
vendored
@ -1,9 +1,10 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1" //nolint:gosec // not used for secure application
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
@ -27,7 +28,7 @@ type Provider struct {
|
|||||||
keywordAll uint64
|
keywordAll uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the `provider`.ID as a string
|
// String returns the `provider`.ID as a string.
|
||||||
func (provider *Provider) String() string {
|
func (provider *Provider) String() string {
|
||||||
if provider == nil {
|
if provider == nil {
|
||||||
return "<nil>"
|
return "<nil>"
|
||||||
@ -54,6 +55,7 @@ const (
|
|||||||
|
|
||||||
type eventInfoClass uint32
|
type eventInfoClass uint32
|
||||||
|
|
||||||
|
//nolint:deadcode,varcheck // keep unused constants for potential future use
|
||||||
const (
|
const (
|
||||||
eventInfoClassProviderBinaryTrackInfo eventInfoClass = iota
|
eventInfoClassProviderBinaryTrackInfo eventInfoClass = iota
|
||||||
eventInfoClassProviderSetReserved1
|
eventInfoClassProviderSetReserved1
|
||||||
@ -65,10 +67,19 @@ const (
|
|||||||
// enable/disable notifications from ETW.
|
// enable/disable notifications from ETW.
|
||||||
type EnableCallback func(guid.GUID, ProviderState, Level, uint64, uint64, uintptr)
|
type EnableCallback func(guid.GUID, ProviderState, Level, uint64, uint64, uintptr)
|
||||||
|
|
||||||
func providerCallback(sourceID guid.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, i uintptr) {
|
func providerCallback(
|
||||||
|
sourceID guid.GUID,
|
||||||
|
state ProviderState,
|
||||||
|
level Level,
|
||||||
|
matchAnyKeyword uint64,
|
||||||
|
matchAllKeyword uint64,
|
||||||
|
filterData uintptr,
|
||||||
|
i uintptr,
|
||||||
|
) {
|
||||||
provider := providers.getProvider(uint(i))
|
provider := providers.getProvider(uint(i))
|
||||||
|
|
||||||
switch state {
|
switch state {
|
||||||
|
case ProviderStateCaptureState:
|
||||||
case ProviderStateDisable:
|
case ProviderStateDisable:
|
||||||
provider.enabled = false
|
provider.enabled = false
|
||||||
case ProviderStateEnable:
|
case ProviderStateEnable:
|
||||||
@ -90,17 +101,22 @@ func providerCallback(sourceID guid.GUID, state ProviderState, level Level, matc
|
|||||||
//
|
//
|
||||||
// The algorithm is roughly the RFC 4122 algorithm for a V5 UUID, but differs in
|
// The algorithm is roughly the RFC 4122 algorithm for a V5 UUID, but differs in
|
||||||
// the following ways:
|
// the following ways:
|
||||||
// - The input name is first upper-cased, UTF16-encoded, and converted to
|
// - The input name is first upper-cased, UTF16-encoded, and converted to
|
||||||
// big-endian.
|
// big-endian.
|
||||||
// - No variant is set on the result UUID.
|
// - No variant is set on the result UUID.
|
||||||
// - The result UUID is treated as being in little-endian format, rather than
|
// - The result UUID is treated as being in little-endian format, rather than
|
||||||
// big-endian.
|
// big-endian.
|
||||||
func providerIDFromName(name string) guid.GUID {
|
func providerIDFromName(name string) guid.GUID {
|
||||||
buffer := sha1.New()
|
buffer := sha1.New() //nolint:gosec // not used for secure application
|
||||||
namespace := guid.GUID{0x482C2DB2, 0xC390, 0x47C8, [8]byte{0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB}}
|
namespace := guid.GUID{
|
||||||
|
Data1: 0x482C2DB2,
|
||||||
|
Data2: 0xC390,
|
||||||
|
Data3: 0x47C8,
|
||||||
|
Data4: [8]byte{0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB},
|
||||||
|
}
|
||||||
namespaceBytes := namespace.ToArray()
|
namespaceBytes := namespace.ToArray()
|
||||||
buffer.Write(namespaceBytes[:])
|
buffer.Write(namespaceBytes[:])
|
||||||
binary.Write(buffer, binary.BigEndian, utf16.Encode([]rune(strings.ToUpper(name))))
|
_ = binary.Write(buffer, binary.BigEndian, utf16.Encode([]rune(strings.ToUpper(name))))
|
||||||
|
|
||||||
sum := buffer.Sum(nil)
|
sum := buffer.Sum(nil)
|
||||||
sum[7] = (sum[7] & 0xf) | 0x50
|
sum[7] = (sum[7] & 0xf) | 0x50
|
||||||
@ -117,25 +133,24 @@ type providerOpts struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ProviderOpt allows the caller to specify provider options to
|
// ProviderOpt allows the caller to specify provider options to
|
||||||
// NewProviderWithOptions
|
// NewProviderWithOptions.
|
||||||
type ProviderOpt func(*providerOpts)
|
type ProviderOpt func(*providerOpts)
|
||||||
|
|
||||||
// WithCallback is used to provide a callback option to NewProviderWithOptions
|
// WithCallback is used to provide a callback option to NewProviderWithOptions.
|
||||||
func WithCallback(callback EnableCallback) ProviderOpt {
|
func WithCallback(callback EnableCallback) ProviderOpt {
|
||||||
return func(opts *providerOpts) {
|
return func(opts *providerOpts) {
|
||||||
opts.callback = callback
|
opts.callback = callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithID is used to provide a provider ID option to NewProviderWithOptions
|
// WithID is used to provide a provider ID option to NewProviderWithOptions.
|
||||||
func WithID(id guid.GUID) ProviderOpt {
|
func WithID(id guid.GUID) ProviderOpt {
|
||||||
return func(opts *providerOpts) {
|
return func(opts *providerOpts) {
|
||||||
opts.id = id
|
opts.id = id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithGroup is used to provide a provider group option to
|
// WithGroup is used to provide a provider group option to NewProviderWithOptions.
|
||||||
// NewProviderWithOptions
|
|
||||||
func WithGroup(group guid.GUID) ProviderOpt {
|
func WithGroup(group guid.GUID) ProviderOpt {
|
||||||
return func(opts *providerOpts) {
|
return func(opts *providerOpts) {
|
||||||
opts.group = group
|
opts.group = group
|
||||||
@ -237,11 +252,17 @@ func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpt
|
|||||||
// event metadata (e.g. for the name) so we don't need to do this check for
|
// event metadata (e.g. for the name) so we don't need to do this check for
|
||||||
// the metadata.
|
// the metadata.
|
||||||
dataBlobs := [][]byte{}
|
dataBlobs := [][]byte{}
|
||||||
if len(ed.bytes()) > 0 {
|
if len(ed.toBytes()) > 0 {
|
||||||
dataBlobs = [][]byte{ed.bytes()}
|
dataBlobs = [][]byte{ed.toBytes()}
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider.writeEventRaw(options.descriptor, options.activityID, options.relatedActivityID, [][]byte{em.bytes()}, dataBlobs)
|
return provider.writeEventRaw(
|
||||||
|
options.descriptor,
|
||||||
|
options.activityID,
|
||||||
|
options.relatedActivityID,
|
||||||
|
[][]byte{em.toBytes()},
|
||||||
|
dataBlobs,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeEventRaw writes a single ETW event from the provider. This function is
|
// writeEventRaw writes a single ETW event from the provider. This function is
|
||||||
@ -257,17 +278,24 @@ func (provider *Provider) writeEventRaw(
|
|||||||
relatedActivityID guid.GUID,
|
relatedActivityID guid.GUID,
|
||||||
metadataBlobs [][]byte,
|
metadataBlobs [][]byte,
|
||||||
dataBlobs [][]byte) error {
|
dataBlobs [][]byte) error {
|
||||||
|
|
||||||
dataDescriptorCount := uint32(1 + len(metadataBlobs) + len(dataBlobs))
|
dataDescriptorCount := uint32(1 + len(metadataBlobs) + len(dataBlobs))
|
||||||
dataDescriptors := make([]eventDataDescriptor, 0, dataDescriptorCount)
|
dataDescriptors := make([]eventDataDescriptor, 0, dataDescriptorCount)
|
||||||
|
|
||||||
dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeProviderMetadata, provider.metadata))
|
dataDescriptors = append(dataDescriptors,
|
||||||
|
newEventDataDescriptor(eventDataDescriptorTypeProviderMetadata, provider.metadata))
|
||||||
for _, blob := range metadataBlobs {
|
for _, blob := range metadataBlobs {
|
||||||
dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeEventMetadata, blob))
|
dataDescriptors = append(dataDescriptors,
|
||||||
|
newEventDataDescriptor(eventDataDescriptorTypeEventMetadata, blob))
|
||||||
}
|
}
|
||||||
for _, blob := range dataBlobs {
|
for _, blob := range dataBlobs {
|
||||||
dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeUserData, blob))
|
dataDescriptors = append(dataDescriptors,
|
||||||
|
newEventDataDescriptor(eventDataDescriptorTypeUserData, blob))
|
||||||
}
|
}
|
||||||
|
|
||||||
return eventWriteTransfer(provider.handle, descriptor, (*windows.GUID)(&activityID), (*windows.GUID)(&relatedActivityID), dataDescriptorCount, &dataDescriptors[0])
|
return eventWriteTransfer(provider.handle,
|
||||||
|
descriptor,
|
||||||
|
(*windows.GUID)(&activityID),
|
||||||
|
(*windows.GUID)(&relatedActivityID),
|
||||||
|
dataDescriptorCount,
|
||||||
|
&dataDescriptors[0])
|
||||||
}
|
}
|
||||||
|
4
vendor/github.com/Microsoft/go-winio/pkg/etw/providerglobal.go
generated
vendored
4
vendor/github.com/Microsoft/go-winio/pkg/etw/providerglobal.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
@ -14,7 +15,6 @@ type providerMap struct {
|
|||||||
m map[uint]*Provider
|
m map[uint]*Provider
|
||||||
i uint
|
i uint
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
once sync.Once
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var providers = providerMap{
|
var providers = providerMap{
|
||||||
@ -50,5 +50,7 @@ func (p *providerMap) getProvider(index uint) *Provider {
|
|||||||
return p.m[index]
|
return p.m[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo: combine these into struct, so that "globalProviderCallback" is guaranteed to be initialized through method access
|
||||||
|
|
||||||
var providerCallbackOnce sync.Once
|
var providerCallbackOnce sync.Once
|
||||||
var globalProviderCallback uintptr
|
var globalProviderCallback uintptr
|
||||||
|
2
vendor/github.com/Microsoft/go-winio/pkg/etw/ptr64_32.go
generated
vendored
2
vendor/github.com/Microsoft/go-winio/pkg/etw/ptr64_32.go
generated
vendored
@ -1,3 +1,5 @@
|
|||||||
|
//go:build windows && (386 || arm)
|
||||||
|
// +build windows
|
||||||
// +build 386 arm
|
// +build 386 arm
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
|
2
vendor/github.com/Microsoft/go-winio/pkg/etw/ptr64_64.go
generated
vendored
2
vendor/github.com/Microsoft/go-winio/pkg/etw/ptr64_64.go
generated
vendored
@ -1,3 +1,5 @@
|
|||||||
|
//go:build windows && (amd64 || arm64)
|
||||||
|
// +build windows
|
||||||
// +build amd64 arm64
|
// +build amd64 arm64
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
// Package etw provides support for TraceLogging-based ETW (Event Tracing
|
//go:build windows
|
||||||
// for Windows). TraceLogging is a format of ETW events that are self-describing
|
|
||||||
// (the event contains information on its own schema). This allows them to be
|
|
||||||
// decoded without needing a separate manifest with event information. The
|
|
||||||
// implementation here is based on the information found in
|
|
||||||
// TraceLoggingProvider.h in the Windows SDK, which implements TraceLogging as a
|
|
||||||
// set of C macros.
|
|
||||||
package etw
|
package etw
|
||||||
|
|
||||||
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go etw.go
|
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go syscall.go
|
||||||
|
|
||||||
//sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister
|
//sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister
|
||||||
|
|
1
vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_32.go
generated
vendored
1
vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_32.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows && (386 || arm)
|
||||||
// +build windows
|
// +build windows
|
||||||
// +build 386 arm
|
// +build 386 arm
|
||||||
|
|
||||||
|
21
vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_64.go
generated
vendored
21
vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_64.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows && (amd64 || arm64)
|
||||||
// +build windows
|
// +build windows
|
||||||
// +build amd64 arm64
|
// +build amd64 arm64
|
||||||
|
|
||||||
@ -19,7 +20,6 @@ func eventWriteTransfer(
|
|||||||
relatedActivityID *windows.GUID,
|
relatedActivityID *windows.GUID,
|
||||||
dataDescriptorCount uint32,
|
dataDescriptorCount uint32,
|
||||||
dataDescriptors *eventDataDescriptor) (win32err error) {
|
dataDescriptors *eventDataDescriptor) (win32err error) {
|
||||||
|
|
||||||
return eventWriteTransfer_64(
|
return eventWriteTransfer_64(
|
||||||
providerHandle,
|
providerHandle,
|
||||||
descriptor,
|
descriptor,
|
||||||
@ -34,7 +34,6 @@ func eventSetInformation(
|
|||||||
class eventInfoClass,
|
class eventInfoClass,
|
||||||
information uintptr,
|
information uintptr,
|
||||||
length uint32) (win32err error) {
|
length uint32) (win32err error) {
|
||||||
|
|
||||||
return eventSetInformation_64(
|
return eventSetInformation_64(
|
||||||
providerHandle,
|
providerHandle,
|
||||||
class,
|
class,
|
||||||
@ -46,7 +45,21 @@ func eventSetInformation(
|
|||||||
// for provider notifications. Because Go has trouble with callback arguments of
|
// for provider notifications. Because Go has trouble with callback arguments of
|
||||||
// different size, it has only pointer-sized arguments, which are then cast to
|
// different size, it has only pointer-sized arguments, which are then cast to
|
||||||
// the appropriate types when calling providerCallback.
|
// the appropriate types when calling providerCallback.
|
||||||
func providerCallbackAdapter(sourceID *guid.GUID, state uintptr, level uintptr, matchAnyKeyword uintptr, matchAllKeyword uintptr, filterData uintptr, i uintptr) uintptr {
|
func providerCallbackAdapter(
|
||||||
providerCallback(*sourceID, ProviderState(state), Level(level), uint64(matchAnyKeyword), uint64(matchAllKeyword), filterData, i)
|
sourceID *guid.GUID,
|
||||||
|
state uintptr,
|
||||||
|
level uintptr,
|
||||||
|
matchAnyKeyword uintptr,
|
||||||
|
matchAllKeyword uintptr,
|
||||||
|
filterData uintptr,
|
||||||
|
i uintptr,
|
||||||
|
) uintptr {
|
||||||
|
providerCallback(*sourceID,
|
||||||
|
ProviderState(state),
|
||||||
|
Level(level),
|
||||||
|
uint64(matchAnyKeyword),
|
||||||
|
uint64(matchAllKeyword),
|
||||||
|
filterData,
|
||||||
|
i)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
4
vendor/github.com/Microsoft/go-winio/pkg/etw/zsyscall_windows.go
generated
vendored
4
vendor/github.com/Microsoft/go-winio/pkg/etw/zsyscall_windows.go
generated
vendored
@ -1,4 +1,6 @@
|
|||||||
// Code generated by 'go generate'; DO NOT EDIT.
|
//go:build windows
|
||||||
|
|
||||||
|
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
||||||
|
|
||||||
package etw
|
package etw
|
||||||
|
|
||||||
|
87
vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go
generated
vendored
87
vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go
generated
vendored
@ -1,40 +1,79 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package etwlogrus
|
package etwlogrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio/pkg/etw"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/Microsoft/go-winio/pkg/etw"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const defaultEventName = "LogrusEntry"
|
||||||
|
|
||||||
|
// ErrNoProvider is returned when a hook is created without a provider being configured.
|
||||||
|
var ErrNoProvider = errors.New("no ETW registered provider")
|
||||||
|
|
||||||
|
// HookOpt is an option to change the behavior of the Logrus ETW hook.
|
||||||
|
type HookOpt func(*Hook) error
|
||||||
|
|
||||||
// Hook is a Logrus hook which logs received events to ETW.
|
// Hook is a Logrus hook which logs received events to ETW.
|
||||||
type Hook struct {
|
type Hook struct {
|
||||||
provider *etw.Provider
|
provider *etw.Provider
|
||||||
closeProvider bool
|
closeProvider bool
|
||||||
|
// allows setting the entry name
|
||||||
|
getName func(*logrus.Entry) string
|
||||||
|
// returns additional options to add to the event
|
||||||
|
getEventsOpts func(*logrus.Entry) []etw.EventOpt
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHook registers a new ETW provider and returns a hook to log from it. The
|
// NewHook registers a new ETW provider and returns a hook to log from it.
|
||||||
// provider will be closed when the hook is closed.
|
// The provider will be closed when the hook is closed.
|
||||||
func NewHook(providerName string) (*Hook, error) {
|
func NewHook(providerName string, opts ...HookOpt) (*Hook, error) {
|
||||||
provider, err := etw.NewProvider(providerName, nil)
|
opts = append(opts, WithNewETWProvider(providerName))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return NewHookFromOpts(opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHookFromProvider creates a new hook based on an existing ETW provider.
|
||||||
|
// The provider will not be closed when the hook is closed.
|
||||||
|
func NewHookFromProvider(provider *etw.Provider, opts ...HookOpt) (*Hook, error) {
|
||||||
|
opts = append(opts, WithExistingETWProvider(provider))
|
||||||
|
|
||||||
|
return NewHookFromOpts(opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHookFromOpts creates a new hook with the provided options.
|
||||||
|
// An error is returned if the hook does not have a valid provider.
|
||||||
|
func NewHookFromOpts(opts ...HookOpt) (*Hook, error) {
|
||||||
|
h := defaultHook()
|
||||||
|
|
||||||
|
for _, o := range opts {
|
||||||
|
if err := o(h); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return h, h.validate()
|
||||||
return &Hook{provider, true}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHookFromProvider creates a new hook based on an existing ETW provider. The
|
func defaultHook() *Hook {
|
||||||
// provider will not be closed when the hook is closed.
|
h := &Hook{}
|
||||||
func NewHookFromProvider(provider *etw.Provider) (*Hook, error) {
|
return h
|
||||||
return &Hook{provider, false}, nil
|
}
|
||||||
|
|
||||||
|
func (h *Hook) validate() error {
|
||||||
|
if h.provider == nil {
|
||||||
|
return ErrNoProvider
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Levels returns the set of levels that this hook wants to receive log entries
|
// Levels returns the set of levels that this hook wants to receive log entries
|
||||||
// for.
|
// for.
|
||||||
func (h *Hook) Levels() []logrus.Level {
|
func (*Hook) Levels() []logrus.Level {
|
||||||
return logrus.AllLevels
|
return logrus.AllLevels
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +97,21 @@ func (h *Hook) Fire(e *logrus.Entry) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name := defaultEventName
|
||||||
|
if h.getName != nil {
|
||||||
|
if n := h.getName(e); n != "" {
|
||||||
|
name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extra room for two more options in addition to log level to avoid repeated reallocations
|
||||||
|
// if the user also provides options
|
||||||
|
opts := make([]etw.EventOpt, 0, 3)
|
||||||
|
opts = append(opts, etw.WithLevel(level))
|
||||||
|
if h.getEventsOpts != nil {
|
||||||
|
opts = append(opts, h.getEventsOpts(e)...)
|
||||||
|
}
|
||||||
|
|
||||||
// Sort the fields by name so they are consistent in each instance
|
// Sort the fields by name so they are consistent in each instance
|
||||||
// of an event. Otherwise, the fields don't line up in WPA.
|
// of an event. Otherwise, the fields don't line up in WPA.
|
||||||
names := make([]string, 0, len(e.Data))
|
names := make([]string, 0, len(e.Data))
|
||||||
@ -88,10 +142,7 @@ func (h *Hook) Fire(e *logrus.Entry) error {
|
|||||||
// as a session listening for the event having no available space in its
|
// as a session listening for the event having no available space in its
|
||||||
// buffers). Therefore, we don't return the error from WriteEvent, as it is
|
// buffers). Therefore, we don't return the error from WriteEvent, as it is
|
||||||
// just noise in many cases.
|
// just noise in many cases.
|
||||||
h.provider.WriteEvent(
|
_ = h.provider.WriteEvent(name, opts, fields)
|
||||||
"LogrusEntry",
|
|
||||||
etw.WithEventOpts(etw.WithLevel(level)),
|
|
||||||
fields)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
53
vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/opts.go
generated
vendored
Normal file
53
vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/opts.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package etwlogrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/Microsoft/go-winio/pkg/etw"
|
||||||
|
)
|
||||||
|
|
||||||
|
// etw provider
|
||||||
|
|
||||||
|
// WithNewETWProvider registers a new ETW provider and sets the hook to log using it.
|
||||||
|
// The provider will be closed when the hook is closed.
|
||||||
|
func WithNewETWProvider(n string) HookOpt {
|
||||||
|
return func(h *Hook) error {
|
||||||
|
provider, err := etw.NewProvider(n, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
h.provider = provider
|
||||||
|
h.closeProvider = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithExistingETWProvider configures the hook to use an existing ETW provider.
|
||||||
|
// The provider will not be closed when the hook is closed.
|
||||||
|
func WithExistingETWProvider(p *etw.Provider) HookOpt {
|
||||||
|
return func(h *Hook) error {
|
||||||
|
h.provider = p
|
||||||
|
h.closeProvider = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGetName sets the ETW EventName of an event to the value returned by f
|
||||||
|
// If the name is empty, the default event name will be used.
|
||||||
|
func WithGetName(f func(*logrus.Entry) string) HookOpt {
|
||||||
|
return func(h *Hook) error {
|
||||||
|
h.getName = f
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEventOpts allows additional ETW event properties (keywords, tags, etc.) to be specified.
|
||||||
|
func WithEventOpts(f func(*logrus.Entry) []etw.EventOpt) HookOpt {
|
||||||
|
return func(h *Hook) error {
|
||||||
|
h.getEventsOpts = f
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
2
vendor/github.com/Microsoft/go-winio/pkg/fs/fs_windows.go
generated
vendored
2
vendor/github.com/Microsoft/go-winio/pkg/fs/fs_windows.go
generated
vendored
@ -27,5 +27,5 @@ func GetFileSystemType(path string) (fsType string, err error) {
|
|||||||
drive += `\`
|
drive += `\`
|
||||||
err = windows.GetVolumeInformation(windows.StringToUTF16Ptr(drive), nil, 0, nil, nil, nil, &buf[0], size)
|
err = windows.GetVolumeInformation(windows.StringToUTF16Ptr(drive), nil, 0, nil, nil, nil, &buf[0], size)
|
||||||
fsType = windows.UTF16ToString(buf)
|
fsType = windows.UTF16ToString(buf)
|
||||||
return
|
return fsType, err
|
||||||
}
|
}
|
||||||
|
16
vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
generated
vendored
16
vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
generated
vendored
@ -1,5 +1,3 @@
|
|||||||
// +build windows
|
|
||||||
|
|
||||||
// Package guid provides a GUID type. The backing structure for a GUID is
|
// Package guid provides a GUID type. The backing structure for a GUID is
|
||||||
// identical to that used by the golang.org/x/sys/windows GUID type.
|
// identical to that used by the golang.org/x/sys/windows GUID type.
|
||||||
// There are two main binary encodings used for a GUID, the big-endian encoding,
|
// There are two main binary encodings used for a GUID, the big-endian encoding,
|
||||||
@ -9,24 +7,26 @@ package guid
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha1"
|
"crypto/sha1" //nolint:gosec // not used for secure application
|
||||||
"encoding"
|
"encoding"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:generate go run golang.org/x/tools/cmd/stringer -type=Variant -trimprefix=Variant -linecomment
|
||||||
|
|
||||||
// Variant specifies which GUID variant (or "type") of the GUID. It determines
|
// Variant specifies which GUID variant (or "type") of the GUID. It determines
|
||||||
// how the entirety of the rest of the GUID is interpreted.
|
// how the entirety of the rest of the GUID is interpreted.
|
||||||
type Variant uint8
|
type Variant uint8
|
||||||
|
|
||||||
// The variants specified by RFC 4122.
|
// The variants specified by RFC 4122 section 4.1.1.
|
||||||
const (
|
const (
|
||||||
// VariantUnknown specifies a GUID variant which does not conform to one of
|
// VariantUnknown specifies a GUID variant which does not conform to one of
|
||||||
// the variant encodings specified in RFC 4122.
|
// the variant encodings specified in RFC 4122.
|
||||||
VariantUnknown Variant = iota
|
VariantUnknown Variant = iota
|
||||||
VariantNCS
|
VariantNCS
|
||||||
VariantRFC4122
|
VariantRFC4122 // RFC 4122
|
||||||
VariantMicrosoft
|
VariantMicrosoft
|
||||||
VariantFuture
|
VariantFuture
|
||||||
)
|
)
|
||||||
@ -36,6 +36,10 @@ const (
|
|||||||
// hash of an input string.
|
// hash of an input string.
|
||||||
type Version uint8
|
type Version uint8
|
||||||
|
|
||||||
|
func (v Version) String() string {
|
||||||
|
return strconv.FormatUint(uint64(v), 10)
|
||||||
|
}
|
||||||
|
|
||||||
var _ = (encoding.TextMarshaler)(GUID{})
|
var _ = (encoding.TextMarshaler)(GUID{})
|
||||||
var _ = (encoding.TextUnmarshaler)(&GUID{})
|
var _ = (encoding.TextUnmarshaler)(&GUID{})
|
||||||
|
|
||||||
@ -61,7 +65,7 @@ func NewV4() (GUID, error) {
|
|||||||
// big-endian UTF16 stream of bytes. If that is desired, the string can be
|
// big-endian UTF16 stream of bytes. If that is desired, the string can be
|
||||||
// encoded as such before being passed to this function.
|
// encoded as such before being passed to this function.
|
||||||
func NewV5(namespace GUID, name []byte) (GUID, error) {
|
func NewV5(namespace GUID, name []byte) (GUID, error) {
|
||||||
b := sha1.New()
|
b := sha1.New() //nolint:gosec // not used for secure application
|
||||||
namespaceBytes := namespace.ToArray()
|
namespaceBytes := namespace.ToArray()
|
||||||
b.Write(namespaceBytes[:])
|
b.Write(namespaceBytes[:])
|
||||||
b.Write(name)
|
b.Write(name)
|
||||||
|
1
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
generated
vendored
1
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build !windows
|
||||||
// +build !windows
|
// +build !windows
|
||||||
|
|
||||||
package guid
|
package guid
|
||||||
|
3
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
generated
vendored
3
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
generated
vendored
@ -1,3 +1,6 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
package guid
|
package guid
|
||||||
|
|
||||||
import "golang.org/x/sys/windows"
|
import "golang.org/x/sys/windows"
|
||||||
|
27
vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go
generated
vendored
Normal file
27
vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Code generated by "stringer -type=Variant -trimprefix=Variant -linecomment"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package guid
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[VariantUnknown-0]
|
||||||
|
_ = x[VariantNCS-1]
|
||||||
|
_ = x[VariantRFC4122-2]
|
||||||
|
_ = x[VariantMicrosoft-3]
|
||||||
|
_ = x[VariantFuture-4]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _Variant_name = "UnknownNCSRFC 4122MicrosoftFuture"
|
||||||
|
|
||||||
|
var _Variant_index = [...]uint8{0, 7, 10, 18, 27, 33}
|
||||||
|
|
||||||
|
func (i Variant) String() string {
|
||||||
|
if i >= Variant(len(_Variant_index)-1) {
|
||||||
|
return "Variant(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _Variant_name[_Variant_index[i]:_Variant_index[i+1]]
|
||||||
|
}
|
33
vendor/github.com/Microsoft/go-winio/pkg/security/grantvmgroupaccess.go
generated
vendored
33
vendor/github.com/Microsoft/go-winio/pkg/security/grantvmgroupaccess.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package security
|
package security
|
||||||
@ -20,6 +21,7 @@ type (
|
|||||||
trusteeForm uint32
|
trusteeForm uint32
|
||||||
trusteeType uint32
|
trusteeType uint32
|
||||||
|
|
||||||
|
//nolint:structcheck // structcheck thinks fields are unused, but the are used to pass data to OS
|
||||||
explicitAccess struct {
|
explicitAccess struct {
|
||||||
accessPermissions accessMask
|
accessPermissions accessMask
|
||||||
accessMode accessMode
|
accessMode accessMode
|
||||||
@ -27,6 +29,7 @@ type (
|
|||||||
trustee trustee
|
trustee trustee
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:structcheck,unused // structcheck thinks fields are unused, but the are used to pass data to OS
|
||||||
trustee struct {
|
trustee struct {
|
||||||
multipleTrustee *trustee
|
multipleTrustee *trustee
|
||||||
multipleTrusteeOperation int32
|
multipleTrusteeOperation int32
|
||||||
@ -44,6 +47,7 @@ const (
|
|||||||
desiredAccessReadControl desiredAccess = 0x20000
|
desiredAccessReadControl desiredAccess = 0x20000
|
||||||
desiredAccessWriteDac desiredAccess = 0x40000
|
desiredAccessWriteDac desiredAccess = 0x40000
|
||||||
|
|
||||||
|
//cspell:disable-next-line
|
||||||
gvmga = "GrantVmGroupAccess:"
|
gvmga = "GrantVmGroupAccess:"
|
||||||
|
|
||||||
inheritModeNoInheritance inheritMode = 0x0
|
inheritModeNoInheritance inheritMode = 0x0
|
||||||
@ -56,9 +60,9 @@ const (
|
|||||||
shareModeRead shareMode = 0x1
|
shareModeRead shareMode = 0x1
|
||||||
shareModeWrite shareMode = 0x2
|
shareModeWrite shareMode = 0x2
|
||||||
|
|
||||||
sidVmGroup = "S-1-5-83-0"
|
sidVMGroup = "S-1-5-83-0"
|
||||||
|
|
||||||
trusteeFormIsSid trusteeForm = 0
|
trusteeFormIsSID trusteeForm = 0
|
||||||
|
|
||||||
trusteeTypeWellKnownGroup trusteeType = 5
|
trusteeTypeWellKnownGroup trusteeType = 5
|
||||||
)
|
)
|
||||||
@ -67,6 +71,8 @@ const (
|
|||||||
// include Grant ACE entries for the VM Group SID. This is a golang re-
|
// include Grant ACE entries for the VM Group SID. This is a golang re-
|
||||||
// implementation of the same function in vmcompute, just not exported in
|
// implementation of the same function in vmcompute, just not exported in
|
||||||
// RS5. Which kind of sucks. Sucks a lot :/
|
// RS5. Which kind of sucks. Sucks a lot :/
|
||||||
|
//
|
||||||
|
//revive:disable-next-line:var-naming VM, not Vm
|
||||||
func GrantVmGroupAccess(name string) error {
|
func GrantVmGroupAccess(name string) error {
|
||||||
// Stat (to determine if `name` is a directory).
|
// Stat (to determine if `name` is a directory).
|
||||||
s, err := os.Stat(name)
|
s, err := os.Stat(name)
|
||||||
@ -79,7 +85,7 @@ func GrantVmGroupAccess(name string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err // Already wrapped
|
return err // Already wrapped
|
||||||
}
|
}
|
||||||
defer syscall.CloseHandle(fd)
|
defer syscall.CloseHandle(fd) //nolint:errcheck
|
||||||
|
|
||||||
// Get the current DACL and Security Descriptor. Must defer LocalFree on success.
|
// Get the current DACL and Security Descriptor. Must defer LocalFree on success.
|
||||||
ot := objectTypeFileObject
|
ot := objectTypeFileObject
|
||||||
@ -89,7 +95,7 @@ func GrantVmGroupAccess(name string) error {
|
|||||||
if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
|
if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
|
||||||
return fmt.Errorf("%s GetSecurityInfo %s: %w", gvmga, name, err)
|
return fmt.Errorf("%s GetSecurityInfo %s: %w", gvmga, name, err)
|
||||||
}
|
}
|
||||||
defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd)))
|
defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd))) //nolint:errcheck
|
||||||
|
|
||||||
// Generate a new DACL which is the current DACL with the required ACEs added.
|
// Generate a new DACL which is the current DACL with the required ACEs added.
|
||||||
// Must defer LocalFree on success.
|
// Must defer LocalFree on success.
|
||||||
@ -97,7 +103,7 @@ func GrantVmGroupAccess(name string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err // Already wrapped
|
return err // Already wrapped
|
||||||
}
|
}
|
||||||
defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL)))
|
defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL))) //nolint:errcheck
|
||||||
|
|
||||||
// And finally use SetSecurityInfo to apply the updated DACL.
|
// And finally use SetSecurityInfo to apply the updated DACL.
|
||||||
if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
|
if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
|
||||||
@ -110,16 +116,19 @@ func GrantVmGroupAccess(name string) error {
|
|||||||
// createFile is a helper function to call [Nt]CreateFile to get a handle to
|
// createFile is a helper function to call [Nt]CreateFile to get a handle to
|
||||||
// the file or directory.
|
// the file or directory.
|
||||||
func createFile(name string, isDir bool) (syscall.Handle, error) {
|
func createFile(name string, isDir bool) (syscall.Handle, error) {
|
||||||
namep := syscall.StringToUTF16(name)
|
namep, err := syscall.UTF16FromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return syscall.InvalidHandle, fmt.Errorf("could not convernt name to UTF-16: %w", err)
|
||||||
|
}
|
||||||
da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
|
da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
|
||||||
sm := uint32(shareModeRead | shareModeWrite)
|
sm := uint32(shareModeRead | shareModeWrite)
|
||||||
fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
|
fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
|
||||||
if isDir {
|
if isDir {
|
||||||
fa = uint32(fa | syscall.FILE_FLAG_BACKUP_SEMANTICS)
|
fa |= syscall.FILE_FLAG_BACKUP_SEMANTICS
|
||||||
}
|
}
|
||||||
fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0)
|
fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("%s syscall.CreateFile %s: %w", gvmga, name, err)
|
return syscall.InvalidHandle, fmt.Errorf("%s syscall.CreateFile %s: %w", gvmga, name, err)
|
||||||
}
|
}
|
||||||
return fd, nil
|
return fd, nil
|
||||||
}
|
}
|
||||||
@ -128,9 +137,9 @@ func createFile(name string, isDir bool) (syscall.Handle, error) {
|
|||||||
// The caller is responsible for LocalFree of the returned DACL on success.
|
// The caller is responsible for LocalFree of the returned DACL on success.
|
||||||
func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintptr, error) {
|
func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintptr, error) {
|
||||||
// Generate pointers to the SIDs based on the string SIDs
|
// Generate pointers to the SIDs based on the string SIDs
|
||||||
sid, err := syscall.StringToSid(sidVmGroup)
|
sid, err := syscall.StringToSid(sidVMGroup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("%s syscall.StringToSid %s %s: %w", gvmga, name, sidVmGroup, err)
|
return 0, fmt.Errorf("%s syscall.StringToSid %s %s: %w", gvmga, name, sidVMGroup, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
inheritance := inheritModeNoInheritance
|
inheritance := inheritModeNoInheritance
|
||||||
@ -139,12 +148,12 @@ func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintp
|
|||||||
}
|
}
|
||||||
|
|
||||||
eaArray := []explicitAccess{
|
eaArray := []explicitAccess{
|
||||||
explicitAccess{
|
{
|
||||||
accessPermissions: accessMaskDesiredPermission,
|
accessPermissions: accessMaskDesiredPermission,
|
||||||
accessMode: accessModeGrant,
|
accessMode: accessModeGrant,
|
||||||
inheritance: inheritance,
|
inheritance: inheritance,
|
||||||
trustee: trustee{
|
trustee: trustee{
|
||||||
trusteeForm: trusteeFormIsSid,
|
trusteeForm: trusteeFormIsSID,
|
||||||
trusteeType: trusteeTypeWellKnownGroup,
|
trusteeType: trusteeTypeWellKnownGroup,
|
||||||
name: uintptr(unsafe.Pointer(sid)),
|
name: uintptr(unsafe.Pointer(sid)),
|
||||||
},
|
},
|
||||||
|
2
vendor/github.com/Microsoft/go-winio/pkg/security/syscall_windows.go
generated
vendored
2
vendor/github.com/Microsoft/go-winio/pkg/security/syscall_windows.go
generated
vendored
@ -1,6 +1,6 @@
|
|||||||
package security
|
package security
|
||||||
|
|
||||||
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
|
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
|
||||||
|
|
||||||
//sys getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (win32err error) = advapi32.GetSecurityInfo
|
//sys getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (win32err error) = advapi32.GetSecurityInfo
|
||||||
//sys setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (win32err error) = advapi32.SetSecurityInfo
|
//sys setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (win32err error) = advapi32.SetSecurityInfo
|
||||||
|
4
vendor/github.com/Microsoft/go-winio/pkg/security/zsyscall_windows.go
generated
vendored
4
vendor/github.com/Microsoft/go-winio/pkg/security/zsyscall_windows.go
generated
vendored
@ -1,4 +1,6 @@
|
|||||||
// Code generated by 'go generate'; DO NOT EDIT.
|
//go:build windows
|
||||||
|
|
||||||
|
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
||||||
|
|
||||||
package security
|
package security
|
||||||
|
|
||||||
|
32
vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
32
vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
@ -24,22 +25,17 @@ import (
|
|||||||
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
|
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SE_PRIVILEGE_ENABLED = 2
|
//revive:disable-next-line:var-naming ALL_CAPS
|
||||||
|
SE_PRIVILEGE_ENABLED = windows.SE_PRIVILEGE_ENABLED
|
||||||
|
|
||||||
ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
|
//revive:disable-next-line:var-naming ALL_CAPS
|
||||||
|
ERROR_NOT_ALL_ASSIGNED syscall.Errno = windows.ERROR_NOT_ALL_ASSIGNED
|
||||||
|
|
||||||
SeBackupPrivilege = "SeBackupPrivilege"
|
SeBackupPrivilege = "SeBackupPrivilege"
|
||||||
SeRestorePrivilege = "SeRestorePrivilege"
|
SeRestorePrivilege = "SeRestorePrivilege"
|
||||||
SeSecurityPrivilege = "SeSecurityPrivilege"
|
SeSecurityPrivilege = "SeSecurityPrivilege"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
securityAnonymous = iota
|
|
||||||
securityIdentification
|
|
||||||
securityImpersonation
|
|
||||||
securityDelegation
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
privNames = make(map[string]uint64)
|
privNames = make(map[string]uint64)
|
||||||
privNameMutex sync.Mutex
|
privNameMutex sync.Mutex
|
||||||
@ -51,11 +47,9 @@ type PrivilegeError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *PrivilegeError) Error() string {
|
func (e *PrivilegeError) Error() string {
|
||||||
s := ""
|
s := "Could not enable privilege "
|
||||||
if len(e.privileges) > 1 {
|
if len(e.privileges) > 1 {
|
||||||
s = "Could not enable privileges "
|
s = "Could not enable privileges "
|
||||||
} else {
|
|
||||||
s = "Could not enable privilege "
|
|
||||||
}
|
}
|
||||||
for i, p := range e.privileges {
|
for i, p := range e.privileges {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
@ -94,7 +88,7 @@ func RunWithPrivileges(names []string, fn func() error) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mapPrivileges(names []string) ([]uint64, error) {
|
func mapPrivileges(names []string) ([]uint64, error) {
|
||||||
var privileges []uint64
|
privileges := make([]uint64, 0, len(names))
|
||||||
privNameMutex.Lock()
|
privNameMutex.Lock()
|
||||||
defer privNameMutex.Unlock()
|
defer privNameMutex.Unlock()
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
@ -127,7 +121,7 @@ func enableDisableProcessPrivilege(names []string, action uint32) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
p, _ := windows.GetCurrentProcess()
|
p := windows.CurrentProcess()
|
||||||
var token windows.Token
|
var token windows.Token
|
||||||
err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
|
err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -140,10 +134,10 @@ func enableDisableProcessPrivilege(names []string, action uint32) error {
|
|||||||
|
|
||||||
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
|
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
|
_ = binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
|
||||||
for _, p := range privileges {
|
for _, p := range privileges {
|
||||||
binary.Write(&b, binary.LittleEndian, p)
|
_ = binary.Write(&b, binary.LittleEndian, p)
|
||||||
binary.Write(&b, binary.LittleEndian, action)
|
_ = binary.Write(&b, binary.LittleEndian, action)
|
||||||
}
|
}
|
||||||
prevState := make([]byte, b.Len())
|
prevState := make([]byte, b.Len())
|
||||||
reqSize := uint32(0)
|
reqSize := uint32(0)
|
||||||
@ -151,7 +145,7 @@ func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) e
|
|||||||
if !success {
|
if !success {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err == ERROR_NOT_ALL_ASSIGNED {
|
if err == ERROR_NOT_ALL_ASSIGNED { //nolint:errorlint // err is Errno
|
||||||
return &PrivilegeError{privileges}
|
return &PrivilegeError{privileges}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -177,7 +171,7 @@ func getPrivilegeName(luid uint64) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newThreadToken() (windows.Token, error) {
|
func newThreadToken() (windows.Token, error) {
|
||||||
err := impersonateSelf(securityImpersonation)
|
err := impersonateSelf(windows.SecurityImpersonation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
11
vendor/github.com/Microsoft/go-winio/reparse.go
generated
vendored
11
vendor/github.com/Microsoft/go-winio/reparse.go
generated
vendored
@ -1,3 +1,6 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -113,16 +116,16 @@ func EncodeReparsePoint(rp *ReparsePoint) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
binary.Write(&b, binary.LittleEndian, &data)
|
_ = binary.Write(&b, binary.LittleEndian, &data)
|
||||||
if !rp.IsMountPoint {
|
if !rp.IsMountPoint {
|
||||||
flags := uint32(0)
|
flags := uint32(0)
|
||||||
if relative {
|
if relative {
|
||||||
flags |= 1
|
flags |= 1
|
||||||
}
|
}
|
||||||
binary.Write(&b, binary.LittleEndian, flags)
|
_ = binary.Write(&b, binary.LittleEndian, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
binary.Write(&b, binary.LittleEndian, ntTarget16)
|
_ = binary.Write(&b, binary.LittleEndian, ntTarget16)
|
||||||
binary.Write(&b, binary.LittleEndian, target16)
|
_ = binary.Write(&b, binary.LittleEndian, target16)
|
||||||
return b.Bytes()
|
return b.Bytes()
|
||||||
}
|
}
|
||||||
|
64
vendor/github.com/Microsoft/go-winio/sd.go
generated
vendored
64
vendor/github.com/Microsoft/go-winio/sd.go
generated
vendored
@ -1,23 +1,25 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
|
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
|
||||||
|
//sys lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountSidW
|
||||||
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
|
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
|
||||||
|
//sys convertStringSidToSid(str *uint16, sid **byte) (err error) = advapi32.ConvertStringSidToSidW
|
||||||
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
|
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
|
||||||
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
|
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
|
||||||
//sys localFree(mem uintptr) = LocalFree
|
//sys localFree(mem uintptr) = LocalFree
|
||||||
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
|
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
|
||||||
|
|
||||||
const (
|
|
||||||
cERROR_NONE_MAPPED = syscall.Errno(1332)
|
|
||||||
)
|
|
||||||
|
|
||||||
type AccountLookupError struct {
|
type AccountLookupError struct {
|
||||||
Name string
|
Name string
|
||||||
Err error
|
Err error
|
||||||
@ -28,8 +30,10 @@ func (e *AccountLookupError) Error() string {
|
|||||||
return "lookup account: empty account name specified"
|
return "lookup account: empty account name specified"
|
||||||
}
|
}
|
||||||
var s string
|
var s string
|
||||||
switch e.Err {
|
switch {
|
||||||
case cERROR_NONE_MAPPED:
|
case errors.Is(e.Err, windows.ERROR_INVALID_SID):
|
||||||
|
s = "the security ID structure is invalid"
|
||||||
|
case errors.Is(e.Err, windows.ERROR_NONE_MAPPED):
|
||||||
s = "not found"
|
s = "not found"
|
||||||
default:
|
default:
|
||||||
s = e.Err.Error()
|
s = e.Err.Error()
|
||||||
@ -37,6 +41,8 @@ func (e *AccountLookupError) Error() string {
|
|||||||
return "lookup account " + e.Name + ": " + s
|
return "lookup account " + e.Name + ": " + s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *AccountLookupError) Unwrap() error { return e.Err }
|
||||||
|
|
||||||
type SddlConversionError struct {
|
type SddlConversionError struct {
|
||||||
Sddl string
|
Sddl string
|
||||||
Err error
|
Err error
|
||||||
@ -46,15 +52,19 @@ func (e *SddlConversionError) Error() string {
|
|||||||
return "convert " + e.Sddl + ": " + e.Err.Error()
|
return "convert " + e.Sddl + ": " + e.Err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *SddlConversionError) Unwrap() error { return e.Err }
|
||||||
|
|
||||||
// LookupSidByName looks up the SID of an account by name
|
// LookupSidByName looks up the SID of an account by name
|
||||||
|
//
|
||||||
|
//revive:disable-next-line:var-naming SID, not Sid
|
||||||
func LookupSidByName(name string) (sid string, err error) {
|
func LookupSidByName(name string) (sid string, err error) {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
|
return "", &AccountLookupError{name, windows.ERROR_NONE_MAPPED}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sidSize, sidNameUse, refDomainSize uint32
|
var sidSize, sidNameUse, refDomainSize uint32
|
||||||
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
|
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
|
||||||
if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
|
if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
|
||||||
return "", &AccountLookupError{name, err}
|
return "", &AccountLookupError{name, err}
|
||||||
}
|
}
|
||||||
sidBuffer := make([]byte, sidSize)
|
sidBuffer := make([]byte, sidSize)
|
||||||
@ -73,6 +83,42 @@ func LookupSidByName(name string) (sid string, err error) {
|
|||||||
return sid, nil
|
return sid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LookupNameBySid looks up the name of an account by SID
|
||||||
|
//
|
||||||
|
//revive:disable-next-line:var-naming SID, not Sid
|
||||||
|
func LookupNameBySid(sid string) (name string, err error) {
|
||||||
|
if sid == "" {
|
||||||
|
return "", &AccountLookupError{sid, windows.ERROR_NONE_MAPPED}
|
||||||
|
}
|
||||||
|
|
||||||
|
sidBuffer, err := windows.UTF16PtrFromString(sid)
|
||||||
|
if err != nil {
|
||||||
|
return "", &AccountLookupError{sid, err}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sidPtr *byte
|
||||||
|
if err = convertStringSidToSid(sidBuffer, &sidPtr); err != nil {
|
||||||
|
return "", &AccountLookupError{sid, err}
|
||||||
|
}
|
||||||
|
defer localFree(uintptr(unsafe.Pointer(sidPtr)))
|
||||||
|
|
||||||
|
var nameSize, refDomainSize, sidNameUse uint32
|
||||||
|
err = lookupAccountSid(nil, sidPtr, nil, &nameSize, nil, &refDomainSize, &sidNameUse)
|
||||||
|
if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
|
||||||
|
return "", &AccountLookupError{sid, err}
|
||||||
|
}
|
||||||
|
|
||||||
|
nameBuffer := make([]uint16, nameSize)
|
||||||
|
refDomainBuffer := make([]uint16, refDomainSize)
|
||||||
|
err = lookupAccountSid(nil, sidPtr, &nameBuffer[0], &nameSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
|
||||||
|
if err != nil {
|
||||||
|
return "", &AccountLookupError{sid, err}
|
||||||
|
}
|
||||||
|
|
||||||
|
name = windows.UTF16ToString(nameBuffer)
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
|
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
|
||||||
var sdBuffer uintptr
|
var sdBuffer uintptr
|
||||||
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
|
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
|
||||||
@ -87,7 +133,7 @@ func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
|
|||||||
|
|
||||||
func SecurityDescriptorToSddl(sd []byte) (string, error) {
|
func SecurityDescriptorToSddl(sd []byte) (string, error) {
|
||||||
var sddl *uint16
|
var sddl *uint16
|
||||||
// The returned string length seems to including an aribtrary number of terminating NULs.
|
// The returned string length seems to include an arbitrary number of terminating NULs.
|
||||||
// Don't use it.
|
// Don't use it.
|
||||||
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
|
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
4
vendor/github.com/Microsoft/go-winio/syscall.go
generated
vendored
4
vendor/github.com/Microsoft/go-winio/syscall.go
generated
vendored
@ -1,3 +1,5 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
|
|
||||||
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go
|
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go ./*.go
|
||||||
|
5
vendor/github.com/Microsoft/go-winio/tools.go
generated
vendored
Normal file
5
vendor/github.com/Microsoft/go-winio/tools.go
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//go:build tools
|
||||||
|
|
||||||
|
package winio
|
||||||
|
|
||||||
|
import _ "golang.org/x/tools/cmd/stringer"
|
59
vendor/github.com/Microsoft/go-winio/vhd/vhd.go
generated
vendored
59
vendor/github.com/Microsoft/go-winio/vhd/vhd.go
generated
vendored
@ -11,7 +11,7 @@ import (
|
|||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run mksyscall_windows.go -output zvhd_windows.go vhd.go
|
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zvhd_windows.go vhd.go
|
||||||
|
|
||||||
//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) = virtdisk.CreateVirtualDisk
|
//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) = virtdisk.CreateVirtualDisk
|
||||||
//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) = virtdisk.OpenVirtualDisk
|
//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) = virtdisk.OpenVirtualDisk
|
||||||
@ -62,8 +62,8 @@ type OpenVirtualDiskParameters struct {
|
|||||||
Version2 OpenVersion2
|
Version2 OpenVersion2
|
||||||
}
|
}
|
||||||
|
|
||||||
// The higher level `OpenVersion2` struct uses bools to refer to `GetInfoOnly` and `ReadOnly` for ease of use. However,
|
// The higher level `OpenVersion2` struct uses `bool`s to refer to `GetInfoOnly` and `ReadOnly` for ease of use. However,
|
||||||
// the internal windows structure uses `BOOLS` aka int32s for these types. `openVersion2` is used for translating
|
// the internal windows structure uses `BOOL`s aka int32s for these types. `openVersion2` is used for translating
|
||||||
// `OpenVersion2` fields to the correct windows internal field types on the `Open____` methods.
|
// `OpenVersion2` fields to the correct windows internal field types on the `Open____` methods.
|
||||||
type openVersion2 struct {
|
type openVersion2 struct {
|
||||||
getInfoOnly int32
|
getInfoOnly int32
|
||||||
@ -87,9 +87,10 @@ type AttachVirtualDiskParameters struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
//revive:disable-next-line:var-naming ALL_CAPS
|
||||||
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 0x3
|
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 0x3
|
||||||
|
|
||||||
// Access Mask for opening a VHD
|
// Access Mask for opening a VHD.
|
||||||
VirtualDiskAccessNone VirtualDiskAccessMask = 0x00000000
|
VirtualDiskAccessNone VirtualDiskAccessMask = 0x00000000
|
||||||
VirtualDiskAccessAttachRO VirtualDiskAccessMask = 0x00010000
|
VirtualDiskAccessAttachRO VirtualDiskAccessMask = 0x00010000
|
||||||
VirtualDiskAccessAttachRW VirtualDiskAccessMask = 0x00020000
|
VirtualDiskAccessAttachRW VirtualDiskAccessMask = 0x00020000
|
||||||
@ -101,7 +102,7 @@ const (
|
|||||||
VirtualDiskAccessAll VirtualDiskAccessMask = 0x003f0000
|
VirtualDiskAccessAll VirtualDiskAccessMask = 0x003f0000
|
||||||
VirtualDiskAccessWritable VirtualDiskAccessMask = 0x00320000
|
VirtualDiskAccessWritable VirtualDiskAccessMask = 0x00320000
|
||||||
|
|
||||||
// Flags for creating a VHD
|
// Flags for creating a VHD.
|
||||||
CreateVirtualDiskFlagNone CreateVirtualDiskFlag = 0x0
|
CreateVirtualDiskFlagNone CreateVirtualDiskFlag = 0x0
|
||||||
CreateVirtualDiskFlagFullPhysicalAllocation CreateVirtualDiskFlag = 0x1
|
CreateVirtualDiskFlagFullPhysicalAllocation CreateVirtualDiskFlag = 0x1
|
||||||
CreateVirtualDiskFlagPreventWritesToSourceDisk CreateVirtualDiskFlag = 0x2
|
CreateVirtualDiskFlagPreventWritesToSourceDisk CreateVirtualDiskFlag = 0x2
|
||||||
@ -109,12 +110,12 @@ const (
|
|||||||
CreateVirtualDiskFlagCreateBackingStorage CreateVirtualDiskFlag = 0x8
|
CreateVirtualDiskFlagCreateBackingStorage CreateVirtualDiskFlag = 0x8
|
||||||
CreateVirtualDiskFlagUseChangeTrackingSourceLimit CreateVirtualDiskFlag = 0x10
|
CreateVirtualDiskFlagUseChangeTrackingSourceLimit CreateVirtualDiskFlag = 0x10
|
||||||
CreateVirtualDiskFlagPreserveParentChangeTrackingState CreateVirtualDiskFlag = 0x20
|
CreateVirtualDiskFlagPreserveParentChangeTrackingState CreateVirtualDiskFlag = 0x20
|
||||||
CreateVirtualDiskFlagVhdSetUseOriginalBackingStorage CreateVirtualDiskFlag = 0x40
|
CreateVirtualDiskFlagVhdSetUseOriginalBackingStorage CreateVirtualDiskFlag = 0x40 //revive:disable-line:var-naming VHD, not Vhd
|
||||||
CreateVirtualDiskFlagSparseFile CreateVirtualDiskFlag = 0x80
|
CreateVirtualDiskFlagSparseFile CreateVirtualDiskFlag = 0x80
|
||||||
CreateVirtualDiskFlagPmemCompatible CreateVirtualDiskFlag = 0x100
|
CreateVirtualDiskFlagPmemCompatible CreateVirtualDiskFlag = 0x100 //revive:disable-line:var-naming PMEM, not Pmem
|
||||||
CreateVirtualDiskFlagSupportCompressedVolumes CreateVirtualDiskFlag = 0x200
|
CreateVirtualDiskFlagSupportCompressedVolumes CreateVirtualDiskFlag = 0x200
|
||||||
|
|
||||||
// Flags for opening a VHD
|
// Flags for opening a VHD.
|
||||||
OpenVirtualDiskFlagNone VirtualDiskFlag = 0x00000000
|
OpenVirtualDiskFlagNone VirtualDiskFlag = 0x00000000
|
||||||
OpenVirtualDiskFlagNoParents VirtualDiskFlag = 0x00000001
|
OpenVirtualDiskFlagNoParents VirtualDiskFlag = 0x00000001
|
||||||
OpenVirtualDiskFlagBlankFile VirtualDiskFlag = 0x00000002
|
OpenVirtualDiskFlagBlankFile VirtualDiskFlag = 0x00000002
|
||||||
@ -127,7 +128,7 @@ const (
|
|||||||
OpenVirtualDiskFlagNoWriteHardening VirtualDiskFlag = 0x00000100
|
OpenVirtualDiskFlagNoWriteHardening VirtualDiskFlag = 0x00000100
|
||||||
OpenVirtualDiskFlagSupportCompressedVolumes VirtualDiskFlag = 0x00000200
|
OpenVirtualDiskFlagSupportCompressedVolumes VirtualDiskFlag = 0x00000200
|
||||||
|
|
||||||
// Flags for attaching a VHD
|
// Flags for attaching a VHD.
|
||||||
AttachVirtualDiskFlagNone AttachVirtualDiskFlag = 0x00000000
|
AttachVirtualDiskFlagNone AttachVirtualDiskFlag = 0x00000000
|
||||||
AttachVirtualDiskFlagReadOnly AttachVirtualDiskFlag = 0x00000001
|
AttachVirtualDiskFlagReadOnly AttachVirtualDiskFlag = 0x00000001
|
||||||
AttachVirtualDiskFlagNoDriveLetter AttachVirtualDiskFlag = 0x00000002
|
AttachVirtualDiskFlagNoDriveLetter AttachVirtualDiskFlag = 0x00000002
|
||||||
@ -140,12 +141,14 @@ const (
|
|||||||
AttachVirtualDiskFlagSinglePartition AttachVirtualDiskFlag = 0x00000100
|
AttachVirtualDiskFlagSinglePartition AttachVirtualDiskFlag = 0x00000100
|
||||||
AttachVirtualDiskFlagRegisterVolume AttachVirtualDiskFlag = 0x00000200
|
AttachVirtualDiskFlagRegisterVolume AttachVirtualDiskFlag = 0x00000200
|
||||||
|
|
||||||
// Flags for detaching a VHD
|
// Flags for detaching a VHD.
|
||||||
DetachVirtualDiskFlagNone DetachVirtualDiskFlag = 0x0
|
DetachVirtualDiskFlagNone DetachVirtualDiskFlag = 0x0
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateVhdx is a helper function to create a simple vhdx file at the given path using
|
// CreateVhdx is a helper function to create a simple vhdx file at the given path using
|
||||||
// default values.
|
// default values.
|
||||||
|
//
|
||||||
|
//revive:disable-next-line:var-naming VHDX, not Vhdx
|
||||||
func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
|
func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
|
||||||
params := CreateVirtualDiskParameters{
|
params := CreateVirtualDiskParameters{
|
||||||
Version: 2,
|
Version: 2,
|
||||||
@ -172,6 +175,8 @@ func DetachVirtualDisk(handle syscall.Handle) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DetachVhd detaches a vhd found at `path`.
|
// DetachVhd detaches a vhd found at `path`.
|
||||||
|
//
|
||||||
|
//revive:disable-next-line:var-naming VHD, not Vhd
|
||||||
func DetachVhd(path string) error {
|
func DetachVhd(path string) error {
|
||||||
handle, err := OpenVirtualDisk(
|
handle, err := OpenVirtualDisk(
|
||||||
path,
|
path,
|
||||||
@ -181,12 +186,16 @@ func DetachVhd(path string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer syscall.CloseHandle(handle)
|
defer syscall.CloseHandle(handle) //nolint:errcheck
|
||||||
return DetachVirtualDisk(handle)
|
return DetachVirtualDisk(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AttachVirtualDisk attaches a virtual hard disk for use.
|
// AttachVirtualDisk attaches a virtual hard disk for use.
|
||||||
func AttachVirtualDisk(handle syscall.Handle, attachVirtualDiskFlag AttachVirtualDiskFlag, parameters *AttachVirtualDiskParameters) (err error) {
|
func AttachVirtualDisk(
|
||||||
|
handle syscall.Handle,
|
||||||
|
attachVirtualDiskFlag AttachVirtualDiskFlag,
|
||||||
|
parameters *AttachVirtualDiskParameters,
|
||||||
|
) (err error) {
|
||||||
// Supports both version 1 and 2 of the attach parameters as version 2 wasn't present in RS5.
|
// Supports both version 1 and 2 of the attach parameters as version 2 wasn't present in RS5.
|
||||||
if err := attachVirtualDisk(
|
if err := attachVirtualDisk(
|
||||||
handle,
|
handle,
|
||||||
@ -203,6 +212,8 @@ func AttachVirtualDisk(handle syscall.Handle, attachVirtualDiskFlag AttachVirtua
|
|||||||
|
|
||||||
// AttachVhd attaches a virtual hard disk at `path` for use. Attaches using version 2
|
// AttachVhd attaches a virtual hard disk at `path` for use. Attaches using version 2
|
||||||
// of the ATTACH_VIRTUAL_DISK_PARAMETERS.
|
// of the ATTACH_VIRTUAL_DISK_PARAMETERS.
|
||||||
|
//
|
||||||
|
//revive:disable-next-line:var-naming VHD, not Vhd
|
||||||
func AttachVhd(path string) (err error) {
|
func AttachVhd(path string) (err error) {
|
||||||
handle, err := OpenVirtualDisk(
|
handle, err := OpenVirtualDisk(
|
||||||
path,
|
path,
|
||||||
@ -213,7 +224,7 @@ func AttachVhd(path string) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer syscall.CloseHandle(handle)
|
defer syscall.CloseHandle(handle) //nolint:errcheck
|
||||||
params := AttachVirtualDiskParameters{Version: 2}
|
params := AttachVirtualDiskParameters{Version: 2}
|
||||||
if err := AttachVirtualDisk(
|
if err := AttachVirtualDisk(
|
||||||
handle,
|
handle,
|
||||||
@ -226,7 +237,11 @@ func AttachVhd(path string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OpenVirtualDisk obtains a handle to a VHD opened with supplied access mask and flags.
|
// OpenVirtualDisk obtains a handle to a VHD opened with supplied access mask and flags.
|
||||||
func OpenVirtualDisk(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag) (syscall.Handle, error) {
|
func OpenVirtualDisk(
|
||||||
|
vhdPath string,
|
||||||
|
virtualDiskAccessMask VirtualDiskAccessMask,
|
||||||
|
openVirtualDiskFlags VirtualDiskFlag,
|
||||||
|
) (syscall.Handle, error) {
|
||||||
parameters := OpenVirtualDiskParameters{Version: 2}
|
parameters := OpenVirtualDiskParameters{Version: 2}
|
||||||
handle, err := OpenVirtualDiskWithParameters(
|
handle, err := OpenVirtualDiskWithParameters(
|
||||||
vhdPath,
|
vhdPath,
|
||||||
@ -241,7 +256,12 @@ func OpenVirtualDisk(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OpenVirtualDiskWithParameters obtains a handle to a VHD opened with supplied access mask, flags and parameters.
|
// OpenVirtualDiskWithParameters obtains a handle to a VHD opened with supplied access mask, flags and parameters.
|
||||||
func OpenVirtualDiskWithParameters(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag, parameters *OpenVirtualDiskParameters) (syscall.Handle, error) {
|
func OpenVirtualDiskWithParameters(
|
||||||
|
vhdPath string,
|
||||||
|
virtualDiskAccessMask VirtualDiskAccessMask,
|
||||||
|
openVirtualDiskFlags VirtualDiskFlag,
|
||||||
|
parameters *OpenVirtualDiskParameters,
|
||||||
|
) (syscall.Handle, error) {
|
||||||
var (
|
var (
|
||||||
handle syscall.Handle
|
handle syscall.Handle
|
||||||
defaultType VirtualStorageType
|
defaultType VirtualStorageType
|
||||||
@ -279,7 +299,12 @@ func OpenVirtualDiskWithParameters(vhdPath string, virtualDiskAccessMask Virtual
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateVirtualDisk creates a virtual harddisk and returns a handle to the disk.
|
// CreateVirtualDisk creates a virtual harddisk and returns a handle to the disk.
|
||||||
func CreateVirtualDisk(path string, virtualDiskAccessMask VirtualDiskAccessMask, createVirtualDiskFlags CreateVirtualDiskFlag, parameters *CreateVirtualDiskParameters) (syscall.Handle, error) {
|
func CreateVirtualDisk(
|
||||||
|
path string,
|
||||||
|
virtualDiskAccessMask VirtualDiskAccessMask,
|
||||||
|
createVirtualDiskFlags CreateVirtualDiskFlag,
|
||||||
|
parameters *CreateVirtualDiskParameters,
|
||||||
|
) (syscall.Handle, error) {
|
||||||
var (
|
var (
|
||||||
handle syscall.Handle
|
handle syscall.Handle
|
||||||
defaultType VirtualStorageType
|
defaultType VirtualStorageType
|
||||||
@ -323,6 +348,8 @@ func GetVirtualDiskPhysicalPath(handle syscall.Handle) (_ string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateDiffVhd is a helper function to create a differencing virtual disk.
|
// CreateDiffVhd is a helper function to create a differencing virtual disk.
|
||||||
|
//
|
||||||
|
//revive:disable-next-line:var-naming VHD, not Vhd
|
||||||
func CreateDiffVhd(diffVhdPath, baseVhdPath string, blockSizeInMB uint32) error {
|
func CreateDiffVhd(diffVhdPath, baseVhdPath string, blockSizeInMB uint32) error {
|
||||||
// Setting `ParentPath` is how to signal to create a differencing disk.
|
// Setting `ParentPath` is how to signal to create a differencing disk.
|
||||||
createParams := &CreateVirtualDiskParameters{
|
createParams := &CreateVirtualDiskParameters{
|
||||||
|
4
vendor/github.com/Microsoft/go-winio/vhd/zvhd_windows.go
generated
vendored
4
vendor/github.com/Microsoft/go-winio/vhd/zvhd_windows.go
generated
vendored
@ -1,4 +1,6 @@
|
|||||||
// Code generated by 'go generate'; DO NOT EDIT.
|
//go:build windows
|
||||||
|
|
||||||
|
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
||||||
|
|
||||||
package vhd
|
package vhd
|
||||||
|
|
||||||
|
45
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
generated
vendored
45
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
generated
vendored
@ -1,4 +1,6 @@
|
|||||||
// Code generated by 'go generate'; DO NOT EDIT.
|
//go:build windows
|
||||||
|
|
||||||
|
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
|
|
||||||
@ -47,9 +49,11 @@ var (
|
|||||||
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
|
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
|
||||||
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
|
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
|
||||||
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
|
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
|
||||||
|
procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
|
||||||
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
|
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
|
||||||
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
|
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
|
||||||
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
|
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
|
||||||
|
procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
|
||||||
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
||||||
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
|
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
|
||||||
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
|
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
|
||||||
@ -74,7 +78,6 @@ var (
|
|||||||
procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
|
procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
|
||||||
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
|
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
|
||||||
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
|
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
|
||||||
procbind = modws2_32.NewProc("bind")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
|
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
|
||||||
@ -123,6 +126,14 @@ func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convertStringSidToSid(str *uint16, sid **byte) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(sid)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
|
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
|
||||||
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
|
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
|
||||||
len = uint32(r0)
|
len = uint32(r0)
|
||||||
@ -154,6 +165,14 @@ func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidS
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
||||||
var _p0 *uint16
|
var _p0 *uint16
|
||||||
_p0, err = syscall.UTF16PtrFromString(systemName)
|
_p0, err = syscall.UTF16PtrFromString(systemName)
|
||||||
@ -380,25 +399,25 @@ func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err erro
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) {
|
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) {
|
||||||
r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0)
|
r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0)
|
||||||
status = ntstatus(r0)
|
status = ntStatus(r0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) {
|
func rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) {
|
||||||
r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
|
r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
|
||||||
status = ntstatus(r0)
|
status = ntStatus(r0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) {
|
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) {
|
||||||
r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0)
|
r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0)
|
||||||
status = ntstatus(r0)
|
status = ntStatus(r0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func rtlNtStatusToDosError(status ntstatus) (winerr error) {
|
func rtlNtStatusToDosError(status ntStatus) (winerr error) {
|
||||||
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
|
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
|
||||||
if r0 != 0 {
|
if r0 != 0 {
|
||||||
winerr = syscall.Errno(r0)
|
winerr = syscall.Errno(r0)
|
||||||
@ -417,11 +436,3 @@ func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) {
|
|
||||||
r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
|
|
||||||
if r1 == socketError {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
27
vendor/golang.org/x/mod/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/mod/LICENSE
generated
vendored
Normal 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.
|
22
vendor/golang.org/x/mod/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/mod/PATENTS
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
401
vendor/golang.org/x/mod/semver/semver.go
generated
vendored
Normal file
401
vendor/golang.org/x/mod/semver/semver.go
generated
vendored
Normal file
@ -0,0 +1,401 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package semver implements comparison of semantic version strings.
|
||||||
|
// In this package, semantic version strings must begin with a leading "v",
|
||||||
|
// as in "v1.0.0".
|
||||||
|
//
|
||||||
|
// The general form of a semantic version string accepted by this package is
|
||||||
|
//
|
||||||
|
// vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]]
|
||||||
|
//
|
||||||
|
// where square brackets indicate optional parts of the syntax;
|
||||||
|
// MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros;
|
||||||
|
// PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers
|
||||||
|
// using only alphanumeric characters and hyphens; and
|
||||||
|
// all-numeric PRERELEASE identifiers must not have leading zeros.
|
||||||
|
//
|
||||||
|
// This package follows Semantic Versioning 2.0.0 (see semver.org)
|
||||||
|
// with two exceptions. First, it requires the "v" prefix. Second, it recognizes
|
||||||
|
// vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes)
|
||||||
|
// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
|
||||||
|
package semver
|
||||||
|
|
||||||
|
import "sort"
|
||||||
|
|
||||||
|
// parsed returns the parsed form of a semantic version string.
|
||||||
|
type parsed struct {
|
||||||
|
major string
|
||||||
|
minor string
|
||||||
|
patch string
|
||||||
|
short string
|
||||||
|
prerelease string
|
||||||
|
build string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid reports whether v is a valid semantic version string.
|
||||||
|
func IsValid(v string) bool {
|
||||||
|
_, ok := parse(v)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Canonical returns the canonical formatting of the semantic version v.
|
||||||
|
// It fills in any missing .MINOR or .PATCH and discards build metadata.
|
||||||
|
// Two semantic versions compare equal only if their canonical formattings
|
||||||
|
// are identical strings.
|
||||||
|
// The canonical invalid semantic version is the empty string.
|
||||||
|
func Canonical(v string) string {
|
||||||
|
p, ok := parse(v)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if p.build != "" {
|
||||||
|
return v[:len(v)-len(p.build)]
|
||||||
|
}
|
||||||
|
if p.short != "" {
|
||||||
|
return v + p.short
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Major returns the major version prefix of the semantic version v.
|
||||||
|
// For example, Major("v2.1.0") == "v2".
|
||||||
|
// If v is an invalid semantic version string, Major returns the empty string.
|
||||||
|
func Major(v string) string {
|
||||||
|
pv, ok := parse(v)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return v[:1+len(pv.major)]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MajorMinor returns the major.minor version prefix of the semantic version v.
|
||||||
|
// For example, MajorMinor("v2.1.0") == "v2.1".
|
||||||
|
// If v is an invalid semantic version string, MajorMinor returns the empty string.
|
||||||
|
func MajorMinor(v string) string {
|
||||||
|
pv, ok := parse(v)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
i := 1 + len(pv.major)
|
||||||
|
if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor {
|
||||||
|
return v[:j]
|
||||||
|
}
|
||||||
|
return v[:i] + "." + pv.minor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prerelease returns the prerelease suffix of the semantic version v.
|
||||||
|
// For example, Prerelease("v2.1.0-pre+meta") == "-pre".
|
||||||
|
// If v is an invalid semantic version string, Prerelease returns the empty string.
|
||||||
|
func Prerelease(v string) string {
|
||||||
|
pv, ok := parse(v)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return pv.prerelease
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build returns the build suffix of the semantic version v.
|
||||||
|
// For example, Build("v2.1.0+meta") == "+meta".
|
||||||
|
// If v is an invalid semantic version string, Build returns the empty string.
|
||||||
|
func Build(v string) string {
|
||||||
|
pv, ok := parse(v)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return pv.build
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare returns an integer comparing two versions according to
|
||||||
|
// semantic version precedence.
|
||||||
|
// The result will be 0 if v == w, -1 if v < w, or +1 if v > w.
|
||||||
|
//
|
||||||
|
// An invalid semantic version string is considered less than a valid one.
|
||||||
|
// All invalid semantic version strings compare equal to each other.
|
||||||
|
func Compare(v, w string) int {
|
||||||
|
pv, ok1 := parse(v)
|
||||||
|
pw, ok2 := parse(w)
|
||||||
|
if !ok1 && !ok2 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if !ok1 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if !ok2 {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
if c := compareInt(pv.major, pw.major); c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
if c := compareInt(pv.minor, pw.minor); c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
if c := compareInt(pv.patch, pw.patch); c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return comparePrerelease(pv.prerelease, pw.prerelease)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max canonicalizes its arguments and then returns the version string
|
||||||
|
// that compares greater.
|
||||||
|
//
|
||||||
|
// Deprecated: use Compare instead. In most cases, returning a canonicalized
|
||||||
|
// version is not expected or desired.
|
||||||
|
func Max(v, w string) string {
|
||||||
|
v = Canonical(v)
|
||||||
|
w = Canonical(w)
|
||||||
|
if Compare(v, w) > 0 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByVersion implements sort.Interface for sorting semantic version strings.
|
||||||
|
type ByVersion []string
|
||||||
|
|
||||||
|
func (vs ByVersion) Len() int { return len(vs) }
|
||||||
|
func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
|
||||||
|
func (vs ByVersion) Less(i, j int) bool {
|
||||||
|
cmp := Compare(vs[i], vs[j])
|
||||||
|
if cmp != 0 {
|
||||||
|
return cmp < 0
|
||||||
|
}
|
||||||
|
return vs[i] < vs[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort sorts a list of semantic version strings using ByVersion.
|
||||||
|
func Sort(list []string) {
|
||||||
|
sort.Sort(ByVersion(list))
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(v string) (p parsed, ok bool) {
|
||||||
|
if v == "" || v[0] != 'v' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.major, v, ok = parseInt(v[1:])
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v == "" {
|
||||||
|
p.minor = "0"
|
||||||
|
p.patch = "0"
|
||||||
|
p.short = ".0.0"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v[0] != '.' {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.minor, v, ok = parseInt(v[1:])
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v == "" {
|
||||||
|
p.patch = "0"
|
||||||
|
p.short = ".0"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v[0] != '.' {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.patch, v, ok = parseInt(v[1:])
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(v) > 0 && v[0] == '-' {
|
||||||
|
p.prerelease, v, ok = parsePrerelease(v)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(v) > 0 && v[0] == '+' {
|
||||||
|
p.build, v, ok = parseBuild(v)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v != "" {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInt(v string) (t, rest string, ok bool) {
|
||||||
|
if v == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v[0] < '0' || '9' < v[0] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i := 1
|
||||||
|
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if v[0] == '0' && i != 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return v[:i], v[i:], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePrerelease(v string) (t, rest string, ok bool) {
|
||||||
|
// "A pre-release version MAY be denoted by appending a hyphen and
|
||||||
|
// a series of dot separated identifiers immediately following the patch version.
|
||||||
|
// Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-].
|
||||||
|
// Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes."
|
||||||
|
if v == "" || v[0] != '-' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i := 1
|
||||||
|
start := 1
|
||||||
|
for i < len(v) && v[i] != '+' {
|
||||||
|
if !isIdentChar(v[i]) && v[i] != '.' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v[i] == '.' {
|
||||||
|
if start == i || isBadNum(v[start:i]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start = i + 1
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if start == i || isBadNum(v[start:i]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return v[:i], v[i:], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBuild(v string) (t, rest string, ok bool) {
|
||||||
|
if v == "" || v[0] != '+' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i := 1
|
||||||
|
start := 1
|
||||||
|
for i < len(v) {
|
||||||
|
if !isIdentChar(v[i]) && v[i] != '.' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v[i] == '.' {
|
||||||
|
if start == i {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start = i + 1
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if start == i {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return v[:i], v[i:], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIdentChar(c byte) bool {
|
||||||
|
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isBadNum(v string) bool {
|
||||||
|
i := 0
|
||||||
|
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i == len(v) && i > 1 && v[0] == '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNum(v string) bool {
|
||||||
|
i := 0
|
||||||
|
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i == len(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareInt(x, y string) int {
|
||||||
|
if x == y {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if len(x) < len(y) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if len(x) > len(y) {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
if x < y {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func comparePrerelease(x, y string) int {
|
||||||
|
// "When major, minor, and patch are equal, a pre-release version has
|
||||||
|
// lower precedence than a normal version.
|
||||||
|
// Example: 1.0.0-alpha < 1.0.0.
|
||||||
|
// Precedence for two pre-release versions with the same major, minor,
|
||||||
|
// and patch version MUST be determined by comparing each dot separated
|
||||||
|
// identifier from left to right until a difference is found as follows:
|
||||||
|
// identifiers consisting of only digits are compared numerically and
|
||||||
|
// identifiers with letters or hyphens are compared lexically in ASCII
|
||||||
|
// sort order. Numeric identifiers always have lower precedence than
|
||||||
|
// non-numeric identifiers. A larger set of pre-release fields has a
|
||||||
|
// higher precedence than a smaller set, if all of the preceding
|
||||||
|
// identifiers are equal.
|
||||||
|
// Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta <
|
||||||
|
// 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0."
|
||||||
|
if x == y {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if x == "" {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
if y == "" {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
for x != "" && y != "" {
|
||||||
|
x = x[1:] // skip - or .
|
||||||
|
y = y[1:] // skip - or .
|
||||||
|
var dx, dy string
|
||||||
|
dx, x = nextIdent(x)
|
||||||
|
dy, y = nextIdent(y)
|
||||||
|
if dx != dy {
|
||||||
|
ix := isNum(dx)
|
||||||
|
iy := isNum(dy)
|
||||||
|
if ix != iy {
|
||||||
|
if ix {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ix {
|
||||||
|
if len(dx) < len(dy) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if len(dx) > len(dy) {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dx < dy {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if x == "" {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextIdent(x string) (dx, rest string) {
|
||||||
|
i := 0
|
||||||
|
for i < len(x) && x[i] != '.' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return x[:i], x[i:]
|
||||||
|
}
|
27
vendor/golang.org/x/tools/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/tools/LICENSE
generated
vendored
Normal 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.
|
22
vendor/golang.org/x/tools/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/tools/PATENTS
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
658
vendor/golang.org/x/tools/cmd/stringer/stringer.go
generated
vendored
Normal file
658
vendor/golang.org/x/tools/cmd/stringer/stringer.go
generated
vendored
Normal file
@ -0,0 +1,658 @@
|
|||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// Stringer is a tool to automate the creation of methods that satisfy the fmt.Stringer
|
||||||
|
// interface. Given the name of a (signed or unsigned) integer type T that has constants
|
||||||
|
// defined, stringer will create a new self-contained Go source file implementing
|
||||||
|
//
|
||||||
|
// func (t T) String() string
|
||||||
|
//
|
||||||
|
// The file is created in the same package and directory as the package that defines T.
|
||||||
|
// It has helpful defaults designed for use with go generate.
|
||||||
|
//
|
||||||
|
// Stringer works best with constants that are consecutive values such as created using iota,
|
||||||
|
// but creates good code regardless. In the future it might also provide custom support for
|
||||||
|
// constant sets that are bit patterns.
|
||||||
|
//
|
||||||
|
// For example, given this snippet,
|
||||||
|
//
|
||||||
|
// package painkiller
|
||||||
|
//
|
||||||
|
// type Pill int
|
||||||
|
//
|
||||||
|
// const (
|
||||||
|
// Placebo Pill = iota
|
||||||
|
// Aspirin
|
||||||
|
// Ibuprofen
|
||||||
|
// Paracetamol
|
||||||
|
// Acetaminophen = Paracetamol
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// running this command
|
||||||
|
//
|
||||||
|
// stringer -type=Pill
|
||||||
|
//
|
||||||
|
// in the same directory will create the file pill_string.go, in package painkiller,
|
||||||
|
// containing a definition of
|
||||||
|
//
|
||||||
|
// func (Pill) String() string
|
||||||
|
//
|
||||||
|
// That method will translate the value of a Pill constant to the string representation
|
||||||
|
// of the respective constant name, so that the call fmt.Print(painkiller.Aspirin) will
|
||||||
|
// print the string "Aspirin".
|
||||||
|
//
|
||||||
|
// Typically this process would be run using go generate, like this:
|
||||||
|
//
|
||||||
|
// //go:generate stringer -type=Pill
|
||||||
|
//
|
||||||
|
// If multiple constants have the same value, the lexically first matching name will
|
||||||
|
// be used (in the example, Acetaminophen will print as "Paracetamol").
|
||||||
|
//
|
||||||
|
// With no arguments, it processes the package in the current directory.
|
||||||
|
// Otherwise, the arguments must name a single directory holding a Go package
|
||||||
|
// or a set of Go source files that represent a single Go package.
|
||||||
|
//
|
||||||
|
// The -type flag accepts a comma-separated list of types so a single run can
|
||||||
|
// generate methods for multiple types. The default output file is t_string.go,
|
||||||
|
// where t is the lower-cased name of the first type listed. It can be overridden
|
||||||
|
// with the -output flag.
|
||||||
|
//
|
||||||
|
// The -linecomment flag tells stringer to generate the text of any line comment, trimmed
|
||||||
|
// of leading spaces, instead of the constant name. For instance, if the constants above had a
|
||||||
|
// Pill prefix, one could write
|
||||||
|
//
|
||||||
|
// PillAspirin // Aspirin
|
||||||
|
//
|
||||||
|
// to suppress it in the output.
|
||||||
|
package main // import "golang.org/x/tools/cmd/stringer"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/constant"
|
||||||
|
"go/format"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
typeNames = flag.String("type", "", "comma-separated list of type names; must be set")
|
||||||
|
output = flag.String("output", "", "output file name; default srcdir/<type>_string.go")
|
||||||
|
trimprefix = flag.String("trimprefix", "", "trim the `prefix` from the generated constant names")
|
||||||
|
linecomment = flag.Bool("linecomment", false, "use line comment text as printed text when present")
|
||||||
|
buildTags = flag.String("tags", "", "comma-separated list of build tags to apply")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Usage is a replacement usage function for the flags package.
|
||||||
|
func Usage() {
|
||||||
|
fmt.Fprintf(os.Stderr, "Usage of stringer:\n")
|
||||||
|
fmt.Fprintf(os.Stderr, "\tstringer [flags] -type T [directory]\n")
|
||||||
|
fmt.Fprintf(os.Stderr, "\tstringer [flags] -type T files... # Must be a single package\n")
|
||||||
|
fmt.Fprintf(os.Stderr, "For more information, see:\n")
|
||||||
|
fmt.Fprintf(os.Stderr, "\thttps://pkg.go.dev/golang.org/x/tools/cmd/stringer\n")
|
||||||
|
fmt.Fprintf(os.Stderr, "Flags:\n")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.SetPrefix("stringer: ")
|
||||||
|
flag.Usage = Usage
|
||||||
|
flag.Parse()
|
||||||
|
if len(*typeNames) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
types := strings.Split(*typeNames, ",")
|
||||||
|
var tags []string
|
||||||
|
if len(*buildTags) > 0 {
|
||||||
|
tags = strings.Split(*buildTags, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We accept either one directory or a list of files. Which do we have?
|
||||||
|
args := flag.Args()
|
||||||
|
if len(args) == 0 {
|
||||||
|
// Default: process whole package in current directory.
|
||||||
|
args = []string{"."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the package once.
|
||||||
|
var dir string
|
||||||
|
g := Generator{
|
||||||
|
trimPrefix: *trimprefix,
|
||||||
|
lineComment: *linecomment,
|
||||||
|
}
|
||||||
|
// TODO(suzmue): accept other patterns for packages (directories, list of files, import paths, etc).
|
||||||
|
if len(args) == 1 && isDirectory(args[0]) {
|
||||||
|
dir = args[0]
|
||||||
|
} else {
|
||||||
|
if len(tags) != 0 {
|
||||||
|
log.Fatal("-tags option applies only to directories, not when files are specified")
|
||||||
|
}
|
||||||
|
dir = filepath.Dir(args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
g.parsePackage(args, tags)
|
||||||
|
|
||||||
|
// Print the header and package clause.
|
||||||
|
g.Printf("// Code generated by \"stringer %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " "))
|
||||||
|
g.Printf("\n")
|
||||||
|
g.Printf("package %s", g.pkg.name)
|
||||||
|
g.Printf("\n")
|
||||||
|
g.Printf("import \"strconv\"\n") // Used by all methods.
|
||||||
|
|
||||||
|
// Run generate for each type.
|
||||||
|
for _, typeName := range types {
|
||||||
|
g.generate(typeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the output.
|
||||||
|
src := g.format()
|
||||||
|
|
||||||
|
// Write to file.
|
||||||
|
outputName := *output
|
||||||
|
if outputName == "" {
|
||||||
|
baseName := fmt.Sprintf("%s_string.go", types[0])
|
||||||
|
outputName = filepath.Join(dir, strings.ToLower(baseName))
|
||||||
|
}
|
||||||
|
err := ioutil.WriteFile(outputName, src, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("writing output: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDirectory reports whether the named file is a directory.
|
||||||
|
func isDirectory(name string) bool {
|
||||||
|
info, err := os.Stat(name)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return info.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generator holds the state of the analysis. Primarily used to buffer
|
||||||
|
// the output for format.Source.
|
||||||
|
type Generator struct {
|
||||||
|
buf bytes.Buffer // Accumulated output.
|
||||||
|
pkg *Package // Package we are scanning.
|
||||||
|
|
||||||
|
trimPrefix string
|
||||||
|
lineComment bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Generator) Printf(format string, args ...interface{}) {
|
||||||
|
fmt.Fprintf(&g.buf, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// File holds a single parsed file and associated data.
|
||||||
|
type File struct {
|
||||||
|
pkg *Package // Package to which this file belongs.
|
||||||
|
file *ast.File // Parsed AST.
|
||||||
|
// These fields are reset for each type being generated.
|
||||||
|
typeName string // Name of the constant type.
|
||||||
|
values []Value // Accumulator for constant values of that type.
|
||||||
|
|
||||||
|
trimPrefix string
|
||||||
|
lineComment bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Package struct {
|
||||||
|
name string
|
||||||
|
defs map[*ast.Ident]types.Object
|
||||||
|
files []*File
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsePackage analyzes the single package constructed from the patterns and tags.
|
||||||
|
// parsePackage exits if there is an error.
|
||||||
|
func (g *Generator) parsePackage(patterns []string, tags []string) {
|
||||||
|
cfg := &packages.Config{
|
||||||
|
Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax,
|
||||||
|
// TODO: Need to think about constants in test files. Maybe write type_string_test.go
|
||||||
|
// in a separate pass? For later.
|
||||||
|
Tests: false,
|
||||||
|
BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(tags, " "))},
|
||||||
|
}
|
||||||
|
pkgs, err := packages.Load(cfg, patterns...)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(pkgs) != 1 {
|
||||||
|
log.Fatalf("error: %d packages found", len(pkgs))
|
||||||
|
}
|
||||||
|
g.addPackage(pkgs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// addPackage adds a type checked Package and its syntax files to the generator.
|
||||||
|
func (g *Generator) addPackage(pkg *packages.Package) {
|
||||||
|
g.pkg = &Package{
|
||||||
|
name: pkg.Name,
|
||||||
|
defs: pkg.TypesInfo.Defs,
|
||||||
|
files: make([]*File, len(pkg.Syntax)),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, file := range pkg.Syntax {
|
||||||
|
g.pkg.files[i] = &File{
|
||||||
|
file: file,
|
||||||
|
pkg: g.pkg,
|
||||||
|
trimPrefix: g.trimPrefix,
|
||||||
|
lineComment: g.lineComment,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate produces the String method for the named type.
|
||||||
|
func (g *Generator) generate(typeName string) {
|
||||||
|
values := make([]Value, 0, 100)
|
||||||
|
for _, file := range g.pkg.files {
|
||||||
|
// Set the state for this run of the walker.
|
||||||
|
file.typeName = typeName
|
||||||
|
file.values = nil
|
||||||
|
if file.file != nil {
|
||||||
|
ast.Inspect(file.file, file.genDecl)
|
||||||
|
values = append(values, file.values...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(values) == 0 {
|
||||||
|
log.Fatalf("no values defined for type %s", typeName)
|
||||||
|
}
|
||||||
|
// Generate code that will fail if the constants change value.
|
||||||
|
g.Printf("func _() {\n")
|
||||||
|
g.Printf("\t// An \"invalid array index\" compiler error signifies that the constant values have changed.\n")
|
||||||
|
g.Printf("\t// Re-run the stringer command to generate them again.\n")
|
||||||
|
g.Printf("\tvar x [1]struct{}\n")
|
||||||
|
for _, v := range values {
|
||||||
|
g.Printf("\t_ = x[%s - %s]\n", v.originalName, v.str)
|
||||||
|
}
|
||||||
|
g.Printf("}\n")
|
||||||
|
runs := splitIntoRuns(values)
|
||||||
|
// The decision of which pattern to use depends on the number of
|
||||||
|
// runs in the numbers. If there's only one, it's easy. For more than
|
||||||
|
// one, there's a tradeoff between complexity and size of the data
|
||||||
|
// and code vs. the simplicity of a map. A map takes more space,
|
||||||
|
// but so does the code. The decision here (crossover at 10) is
|
||||||
|
// arbitrary, but considers that for large numbers of runs the cost
|
||||||
|
// of the linear scan in the switch might become important, and
|
||||||
|
// rather than use yet another algorithm such as binary search,
|
||||||
|
// we punt and use a map. In any case, the likelihood of a map
|
||||||
|
// being necessary for any realistic example other than bitmasks
|
||||||
|
// is very low. And bitmasks probably deserve their own analysis,
|
||||||
|
// to be done some other day.
|
||||||
|
switch {
|
||||||
|
case len(runs) == 1:
|
||||||
|
g.buildOneRun(runs, typeName)
|
||||||
|
case len(runs) <= 10:
|
||||||
|
g.buildMultipleRuns(runs, typeName)
|
||||||
|
default:
|
||||||
|
g.buildMap(runs, typeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitIntoRuns breaks the values into runs of contiguous sequences.
|
||||||
|
// For example, given 1,2,3,5,6,7 it returns {1,2,3},{5,6,7}.
|
||||||
|
// The input slice is known to be non-empty.
|
||||||
|
func splitIntoRuns(values []Value) [][]Value {
|
||||||
|
// We use stable sort so the lexically first name is chosen for equal elements.
|
||||||
|
sort.Stable(byValue(values))
|
||||||
|
// Remove duplicates. Stable sort has put the one we want to print first,
|
||||||
|
// so use that one. The String method won't care about which named constant
|
||||||
|
// was the argument, so the first name for the given value is the only one to keep.
|
||||||
|
// We need to do this because identical values would cause the switch or map
|
||||||
|
// to fail to compile.
|
||||||
|
j := 1
|
||||||
|
for i := 1; i < len(values); i++ {
|
||||||
|
if values[i].value != values[i-1].value {
|
||||||
|
values[j] = values[i]
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
values = values[:j]
|
||||||
|
runs := make([][]Value, 0, 10)
|
||||||
|
for len(values) > 0 {
|
||||||
|
// One contiguous sequence per outer loop.
|
||||||
|
i := 1
|
||||||
|
for i < len(values) && values[i].value == values[i-1].value+1 {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
runs = append(runs, values[:i])
|
||||||
|
values = values[i:]
|
||||||
|
}
|
||||||
|
return runs
|
||||||
|
}
|
||||||
|
|
||||||
|
// format returns the gofmt-ed contents of the Generator's buffer.
|
||||||
|
func (g *Generator) format() []byte {
|
||||||
|
src, err := format.Source(g.buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
// Should never happen, but can arise when developing this code.
|
||||||
|
// The user can compile the output to see the error.
|
||||||
|
log.Printf("warning: internal error: invalid Go generated: %s", err)
|
||||||
|
log.Printf("warning: compile the package to analyze the error")
|
||||||
|
return g.buf.Bytes()
|
||||||
|
}
|
||||||
|
return src
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value represents a declared constant.
|
||||||
|
type Value struct {
|
||||||
|
originalName string // The name of the constant.
|
||||||
|
name string // The name with trimmed prefix.
|
||||||
|
// The value is stored as a bit pattern alone. The boolean tells us
|
||||||
|
// whether to interpret it as an int64 or a uint64; the only place
|
||||||
|
// this matters is when sorting.
|
||||||
|
// Much of the time the str field is all we need; it is printed
|
||||||
|
// by Value.String.
|
||||||
|
value uint64 // Will be converted to int64 when needed.
|
||||||
|
signed bool // Whether the constant is a signed type.
|
||||||
|
str string // The string representation given by the "go/constant" package.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Value) String() string {
|
||||||
|
return v.str
|
||||||
|
}
|
||||||
|
|
||||||
|
// byValue lets us sort the constants into increasing order.
|
||||||
|
// We take care in the Less method to sort in signed or unsigned order,
|
||||||
|
// as appropriate.
|
||||||
|
type byValue []Value
|
||||||
|
|
||||||
|
func (b byValue) Len() int { return len(b) }
|
||||||
|
func (b byValue) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||||
|
func (b byValue) Less(i, j int) bool {
|
||||||
|
if b[i].signed {
|
||||||
|
return int64(b[i].value) < int64(b[j].value)
|
||||||
|
}
|
||||||
|
return b[i].value < b[j].value
|
||||||
|
}
|
||||||
|
|
||||||
|
// genDecl processes one declaration clause.
|
||||||
|
func (f *File) genDecl(node ast.Node) bool {
|
||||||
|
decl, ok := node.(*ast.GenDecl)
|
||||||
|
if !ok || decl.Tok != token.CONST {
|
||||||
|
// We only care about const declarations.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// The name of the type of the constants we are declaring.
|
||||||
|
// Can change if this is a multi-element declaration.
|
||||||
|
typ := ""
|
||||||
|
// Loop over the elements of the declaration. Each element is a ValueSpec:
|
||||||
|
// a list of names possibly followed by a type, possibly followed by values.
|
||||||
|
// If the type and value are both missing, we carry down the type (and value,
|
||||||
|
// but the "go/types" package takes care of that).
|
||||||
|
for _, spec := range decl.Specs {
|
||||||
|
vspec := spec.(*ast.ValueSpec) // Guaranteed to succeed as this is CONST.
|
||||||
|
if vspec.Type == nil && len(vspec.Values) > 0 {
|
||||||
|
// "X = 1". With no type but a value. If the constant is untyped,
|
||||||
|
// skip this vspec and reset the remembered type.
|
||||||
|
typ = ""
|
||||||
|
|
||||||
|
// If this is a simple type conversion, remember the type.
|
||||||
|
// We don't mind if this is actually a call; a qualified call won't
|
||||||
|
// be matched (that will be SelectorExpr, not Ident), and only unusual
|
||||||
|
// situations will result in a function call that appears to be
|
||||||
|
// a type conversion.
|
||||||
|
ce, ok := vspec.Values[0].(*ast.CallExpr)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
id, ok := ce.Fun.(*ast.Ident)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
typ = id.Name
|
||||||
|
}
|
||||||
|
if vspec.Type != nil {
|
||||||
|
// "X T". We have a type. Remember it.
|
||||||
|
ident, ok := vspec.Type.(*ast.Ident)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
typ = ident.Name
|
||||||
|
}
|
||||||
|
if typ != f.typeName {
|
||||||
|
// This is not the type we're looking for.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// We now have a list of names (from one line of source code) all being
|
||||||
|
// declared with the desired type.
|
||||||
|
// Grab their names and actual values and store them in f.values.
|
||||||
|
for _, name := range vspec.Names {
|
||||||
|
if name.Name == "_" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// This dance lets the type checker find the values for us. It's a
|
||||||
|
// bit tricky: look up the object declared by the name, find its
|
||||||
|
// types.Const, and extract its value.
|
||||||
|
obj, ok := f.pkg.defs[name]
|
||||||
|
if !ok {
|
||||||
|
log.Fatalf("no value for constant %s", name)
|
||||||
|
}
|
||||||
|
info := obj.Type().Underlying().(*types.Basic).Info()
|
||||||
|
if info&types.IsInteger == 0 {
|
||||||
|
log.Fatalf("can't handle non-integer constant type %s", typ)
|
||||||
|
}
|
||||||
|
value := obj.(*types.Const).Val() // Guaranteed to succeed as this is CONST.
|
||||||
|
if value.Kind() != constant.Int {
|
||||||
|
log.Fatalf("can't happen: constant is not an integer %s", name)
|
||||||
|
}
|
||||||
|
i64, isInt := constant.Int64Val(value)
|
||||||
|
u64, isUint := constant.Uint64Val(value)
|
||||||
|
if !isInt && !isUint {
|
||||||
|
log.Fatalf("internal error: value of %s is not an integer: %s", name, value.String())
|
||||||
|
}
|
||||||
|
if !isInt {
|
||||||
|
u64 = uint64(i64)
|
||||||
|
}
|
||||||
|
v := Value{
|
||||||
|
originalName: name.Name,
|
||||||
|
value: u64,
|
||||||
|
signed: info&types.IsUnsigned == 0,
|
||||||
|
str: value.String(),
|
||||||
|
}
|
||||||
|
if c := vspec.Comment; f.lineComment && c != nil && len(c.List) == 1 {
|
||||||
|
v.name = strings.TrimSpace(c.Text())
|
||||||
|
} else {
|
||||||
|
v.name = strings.TrimPrefix(v.originalName, f.trimPrefix)
|
||||||
|
}
|
||||||
|
f.values = append(f.values, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
// usize returns the number of bits of the smallest unsigned integer
|
||||||
|
// type that will hold n. Used to create the smallest possible slice of
|
||||||
|
// integers to use as indexes into the concatenated strings.
|
||||||
|
func usize(n int) int {
|
||||||
|
switch {
|
||||||
|
case n < 1<<8:
|
||||||
|
return 8
|
||||||
|
case n < 1<<16:
|
||||||
|
return 16
|
||||||
|
default:
|
||||||
|
// 2^32 is enough constants for anyone.
|
||||||
|
return 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// declareIndexAndNameVars declares the index slices and concatenated names
|
||||||
|
// strings representing the runs of values.
|
||||||
|
func (g *Generator) declareIndexAndNameVars(runs [][]Value, typeName string) {
|
||||||
|
var indexes, names []string
|
||||||
|
for i, run := range runs {
|
||||||
|
index, name := g.createIndexAndNameDecl(run, typeName, fmt.Sprintf("_%d", i))
|
||||||
|
if len(run) != 1 {
|
||||||
|
indexes = append(indexes, index)
|
||||||
|
}
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
g.Printf("const (\n")
|
||||||
|
for _, name := range names {
|
||||||
|
g.Printf("\t%s\n", name)
|
||||||
|
}
|
||||||
|
g.Printf(")\n\n")
|
||||||
|
|
||||||
|
if len(indexes) > 0 {
|
||||||
|
g.Printf("var (")
|
||||||
|
for _, index := range indexes {
|
||||||
|
g.Printf("\t%s\n", index)
|
||||||
|
}
|
||||||
|
g.Printf(")\n\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// declareIndexAndNameVar is the single-run version of declareIndexAndNameVars
|
||||||
|
func (g *Generator) declareIndexAndNameVar(run []Value, typeName string) {
|
||||||
|
index, name := g.createIndexAndNameDecl(run, typeName, "")
|
||||||
|
g.Printf("const %s\n", name)
|
||||||
|
g.Printf("var %s\n", index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// createIndexAndNameDecl returns the pair of declarations for the run. The caller will add "const" and "var".
|
||||||
|
func (g *Generator) createIndexAndNameDecl(run []Value, typeName string, suffix string) (string, string) {
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
indexes := make([]int, len(run))
|
||||||
|
for i := range run {
|
||||||
|
b.WriteString(run[i].name)
|
||||||
|
indexes[i] = b.Len()
|
||||||
|
}
|
||||||
|
nameConst := fmt.Sprintf("_%s_name%s = %q", typeName, suffix, b.String())
|
||||||
|
nameLen := b.Len()
|
||||||
|
b.Reset()
|
||||||
|
fmt.Fprintf(b, "_%s_index%s = [...]uint%d{0, ", typeName, suffix, usize(nameLen))
|
||||||
|
for i, v := range indexes {
|
||||||
|
if i > 0 {
|
||||||
|
fmt.Fprintf(b, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(b, "%d", v)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(b, "}")
|
||||||
|
return b.String(), nameConst
|
||||||
|
}
|
||||||
|
|
||||||
|
// declareNameVars declares the concatenated names string representing all the values in the runs.
|
||||||
|
func (g *Generator) declareNameVars(runs [][]Value, typeName string, suffix string) {
|
||||||
|
g.Printf("const _%s_name%s = \"", typeName, suffix)
|
||||||
|
for _, run := range runs {
|
||||||
|
for i := range run {
|
||||||
|
g.Printf("%s", run[i].name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.Printf("\"\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildOneRun generates the variables and String method for a single run of contiguous values.
|
||||||
|
func (g *Generator) buildOneRun(runs [][]Value, typeName string) {
|
||||||
|
values := runs[0]
|
||||||
|
g.Printf("\n")
|
||||||
|
g.declareIndexAndNameVar(values, typeName)
|
||||||
|
// The generated code is simple enough to write as a Printf format.
|
||||||
|
lessThanZero := ""
|
||||||
|
if values[0].signed {
|
||||||
|
lessThanZero = "i < 0 || "
|
||||||
|
}
|
||||||
|
if values[0].value == 0 { // Signed or unsigned, 0 is still 0.
|
||||||
|
g.Printf(stringOneRun, typeName, usize(len(values)), lessThanZero)
|
||||||
|
} else {
|
||||||
|
g.Printf(stringOneRunWithOffset, typeName, values[0].String(), usize(len(values)), lessThanZero)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arguments to format are:
|
||||||
|
//
|
||||||
|
// [1]: type name
|
||||||
|
// [2]: size of index element (8 for uint8 etc.)
|
||||||
|
// [3]: less than zero check (for signed types)
|
||||||
|
const stringOneRun = `func (i %[1]s) String() string {
|
||||||
|
if %[3]si >= %[1]s(len(_%[1]s_index)-1) {
|
||||||
|
return "%[1]s(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _%[1]s_name[_%[1]s_index[i]:_%[1]s_index[i+1]]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// Arguments to format are:
|
||||||
|
// [1]: type name
|
||||||
|
// [2]: lowest defined value for type, as a string
|
||||||
|
// [3]: size of index element (8 for uint8 etc.)
|
||||||
|
// [4]: less than zero check (for signed types)
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
const stringOneRunWithOffset = `func (i %[1]s) String() string {
|
||||||
|
i -= %[2]s
|
||||||
|
if %[4]si >= %[1]s(len(_%[1]s_index)-1) {
|
||||||
|
return "%[1]s(" + strconv.FormatInt(int64(i + %[2]s), 10) + ")"
|
||||||
|
}
|
||||||
|
return _%[1]s_name[_%[1]s_index[i] : _%[1]s_index[i+1]]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// buildMultipleRuns generates the variables and String method for multiple runs of contiguous values.
|
||||||
|
// For this pattern, a single Printf format won't do.
|
||||||
|
func (g *Generator) buildMultipleRuns(runs [][]Value, typeName string) {
|
||||||
|
g.Printf("\n")
|
||||||
|
g.declareIndexAndNameVars(runs, typeName)
|
||||||
|
g.Printf("func (i %s) String() string {\n", typeName)
|
||||||
|
g.Printf("\tswitch {\n")
|
||||||
|
for i, values := range runs {
|
||||||
|
if len(values) == 1 {
|
||||||
|
g.Printf("\tcase i == %s:\n", &values[0])
|
||||||
|
g.Printf("\t\treturn _%s_name_%d\n", typeName, i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if values[0].value == 0 && !values[0].signed {
|
||||||
|
// For an unsigned lower bound of 0, "0 <= i" would be redundant.
|
||||||
|
g.Printf("\tcase i <= %s:\n", &values[len(values)-1])
|
||||||
|
} else {
|
||||||
|
g.Printf("\tcase %s <= i && i <= %s:\n", &values[0], &values[len(values)-1])
|
||||||
|
}
|
||||||
|
if values[0].value != 0 {
|
||||||
|
g.Printf("\t\ti -= %s\n", &values[0])
|
||||||
|
}
|
||||||
|
g.Printf("\t\treturn _%s_name_%d[_%s_index_%d[i]:_%s_index_%d[i+1]]\n",
|
||||||
|
typeName, i, typeName, i, typeName, i)
|
||||||
|
}
|
||||||
|
g.Printf("\tdefault:\n")
|
||||||
|
g.Printf("\t\treturn \"%s(\" + strconv.FormatInt(int64(i), 10) + \")\"\n", typeName)
|
||||||
|
g.Printf("\t}\n")
|
||||||
|
g.Printf("}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildMap handles the case where the space is so sparse a map is a reasonable fallback.
|
||||||
|
// It's a rare situation but has simple code.
|
||||||
|
func (g *Generator) buildMap(runs [][]Value, typeName string) {
|
||||||
|
g.Printf("\n")
|
||||||
|
g.declareNameVars(runs, typeName, "")
|
||||||
|
g.Printf("\nvar _%s_map = map[%s]string{\n", typeName, typeName)
|
||||||
|
n := 0
|
||||||
|
for _, values := range runs {
|
||||||
|
for _, value := range values {
|
||||||
|
g.Printf("\t%s: _%s_name[%d:%d],\n", &value, typeName, n, n+len(value.name))
|
||||||
|
n += len(value.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.Printf("}\n\n")
|
||||||
|
g.Printf(stringMap, typeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Argument to format is the type name.
|
||||||
|
const stringMap = `func (i %[1]s) String() string {
|
||||||
|
if str, ok := _%[1]s_map[i]; ok {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return "%[1]s(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
`
|
177
vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go
generated
vendored
Normal file
177
vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
// Copyright 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 gcexportdata provides functions for locating, reading, and
|
||||||
|
// writing export data files containing type information produced by the
|
||||||
|
// gc compiler. This package supports go1.7 export data format and all
|
||||||
|
// later versions.
|
||||||
|
//
|
||||||
|
// Although it might seem convenient for this package to live alongside
|
||||||
|
// go/types in the standard library, this would cause version skew
|
||||||
|
// problems for developer tools that use it, since they must be able to
|
||||||
|
// consume the outputs of the gc compiler both before and after a Go
|
||||||
|
// update such as from Go 1.7 to Go 1.8. Because this package lives in
|
||||||
|
// golang.org/x/tools, sites can update their version of this repo some
|
||||||
|
// time before the Go 1.8 release and rebuild and redeploy their
|
||||||
|
// developer tools, which will then be able to consume both Go 1.7 and
|
||||||
|
// Go 1.8 export data files, so they will work before and after the
|
||||||
|
// Go update. (See discussion at https://golang.org/issue/15651.)
|
||||||
|
package gcexportdata // import "golang.org/x/tools/go/gcexportdata"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/internal/gcimporter"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Find returns the name of an object (.o) or archive (.a) file
|
||||||
|
// containing type information for the specified import path,
|
||||||
|
// using the go command.
|
||||||
|
// If no file was found, an empty filename is returned.
|
||||||
|
//
|
||||||
|
// A relative srcDir is interpreted relative to the current working directory.
|
||||||
|
//
|
||||||
|
// Find also returns the package's resolved (canonical) import path,
|
||||||
|
// reflecting the effects of srcDir and vendoring on importPath.
|
||||||
|
//
|
||||||
|
// Deprecated: Use the higher-level API in golang.org/x/tools/go/packages,
|
||||||
|
// which is more efficient.
|
||||||
|
func Find(importPath, srcDir string) (filename, path string) {
|
||||||
|
cmd := exec.Command("go", "list", "-json", "-export", "--", importPath)
|
||||||
|
cmd.Dir = srcDir
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
var data struct {
|
||||||
|
ImportPath string
|
||||||
|
Export string
|
||||||
|
}
|
||||||
|
json.Unmarshal(out, &data)
|
||||||
|
return data.Export, data.ImportPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewReader returns a reader for the export data section of an object
|
||||||
|
// (.o) or archive (.a) file read from r. The new reader may provide
|
||||||
|
// additional trailing data beyond the end of the export data.
|
||||||
|
func NewReader(r io.Reader) (io.Reader, error) {
|
||||||
|
buf := bufio.NewReader(r)
|
||||||
|
_, size, err := gcimporter.FindExportData(buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if size >= 0 {
|
||||||
|
// We were given an archive and found the __.PKGDEF in it.
|
||||||
|
// This tells us the size of the export data, and we don't
|
||||||
|
// need to return the entire file.
|
||||||
|
return &io.LimitedReader{
|
||||||
|
R: buf,
|
||||||
|
N: size,
|
||||||
|
}, nil
|
||||||
|
} else {
|
||||||
|
// We were given an object file. As such, we don't know how large
|
||||||
|
// the export data is and must return the entire file.
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads export data from in, decodes it, and returns type
|
||||||
|
// information for the package.
|
||||||
|
// The package name is specified by path.
|
||||||
|
// File position information is added to fset.
|
||||||
|
//
|
||||||
|
// Read may inspect and add to the imports map to ensure that references
|
||||||
|
// within the export data to other packages are consistent. The caller
|
||||||
|
// must ensure that imports[path] does not exist, or exists but is
|
||||||
|
// incomplete (see types.Package.Complete), and Read inserts the
|
||||||
|
// resulting package into this map entry.
|
||||||
|
//
|
||||||
|
// On return, the state of the reader is undefined.
|
||||||
|
func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) {
|
||||||
|
data, err := ioutil.ReadAll(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("reading export data for %q: %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.HasPrefix(data, []byte("!<arch>")) {
|
||||||
|
return nil, fmt.Errorf("can't read export data for %q directly from an archive file (call gcexportdata.NewReader first to extract export data)", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The App Engine Go runtime v1.6 uses the old export data format.
|
||||||
|
// TODO(adonovan): delete once v1.7 has been around for a while.
|
||||||
|
if bytes.HasPrefix(data, []byte("package ")) {
|
||||||
|
return gcimporter.ImportData(imports, path, path, bytes.NewReader(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The indexed export format starts with an 'i'; the older
|
||||||
|
// binary export format starts with a 'c', 'd', or 'v'
|
||||||
|
// (from "version"). Select appropriate importer.
|
||||||
|
if len(data) > 0 {
|
||||||
|
switch data[0] {
|
||||||
|
case 'i':
|
||||||
|
_, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path)
|
||||||
|
return pkg, err
|
||||||
|
|
||||||
|
case 'v', 'c', 'd':
|
||||||
|
_, pkg, err := gcimporter.BImportData(fset, imports, data, path)
|
||||||
|
return pkg, err
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
_, pkg, err := gcimporter.UImportData(fset, imports, data[1:], path)
|
||||||
|
return pkg, err
|
||||||
|
|
||||||
|
default:
|
||||||
|
l := len(data)
|
||||||
|
if l > 10 {
|
||||||
|
l = 10
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unexpected export data with prefix %q for path %s", string(data[:l]), path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("empty export data for %s", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes encoded type information for the specified package to out.
|
||||||
|
// The FileSet provides file position information for named objects.
|
||||||
|
func Write(out io.Writer, fset *token.FileSet, pkg *types.Package) error {
|
||||||
|
if _, err := io.WriteString(out, "i"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return gcimporter.IExportData(out, fset, pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadBundle reads an export bundle from in, decodes it, and returns type
|
||||||
|
// information for the packages.
|
||||||
|
// File position information is added to fset.
|
||||||
|
//
|
||||||
|
// ReadBundle may inspect and add to the imports map to ensure that references
|
||||||
|
// within the export bundle to other packages are consistent.
|
||||||
|
//
|
||||||
|
// On return, the state of the reader is undefined.
|
||||||
|
//
|
||||||
|
// Experimental: This API is experimental and may change in the future.
|
||||||
|
func ReadBundle(in io.Reader, fset *token.FileSet, imports map[string]*types.Package) ([]*types.Package, error) {
|
||||||
|
data, err := ioutil.ReadAll(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("reading export bundle: %v", err)
|
||||||
|
}
|
||||||
|
return gcimporter.IImportBundle(fset, imports, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBundle writes encoded type information for the specified packages to out.
|
||||||
|
// The FileSet provides file position information for named objects.
|
||||||
|
//
|
||||||
|
// Experimental: This API is experimental and may change in the future.
|
||||||
|
func WriteBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error {
|
||||||
|
return gcimporter.IExportBundle(out, fset, pkgs)
|
||||||
|
}
|
75
vendor/golang.org/x/tools/go/gcexportdata/importer.go
generated
vendored
Normal file
75
vendor/golang.org/x/tools/go/gcexportdata/importer.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright 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 gcexportdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewImporter returns a new instance of the types.Importer interface
|
||||||
|
// that reads type information from export data files written by gc.
|
||||||
|
// The Importer also satisfies types.ImporterFrom.
|
||||||
|
//
|
||||||
|
// Export data files are located using "go build" workspace conventions
|
||||||
|
// and the build.Default context.
|
||||||
|
//
|
||||||
|
// Use this importer instead of go/importer.For("gc", ...) to avoid the
|
||||||
|
// version-skew problems described in the documentation of this package,
|
||||||
|
// or to control the FileSet or access the imports map populated during
|
||||||
|
// package loading.
|
||||||
|
//
|
||||||
|
// Deprecated: Use the higher-level API in golang.org/x/tools/go/packages,
|
||||||
|
// which is more efficient.
|
||||||
|
func NewImporter(fset *token.FileSet, imports map[string]*types.Package) types.ImporterFrom {
|
||||||
|
return importer{fset, imports}
|
||||||
|
}
|
||||||
|
|
||||||
|
type importer struct {
|
||||||
|
fset *token.FileSet
|
||||||
|
imports map[string]*types.Package
|
||||||
|
}
|
||||||
|
|
||||||
|
func (imp importer) Import(importPath string) (*types.Package, error) {
|
||||||
|
return imp.ImportFrom(importPath, "", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (imp importer) ImportFrom(importPath, srcDir string, mode types.ImportMode) (_ *types.Package, err error) {
|
||||||
|
filename, path := Find(importPath, srcDir)
|
||||||
|
if filename == "" {
|
||||||
|
if importPath == "unsafe" {
|
||||||
|
// Even for unsafe, call Find first in case
|
||||||
|
// the package was vendored.
|
||||||
|
return types.Unsafe, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("can't find import: %s", importPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkg, ok := imp.imports[path]; ok && pkg.Complete() {
|
||||||
|
return pkg, nil // cache hit
|
||||||
|
}
|
||||||
|
|
||||||
|
// open file
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
f.Close()
|
||||||
|
if err != nil {
|
||||||
|
// add file name to error
|
||||||
|
err = fmt.Errorf("reading export data: %s: %v", filename, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
r, err := NewReader(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Read(r, imp.fset, imp.imports, path)
|
||||||
|
}
|
853
vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go
generated
vendored
Normal file
853
vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go
generated
vendored
Normal file
@ -0,0 +1,853 @@
|
|||||||
|
// Copyright 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.
|
||||||
|
|
||||||
|
// Binary package export.
|
||||||
|
// This file was derived from $GOROOT/src/cmd/compile/internal/gc/bexport.go;
|
||||||
|
// see that file for specification of the format.
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/constant"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"math"
|
||||||
|
"math/big"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// If debugFormat is set, each integer and string value is preceded by a marker
|
||||||
|
// and position information in the encoding. This mechanism permits an importer
|
||||||
|
// to recognize immediately when it is out of sync. The importer recognizes this
|
||||||
|
// mode automatically (i.e., it can import export data produced with debugging
|
||||||
|
// support even if debugFormat is not set at the time of import). This mode will
|
||||||
|
// lead to massively larger export data (by a factor of 2 to 3) and should only
|
||||||
|
// be enabled during development and debugging.
|
||||||
|
//
|
||||||
|
// NOTE: This flag is the first flag to enable if importing dies because of
|
||||||
|
// (suspected) format errors, and whenever a change is made to the format.
|
||||||
|
const debugFormat = false // default: false
|
||||||
|
|
||||||
|
// Current export format version. Increase with each format change.
|
||||||
|
//
|
||||||
|
// Note: The latest binary (non-indexed) export format is at version 6.
|
||||||
|
// This exporter is still at level 4, but it doesn't matter since
|
||||||
|
// the binary importer can handle older versions just fine.
|
||||||
|
//
|
||||||
|
// 6: package height (CL 105038) -- NOT IMPLEMENTED HERE
|
||||||
|
// 5: improved position encoding efficiency (issue 20080, CL 41619) -- NOT IMPLEMENTED HERE
|
||||||
|
// 4: type name objects support type aliases, uses aliasTag
|
||||||
|
// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
|
||||||
|
// 2: removed unused bool in ODCL export (compiler only)
|
||||||
|
// 1: header format change (more regular), export package for _ struct fields
|
||||||
|
// 0: Go1.7 encoding
|
||||||
|
const exportVersion = 4
|
||||||
|
|
||||||
|
// trackAllTypes enables cycle tracking for all types, not just named
|
||||||
|
// types. The existing compiler invariants assume that unnamed types
|
||||||
|
// that are not completely set up are not used, or else there are spurious
|
||||||
|
// errors.
|
||||||
|
// If disabled, only named types are tracked, possibly leading to slightly
|
||||||
|
// less efficient encoding in rare cases. It also prevents the export of
|
||||||
|
// some corner-case type declarations (but those are not handled correctly
|
||||||
|
// with with the textual export format either).
|
||||||
|
// TODO(gri) enable and remove once issues caused by it are fixed
|
||||||
|
const trackAllTypes = false
|
||||||
|
|
||||||
|
type exporter struct {
|
||||||
|
fset *token.FileSet
|
||||||
|
out bytes.Buffer
|
||||||
|
|
||||||
|
// object -> index maps, indexed in order of serialization
|
||||||
|
strIndex map[string]int
|
||||||
|
pkgIndex map[*types.Package]int
|
||||||
|
typIndex map[types.Type]int
|
||||||
|
|
||||||
|
// position encoding
|
||||||
|
posInfoFormat bool
|
||||||
|
prevFile string
|
||||||
|
prevLine int
|
||||||
|
|
||||||
|
// debugging support
|
||||||
|
written int // bytes written
|
||||||
|
indent int // for trace
|
||||||
|
}
|
||||||
|
|
||||||
|
// internalError represents an error generated inside this package.
|
||||||
|
type internalError string
|
||||||
|
|
||||||
|
func (e internalError) Error() string { return "gcimporter: " + string(e) }
|
||||||
|
|
||||||
|
func internalErrorf(format string, args ...interface{}) error {
|
||||||
|
return internalError(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BExportData returns binary export data for pkg.
|
||||||
|
// If no file set is provided, position info will be missing.
|
||||||
|
func BExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) {
|
||||||
|
if !debug {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
if ierr, ok := e.(internalError); ok {
|
||||||
|
err = ierr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Not an internal error; panic again.
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
p := exporter{
|
||||||
|
fset: fset,
|
||||||
|
strIndex: map[string]int{"": 0}, // empty string is mapped to 0
|
||||||
|
pkgIndex: make(map[*types.Package]int),
|
||||||
|
typIndex: make(map[types.Type]int),
|
||||||
|
posInfoFormat: true, // TODO(gri) might become a flag, eventually
|
||||||
|
}
|
||||||
|
|
||||||
|
// write version info
|
||||||
|
// The version string must start with "version %d" where %d is the version
|
||||||
|
// number. Additional debugging information may follow after a blank; that
|
||||||
|
// text is ignored by the importer.
|
||||||
|
p.rawStringln(fmt.Sprintf("version %d", exportVersion))
|
||||||
|
var debug string
|
||||||
|
if debugFormat {
|
||||||
|
debug = "debug"
|
||||||
|
}
|
||||||
|
p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly
|
||||||
|
p.bool(trackAllTypes)
|
||||||
|
p.bool(p.posInfoFormat)
|
||||||
|
|
||||||
|
// --- generic export data ---
|
||||||
|
|
||||||
|
// populate type map with predeclared "known" types
|
||||||
|
for index, typ := range predeclared() {
|
||||||
|
p.typIndex[typ] = index
|
||||||
|
}
|
||||||
|
if len(p.typIndex) != len(predeclared()) {
|
||||||
|
return nil, internalError("duplicate entries in type map?")
|
||||||
|
}
|
||||||
|
|
||||||
|
// write package data
|
||||||
|
p.pkg(pkg, true)
|
||||||
|
if trace {
|
||||||
|
p.tracef("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// write objects
|
||||||
|
objcount := 0
|
||||||
|
scope := pkg.Scope()
|
||||||
|
for _, name := range scope.Names() {
|
||||||
|
if !ast.IsExported(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if trace {
|
||||||
|
p.tracef("\n")
|
||||||
|
}
|
||||||
|
p.obj(scope.Lookup(name))
|
||||||
|
objcount++
|
||||||
|
}
|
||||||
|
|
||||||
|
// indicate end of list
|
||||||
|
if trace {
|
||||||
|
p.tracef("\n")
|
||||||
|
}
|
||||||
|
p.tag(endTag)
|
||||||
|
|
||||||
|
// for self-verification only (redundant)
|
||||||
|
p.int(objcount)
|
||||||
|
|
||||||
|
if trace {
|
||||||
|
p.tracef("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- end of export data ---
|
||||||
|
|
||||||
|
return p.out.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) pkg(pkg *types.Package, emptypath bool) {
|
||||||
|
if pkg == nil {
|
||||||
|
panic(internalError("unexpected nil pkg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we saw the package before, write its index (>= 0)
|
||||||
|
if i, ok := p.pkgIndex[pkg]; ok {
|
||||||
|
p.index('P', i)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, remember the package, write the package tag (< 0) and package data
|
||||||
|
if trace {
|
||||||
|
p.tracef("P%d = { ", len(p.pkgIndex))
|
||||||
|
defer p.tracef("} ")
|
||||||
|
}
|
||||||
|
p.pkgIndex[pkg] = len(p.pkgIndex)
|
||||||
|
|
||||||
|
p.tag(packageTag)
|
||||||
|
p.string(pkg.Name())
|
||||||
|
if emptypath {
|
||||||
|
p.string("")
|
||||||
|
} else {
|
||||||
|
p.string(pkg.Path())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) obj(obj types.Object) {
|
||||||
|
switch obj := obj.(type) {
|
||||||
|
case *types.Const:
|
||||||
|
p.tag(constTag)
|
||||||
|
p.pos(obj)
|
||||||
|
p.qualifiedName(obj)
|
||||||
|
p.typ(obj.Type())
|
||||||
|
p.value(obj.Val())
|
||||||
|
|
||||||
|
case *types.TypeName:
|
||||||
|
if obj.IsAlias() {
|
||||||
|
p.tag(aliasTag)
|
||||||
|
p.pos(obj)
|
||||||
|
p.qualifiedName(obj)
|
||||||
|
} else {
|
||||||
|
p.tag(typeTag)
|
||||||
|
}
|
||||||
|
p.typ(obj.Type())
|
||||||
|
|
||||||
|
case *types.Var:
|
||||||
|
p.tag(varTag)
|
||||||
|
p.pos(obj)
|
||||||
|
p.qualifiedName(obj)
|
||||||
|
p.typ(obj.Type())
|
||||||
|
|
||||||
|
case *types.Func:
|
||||||
|
p.tag(funcTag)
|
||||||
|
p.pos(obj)
|
||||||
|
p.qualifiedName(obj)
|
||||||
|
sig := obj.Type().(*types.Signature)
|
||||||
|
p.paramList(sig.Params(), sig.Variadic())
|
||||||
|
p.paramList(sig.Results(), false)
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(internalErrorf("unexpected object %v (%T)", obj, obj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) pos(obj types.Object) {
|
||||||
|
if !p.posInfoFormat {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
file, line := p.fileLine(obj)
|
||||||
|
if file == p.prevFile {
|
||||||
|
// common case: write line delta
|
||||||
|
// delta == 0 means different file or no line change
|
||||||
|
delta := line - p.prevLine
|
||||||
|
p.int(delta)
|
||||||
|
if delta == 0 {
|
||||||
|
p.int(-1) // -1 means no file change
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// different file
|
||||||
|
p.int(0)
|
||||||
|
// Encode filename as length of common prefix with previous
|
||||||
|
// filename, followed by (possibly empty) suffix. Filenames
|
||||||
|
// frequently share path prefixes, so this can save a lot
|
||||||
|
// of space and make export data size less dependent on file
|
||||||
|
// path length. The suffix is unlikely to be empty because
|
||||||
|
// file names tend to end in ".go".
|
||||||
|
n := commonPrefixLen(p.prevFile, file)
|
||||||
|
p.int(n) // n >= 0
|
||||||
|
p.string(file[n:]) // write suffix only
|
||||||
|
p.prevFile = file
|
||||||
|
p.int(line)
|
||||||
|
}
|
||||||
|
p.prevLine = line
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) fileLine(obj types.Object) (file string, line int) {
|
||||||
|
if p.fset != nil {
|
||||||
|
pos := p.fset.Position(obj.Pos())
|
||||||
|
file = pos.Filename
|
||||||
|
line = pos.Line
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func commonPrefixLen(a, b string) int {
|
||||||
|
if len(a) > len(b) {
|
||||||
|
a, b = b, a
|
||||||
|
}
|
||||||
|
// len(a) <= len(b)
|
||||||
|
i := 0
|
||||||
|
for i < len(a) && a[i] == b[i] {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) qualifiedName(obj types.Object) {
|
||||||
|
p.string(obj.Name())
|
||||||
|
p.pkg(obj.Pkg(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) typ(t types.Type) {
|
||||||
|
if t == nil {
|
||||||
|
panic(internalError("nil type"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possible optimization: Anonymous pointer types *T where
|
||||||
|
// T is a named type are common. We could canonicalize all
|
||||||
|
// such types *T to a single type PT = *T. This would lead
|
||||||
|
// to at most one *T entry in typIndex, and all future *T's
|
||||||
|
// would be encoded as the respective index directly. Would
|
||||||
|
// save 1 byte (pointerTag) per *T and reduce the typIndex
|
||||||
|
// size (at the cost of a canonicalization map). We can do
|
||||||
|
// this later, without encoding format change.
|
||||||
|
|
||||||
|
// if we saw the type before, write its index (>= 0)
|
||||||
|
if i, ok := p.typIndex[t]; ok {
|
||||||
|
p.index('T', i)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, remember the type, write the type tag (< 0) and type data
|
||||||
|
if trackAllTypes {
|
||||||
|
if trace {
|
||||||
|
p.tracef("T%d = {>\n", len(p.typIndex))
|
||||||
|
defer p.tracef("<\n} ")
|
||||||
|
}
|
||||||
|
p.typIndex[t] = len(p.typIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t := t.(type) {
|
||||||
|
case *types.Named:
|
||||||
|
if !trackAllTypes {
|
||||||
|
// if we don't track all types, track named types now
|
||||||
|
p.typIndex[t] = len(p.typIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.tag(namedTag)
|
||||||
|
p.pos(t.Obj())
|
||||||
|
p.qualifiedName(t.Obj())
|
||||||
|
p.typ(t.Underlying())
|
||||||
|
if !types.IsInterface(t) {
|
||||||
|
p.assocMethods(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *types.Array:
|
||||||
|
p.tag(arrayTag)
|
||||||
|
p.int64(t.Len())
|
||||||
|
p.typ(t.Elem())
|
||||||
|
|
||||||
|
case *types.Slice:
|
||||||
|
p.tag(sliceTag)
|
||||||
|
p.typ(t.Elem())
|
||||||
|
|
||||||
|
case *dddSlice:
|
||||||
|
p.tag(dddTag)
|
||||||
|
p.typ(t.elem)
|
||||||
|
|
||||||
|
case *types.Struct:
|
||||||
|
p.tag(structTag)
|
||||||
|
p.fieldList(t)
|
||||||
|
|
||||||
|
case *types.Pointer:
|
||||||
|
p.tag(pointerTag)
|
||||||
|
p.typ(t.Elem())
|
||||||
|
|
||||||
|
case *types.Signature:
|
||||||
|
p.tag(signatureTag)
|
||||||
|
p.paramList(t.Params(), t.Variadic())
|
||||||
|
p.paramList(t.Results(), false)
|
||||||
|
|
||||||
|
case *types.Interface:
|
||||||
|
p.tag(interfaceTag)
|
||||||
|
p.iface(t)
|
||||||
|
|
||||||
|
case *types.Map:
|
||||||
|
p.tag(mapTag)
|
||||||
|
p.typ(t.Key())
|
||||||
|
p.typ(t.Elem())
|
||||||
|
|
||||||
|
case *types.Chan:
|
||||||
|
p.tag(chanTag)
|
||||||
|
p.int(int(3 - t.Dir())) // hack
|
||||||
|
p.typ(t.Elem())
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(internalErrorf("unexpected type %T: %s", t, t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) assocMethods(named *types.Named) {
|
||||||
|
// Sort methods (for determinism).
|
||||||
|
var methods []*types.Func
|
||||||
|
for i := 0; i < named.NumMethods(); i++ {
|
||||||
|
methods = append(methods, named.Method(i))
|
||||||
|
}
|
||||||
|
sort.Sort(methodsByName(methods))
|
||||||
|
|
||||||
|
p.int(len(methods))
|
||||||
|
|
||||||
|
if trace && methods != nil {
|
||||||
|
p.tracef("associated methods {>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, m := range methods {
|
||||||
|
if trace && i > 0 {
|
||||||
|
p.tracef("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
p.pos(m)
|
||||||
|
name := m.Name()
|
||||||
|
p.string(name)
|
||||||
|
if !exported(name) {
|
||||||
|
p.pkg(m.Pkg(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
sig := m.Type().(*types.Signature)
|
||||||
|
p.paramList(types.NewTuple(sig.Recv()), false)
|
||||||
|
p.paramList(sig.Params(), sig.Variadic())
|
||||||
|
p.paramList(sig.Results(), false)
|
||||||
|
p.int(0) // dummy value for go:nointerface pragma - ignored by importer
|
||||||
|
}
|
||||||
|
|
||||||
|
if trace && methods != nil {
|
||||||
|
p.tracef("<\n} ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type methodsByName []*types.Func
|
||||||
|
|
||||||
|
func (x methodsByName) Len() int { return len(x) }
|
||||||
|
func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||||
|
func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() }
|
||||||
|
|
||||||
|
func (p *exporter) fieldList(t *types.Struct) {
|
||||||
|
if trace && t.NumFields() > 0 {
|
||||||
|
p.tracef("fields {>\n")
|
||||||
|
defer p.tracef("<\n} ")
|
||||||
|
}
|
||||||
|
|
||||||
|
p.int(t.NumFields())
|
||||||
|
for i := 0; i < t.NumFields(); i++ {
|
||||||
|
if trace && i > 0 {
|
||||||
|
p.tracef("\n")
|
||||||
|
}
|
||||||
|
p.field(t.Field(i))
|
||||||
|
p.string(t.Tag(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) field(f *types.Var) {
|
||||||
|
if !f.IsField() {
|
||||||
|
panic(internalError("field expected"))
|
||||||
|
}
|
||||||
|
|
||||||
|
p.pos(f)
|
||||||
|
p.fieldName(f)
|
||||||
|
p.typ(f.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) iface(t *types.Interface) {
|
||||||
|
// TODO(gri): enable importer to load embedded interfaces,
|
||||||
|
// then emit Embeddeds and ExplicitMethods separately here.
|
||||||
|
p.int(0)
|
||||||
|
|
||||||
|
n := t.NumMethods()
|
||||||
|
if trace && n > 0 {
|
||||||
|
p.tracef("methods {>\n")
|
||||||
|
defer p.tracef("<\n} ")
|
||||||
|
}
|
||||||
|
p.int(n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
if trace && i > 0 {
|
||||||
|
p.tracef("\n")
|
||||||
|
}
|
||||||
|
p.method(t.Method(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) method(m *types.Func) {
|
||||||
|
sig := m.Type().(*types.Signature)
|
||||||
|
if sig.Recv() == nil {
|
||||||
|
panic(internalError("method expected"))
|
||||||
|
}
|
||||||
|
|
||||||
|
p.pos(m)
|
||||||
|
p.string(m.Name())
|
||||||
|
if m.Name() != "_" && !ast.IsExported(m.Name()) {
|
||||||
|
p.pkg(m.Pkg(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// interface method; no need to encode receiver.
|
||||||
|
p.paramList(sig.Params(), sig.Variadic())
|
||||||
|
p.paramList(sig.Results(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) fieldName(f *types.Var) {
|
||||||
|
name := f.Name()
|
||||||
|
|
||||||
|
if f.Anonymous() {
|
||||||
|
// anonymous field - we distinguish between 3 cases:
|
||||||
|
// 1) field name matches base type name and is exported
|
||||||
|
// 2) field name matches base type name and is not exported
|
||||||
|
// 3) field name doesn't match base type name (alias name)
|
||||||
|
bname := basetypeName(f.Type())
|
||||||
|
if name == bname {
|
||||||
|
if ast.IsExported(name) {
|
||||||
|
name = "" // 1) we don't need to know the field name or package
|
||||||
|
} else {
|
||||||
|
name = "?" // 2) use unexported name "?" to force package export
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 3) indicate alias and export name as is
|
||||||
|
// (this requires an extra "@" but this is a rare case)
|
||||||
|
p.string("@")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.string(name)
|
||||||
|
if name != "" && !ast.IsExported(name) {
|
||||||
|
p.pkg(f.Pkg(), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func basetypeName(typ types.Type) string {
|
||||||
|
switch typ := deref(typ).(type) {
|
||||||
|
case *types.Basic:
|
||||||
|
return typ.Name()
|
||||||
|
case *types.Named:
|
||||||
|
return typ.Obj().Name()
|
||||||
|
default:
|
||||||
|
return "" // unnamed type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) paramList(params *types.Tuple, variadic bool) {
|
||||||
|
// use negative length to indicate unnamed parameters
|
||||||
|
// (look at the first parameter only since either all
|
||||||
|
// names are present or all are absent)
|
||||||
|
n := params.Len()
|
||||||
|
if n > 0 && params.At(0).Name() == "" {
|
||||||
|
n = -n
|
||||||
|
}
|
||||||
|
p.int(n)
|
||||||
|
for i := 0; i < params.Len(); i++ {
|
||||||
|
q := params.At(i)
|
||||||
|
t := q.Type()
|
||||||
|
if variadic && i == params.Len()-1 {
|
||||||
|
t = &dddSlice{t.(*types.Slice).Elem()}
|
||||||
|
}
|
||||||
|
p.typ(t)
|
||||||
|
if n > 0 {
|
||||||
|
name := q.Name()
|
||||||
|
p.string(name)
|
||||||
|
if name != "_" {
|
||||||
|
p.pkg(q.Pkg(), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.string("") // no compiler-specific info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) value(x constant.Value) {
|
||||||
|
if trace {
|
||||||
|
p.tracef("= ")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch x.Kind() {
|
||||||
|
case constant.Bool:
|
||||||
|
tag := falseTag
|
||||||
|
if constant.BoolVal(x) {
|
||||||
|
tag = trueTag
|
||||||
|
}
|
||||||
|
p.tag(tag)
|
||||||
|
|
||||||
|
case constant.Int:
|
||||||
|
if v, exact := constant.Int64Val(x); exact {
|
||||||
|
// common case: x fits into an int64 - use compact encoding
|
||||||
|
p.tag(int64Tag)
|
||||||
|
p.int64(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// uncommon case: large x - use float encoding
|
||||||
|
// (powers of 2 will be encoded efficiently with exponent)
|
||||||
|
p.tag(floatTag)
|
||||||
|
p.float(constant.ToFloat(x))
|
||||||
|
|
||||||
|
case constant.Float:
|
||||||
|
p.tag(floatTag)
|
||||||
|
p.float(x)
|
||||||
|
|
||||||
|
case constant.Complex:
|
||||||
|
p.tag(complexTag)
|
||||||
|
p.float(constant.Real(x))
|
||||||
|
p.float(constant.Imag(x))
|
||||||
|
|
||||||
|
case constant.String:
|
||||||
|
p.tag(stringTag)
|
||||||
|
p.string(constant.StringVal(x))
|
||||||
|
|
||||||
|
case constant.Unknown:
|
||||||
|
// package contains type errors
|
||||||
|
p.tag(unknownTag)
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(internalErrorf("unexpected value %v (%T)", x, x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) float(x constant.Value) {
|
||||||
|
if x.Kind() != constant.Float {
|
||||||
|
panic(internalErrorf("unexpected constant %v, want float", x))
|
||||||
|
}
|
||||||
|
// extract sign (there is no -0)
|
||||||
|
sign := constant.Sign(x)
|
||||||
|
if sign == 0 {
|
||||||
|
// x == 0
|
||||||
|
p.int(0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// x != 0
|
||||||
|
|
||||||
|
var f big.Float
|
||||||
|
if v, exact := constant.Float64Val(x); exact {
|
||||||
|
// float64
|
||||||
|
f.SetFloat64(v)
|
||||||
|
} else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int {
|
||||||
|
// TODO(gri): add big.Rat accessor to constant.Value.
|
||||||
|
r := valueToRat(num)
|
||||||
|
f.SetRat(r.Quo(r, valueToRat(denom)))
|
||||||
|
} else {
|
||||||
|
// Value too large to represent as a fraction => inaccessible.
|
||||||
|
// TODO(gri): add big.Float accessor to constant.Value.
|
||||||
|
f.SetFloat64(math.MaxFloat64) // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract exponent such that 0.5 <= m < 1.0
|
||||||
|
var m big.Float
|
||||||
|
exp := f.MantExp(&m)
|
||||||
|
|
||||||
|
// extract mantissa as *big.Int
|
||||||
|
// - set exponent large enough so mant satisfies mant.IsInt()
|
||||||
|
// - get *big.Int from mant
|
||||||
|
m.SetMantExp(&m, int(m.MinPrec()))
|
||||||
|
mant, acc := m.Int(nil)
|
||||||
|
if acc != big.Exact {
|
||||||
|
panic(internalError("internal error"))
|
||||||
|
}
|
||||||
|
|
||||||
|
p.int(sign)
|
||||||
|
p.int(exp)
|
||||||
|
p.string(string(mant.Bytes()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToRat(x constant.Value) *big.Rat {
|
||||||
|
// Convert little-endian to big-endian.
|
||||||
|
// I can't believe this is necessary.
|
||||||
|
bytes := constant.Bytes(x)
|
||||||
|
for i := 0; i < len(bytes)/2; i++ {
|
||||||
|
bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i]
|
||||||
|
}
|
||||||
|
return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) bool(b bool) bool {
|
||||||
|
if trace {
|
||||||
|
p.tracef("[")
|
||||||
|
defer p.tracef("= %v] ", b)
|
||||||
|
}
|
||||||
|
|
||||||
|
x := 0
|
||||||
|
if b {
|
||||||
|
x = 1
|
||||||
|
}
|
||||||
|
p.int(x)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Low-level encoders
|
||||||
|
|
||||||
|
func (p *exporter) index(marker byte, index int) {
|
||||||
|
if index < 0 {
|
||||||
|
panic(internalError("invalid index < 0"))
|
||||||
|
}
|
||||||
|
if debugFormat {
|
||||||
|
p.marker('t')
|
||||||
|
}
|
||||||
|
if trace {
|
||||||
|
p.tracef("%c%d ", marker, index)
|
||||||
|
}
|
||||||
|
p.rawInt64(int64(index))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) tag(tag int) {
|
||||||
|
if tag >= 0 {
|
||||||
|
panic(internalError("invalid tag >= 0"))
|
||||||
|
}
|
||||||
|
if debugFormat {
|
||||||
|
p.marker('t')
|
||||||
|
}
|
||||||
|
if trace {
|
||||||
|
p.tracef("%s ", tagString[-tag])
|
||||||
|
}
|
||||||
|
p.rawInt64(int64(tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) int(x int) {
|
||||||
|
p.int64(int64(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) int64(x int64) {
|
||||||
|
if debugFormat {
|
||||||
|
p.marker('i')
|
||||||
|
}
|
||||||
|
if trace {
|
||||||
|
p.tracef("%d ", x)
|
||||||
|
}
|
||||||
|
p.rawInt64(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) string(s string) {
|
||||||
|
if debugFormat {
|
||||||
|
p.marker('s')
|
||||||
|
}
|
||||||
|
if trace {
|
||||||
|
p.tracef("%q ", s)
|
||||||
|
}
|
||||||
|
// if we saw the string before, write its index (>= 0)
|
||||||
|
// (the empty string is mapped to 0)
|
||||||
|
if i, ok := p.strIndex[s]; ok {
|
||||||
|
p.rawInt64(int64(i))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// otherwise, remember string and write its negative length and bytes
|
||||||
|
p.strIndex[s] = len(p.strIndex)
|
||||||
|
p.rawInt64(-int64(len(s)))
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
p.rawByte(s[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// marker emits a marker byte and position information which makes
|
||||||
|
// it easy for a reader to detect if it is "out of sync". Used for
|
||||||
|
// debugFormat format only.
|
||||||
|
func (p *exporter) marker(m byte) {
|
||||||
|
p.rawByte(m)
|
||||||
|
// Enable this for help tracking down the location
|
||||||
|
// of an incorrect marker when running in debugFormat.
|
||||||
|
if false && trace {
|
||||||
|
p.tracef("#%d ", p.written)
|
||||||
|
}
|
||||||
|
p.rawInt64(int64(p.written))
|
||||||
|
}
|
||||||
|
|
||||||
|
// rawInt64 should only be used by low-level encoders.
|
||||||
|
func (p *exporter) rawInt64(x int64) {
|
||||||
|
var tmp [binary.MaxVarintLen64]byte
|
||||||
|
n := binary.PutVarint(tmp[:], x)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
p.rawByte(tmp[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rawStringln should only be used to emit the initial version string.
|
||||||
|
func (p *exporter) rawStringln(s string) {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
p.rawByte(s[i])
|
||||||
|
}
|
||||||
|
p.rawByte('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
// rawByte is the bottleneck interface to write to p.out.
|
||||||
|
// rawByte escapes b as follows (any encoding does that
|
||||||
|
// hides '$'):
|
||||||
|
//
|
||||||
|
// '$' => '|' 'S'
|
||||||
|
// '|' => '|' '|'
|
||||||
|
//
|
||||||
|
// Necessary so other tools can find the end of the
|
||||||
|
// export data by searching for "$$".
|
||||||
|
// rawByte should only be used by low-level encoders.
|
||||||
|
func (p *exporter) rawByte(b byte) {
|
||||||
|
switch b {
|
||||||
|
case '$':
|
||||||
|
// write '$' as '|' 'S'
|
||||||
|
b = 'S'
|
||||||
|
fallthrough
|
||||||
|
case '|':
|
||||||
|
// write '|' as '|' '|'
|
||||||
|
p.out.WriteByte('|')
|
||||||
|
p.written++
|
||||||
|
}
|
||||||
|
p.out.WriteByte(b)
|
||||||
|
p.written++
|
||||||
|
}
|
||||||
|
|
||||||
|
// tracef is like fmt.Printf but it rewrites the format string
|
||||||
|
// to take care of indentation.
|
||||||
|
func (p *exporter) tracef(format string, args ...interface{}) {
|
||||||
|
if strings.ContainsAny(format, "<>\n") {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for i := 0; i < len(format); i++ {
|
||||||
|
// no need to deal with runes
|
||||||
|
ch := format[i]
|
||||||
|
switch ch {
|
||||||
|
case '>':
|
||||||
|
p.indent++
|
||||||
|
continue
|
||||||
|
case '<':
|
||||||
|
p.indent--
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf.WriteByte(ch)
|
||||||
|
if ch == '\n' {
|
||||||
|
for j := p.indent; j > 0; j-- {
|
||||||
|
buf.WriteString(". ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format = buf.String()
|
||||||
|
}
|
||||||
|
fmt.Printf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugging support.
|
||||||
|
// (tagString is only used when tracing is enabled)
|
||||||
|
var tagString = [...]string{
|
||||||
|
// Packages
|
||||||
|
-packageTag: "package",
|
||||||
|
|
||||||
|
// Types
|
||||||
|
-namedTag: "named type",
|
||||||
|
-arrayTag: "array",
|
||||||
|
-sliceTag: "slice",
|
||||||
|
-dddTag: "ddd",
|
||||||
|
-structTag: "struct",
|
||||||
|
-pointerTag: "pointer",
|
||||||
|
-signatureTag: "signature",
|
||||||
|
-interfaceTag: "interface",
|
||||||
|
-mapTag: "map",
|
||||||
|
-chanTag: "chan",
|
||||||
|
|
||||||
|
// Values
|
||||||
|
-falseTag: "false",
|
||||||
|
-trueTag: "true",
|
||||||
|
-int64Tag: "int64",
|
||||||
|
-floatTag: "float",
|
||||||
|
-fractionTag: "fraction",
|
||||||
|
-complexTag: "complex",
|
||||||
|
-stringTag: "string",
|
||||||
|
-unknownTag: "unknown",
|
||||||
|
|
||||||
|
// Type aliases
|
||||||
|
-aliasTag: "alias",
|
||||||
|
}
|
1053
vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go
generated
vendored
Normal file
1053
vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
99
vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go
generated
vendored
Normal file
99
vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This file is a copy of $GOROOT/src/go/internal/gcimporter/exportdata.go.
|
||||||
|
|
||||||
|
// This file implements FindExportData.
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readGopackHeader(r *bufio.Reader) (name string, size int64, err error) {
|
||||||
|
// See $GOROOT/include/ar.h.
|
||||||
|
hdr := make([]byte, 16+12+6+6+8+10+2)
|
||||||
|
_, err = io.ReadFull(r, hdr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// leave for debugging
|
||||||
|
if false {
|
||||||
|
fmt.Printf("header: %s", hdr)
|
||||||
|
}
|
||||||
|
s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
|
||||||
|
length, err := strconv.Atoi(s)
|
||||||
|
size = int64(length)
|
||||||
|
if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
|
||||||
|
err = fmt.Errorf("invalid archive header")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
name = strings.TrimSpace(string(hdr[:16]))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindExportData positions the reader r at the beginning of the
|
||||||
|
// export data section of an underlying GC-created object/archive
|
||||||
|
// file by reading from it. The reader must be positioned at the
|
||||||
|
// start of the file before calling this function. The hdr result
|
||||||
|
// is the string before the export data, either "$$" or "$$B".
|
||||||
|
// The size result is the length of the export data in bytes, or -1 if not known.
|
||||||
|
func FindExportData(r *bufio.Reader) (hdr string, size int64, err error) {
|
||||||
|
// Read first line to make sure this is an object file.
|
||||||
|
line, err := r.ReadSlice('\n')
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("can't find export data (%v)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(line) == "!<arch>\n" {
|
||||||
|
// Archive file. Scan to __.PKGDEF.
|
||||||
|
var name string
|
||||||
|
if name, size, err = readGopackHeader(r); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// First entry should be __.PKGDEF.
|
||||||
|
if name != "__.PKGDEF" {
|
||||||
|
err = fmt.Errorf("go archive is missing __.PKGDEF")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read first line of __.PKGDEF data, so that line
|
||||||
|
// is once again the first line of the input.
|
||||||
|
if line, err = r.ReadSlice('\n'); err != nil {
|
||||||
|
err = fmt.Errorf("can't find export data (%v)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
size -= int64(len(line))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now at __.PKGDEF in archive or still at beginning of file.
|
||||||
|
// Either way, line should begin with "go object ".
|
||||||
|
if !strings.HasPrefix(string(line), "go object ") {
|
||||||
|
err = fmt.Errorf("not a Go object file")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip over object header to export data.
|
||||||
|
// Begins after first line starting with $$.
|
||||||
|
for line[0] != '$' {
|
||||||
|
if line, err = r.ReadSlice('\n'); err != nil {
|
||||||
|
err = fmt.Errorf("can't find export data (%v)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
size -= int64(len(line))
|
||||||
|
}
|
||||||
|
hdr = string(line)
|
||||||
|
if size < 0 {
|
||||||
|
size = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
1125
vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go
generated
vendored
Normal file
1125
vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1010
vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go
generated
vendored
Normal file
1010
vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
878
vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go
generated
vendored
Normal file
878
vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go
generated
vendored
Normal file
@ -0,0 +1,878 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Indexed package import.
|
||||||
|
// See cmd/compile/internal/gc/iexport.go for the export data format.
|
||||||
|
|
||||||
|
// This file is a copy of $GOROOT/src/go/internal/gcimporter/iimport.go.
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"go/constant"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"io"
|
||||||
|
"math/big"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/typeparams"
|
||||||
|
)
|
||||||
|
|
||||||
|
type intReader struct {
|
||||||
|
*bytes.Reader
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *intReader) int64() int64 {
|
||||||
|
i, err := binary.ReadVarint(r.Reader)
|
||||||
|
if err != nil {
|
||||||
|
errorf("import %q: read varint error: %v", r.path, err)
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *intReader) uint64() uint64 {
|
||||||
|
i, err := binary.ReadUvarint(r.Reader)
|
||||||
|
if err != nil {
|
||||||
|
errorf("import %q: read varint error: %v", r.path, err)
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep this in sync with constants in iexport.go.
|
||||||
|
const (
|
||||||
|
iexportVersionGo1_11 = 0
|
||||||
|
iexportVersionPosCol = 1
|
||||||
|
iexportVersionGo1_18 = 2
|
||||||
|
iexportVersionGenerics = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
type ident struct {
|
||||||
|
pkg *types.Package
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
const predeclReserved = 32
|
||||||
|
|
||||||
|
type itag uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Types
|
||||||
|
definedType itag = iota
|
||||||
|
pointerType
|
||||||
|
sliceType
|
||||||
|
arrayType
|
||||||
|
chanType
|
||||||
|
mapType
|
||||||
|
signatureType
|
||||||
|
structType
|
||||||
|
interfaceType
|
||||||
|
typeParamType
|
||||||
|
instanceType
|
||||||
|
unionType
|
||||||
|
)
|
||||||
|
|
||||||
|
// IImportData imports a package from the serialized package data
|
||||||
|
// and returns 0 and a reference to the package.
|
||||||
|
// If the export data version is not recognized or the format is otherwise
|
||||||
|
// compromised, an error is returned.
|
||||||
|
func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) {
|
||||||
|
pkgs, err := iimportCommon(fset, imports, data, false, path)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
return 0, pkgs[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IImportBundle imports a set of packages from the serialized package bundle.
|
||||||
|
func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) {
|
||||||
|
return iimportCommon(fset, imports, data, true, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string) (pkgs []*types.Package, err error) {
|
||||||
|
const currentVersion = 1
|
||||||
|
version := int64(-1)
|
||||||
|
if !debug {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
if bundle {
|
||||||
|
err = fmt.Errorf("%v", e)
|
||||||
|
} else if version > currentVersion {
|
||||||
|
err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
r := &intReader{bytes.NewReader(data), path}
|
||||||
|
|
||||||
|
if bundle {
|
||||||
|
bundleVersion := r.uint64()
|
||||||
|
switch bundleVersion {
|
||||||
|
case bundleVersion:
|
||||||
|
default:
|
||||||
|
errorf("unknown bundle format version %d", bundleVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
version = int64(r.uint64())
|
||||||
|
switch version {
|
||||||
|
case iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11:
|
||||||
|
default:
|
||||||
|
if version > iexportVersionGo1_18 {
|
||||||
|
errorf("unstable iexport format version %d, just rebuild compiler and std library", version)
|
||||||
|
} else {
|
||||||
|
errorf("unknown iexport format version %d", version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sLen := int64(r.uint64())
|
||||||
|
dLen := int64(r.uint64())
|
||||||
|
|
||||||
|
whence, _ := r.Seek(0, io.SeekCurrent)
|
||||||
|
stringData := data[whence : whence+sLen]
|
||||||
|
declData := data[whence+sLen : whence+sLen+dLen]
|
||||||
|
r.Seek(sLen+dLen, io.SeekCurrent)
|
||||||
|
|
||||||
|
p := iimporter{
|
||||||
|
version: int(version),
|
||||||
|
ipath: path,
|
||||||
|
|
||||||
|
stringData: stringData,
|
||||||
|
stringCache: make(map[uint64]string),
|
||||||
|
pkgCache: make(map[uint64]*types.Package),
|
||||||
|
|
||||||
|
declData: declData,
|
||||||
|
pkgIndex: make(map[*types.Package]map[string]uint64),
|
||||||
|
typCache: make(map[uint64]types.Type),
|
||||||
|
// Separate map for typeparams, keyed by their package and unique
|
||||||
|
// name.
|
||||||
|
tparamIndex: make(map[ident]types.Type),
|
||||||
|
|
||||||
|
fake: fakeFileSet{
|
||||||
|
fset: fset,
|
||||||
|
files: make(map[string]*fileInfo),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
defer p.fake.setLines() // set lines for files in fset
|
||||||
|
|
||||||
|
for i, pt := range predeclared() {
|
||||||
|
p.typCache[uint64(i)] = pt
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgList := make([]*types.Package, r.uint64())
|
||||||
|
for i := range pkgList {
|
||||||
|
pkgPathOff := r.uint64()
|
||||||
|
pkgPath := p.stringAt(pkgPathOff)
|
||||||
|
pkgName := p.stringAt(r.uint64())
|
||||||
|
_ = r.uint64() // package height; unused by go/types
|
||||||
|
|
||||||
|
if pkgPath == "" {
|
||||||
|
pkgPath = path
|
||||||
|
}
|
||||||
|
pkg := imports[pkgPath]
|
||||||
|
if pkg == nil {
|
||||||
|
pkg = types.NewPackage(pkgPath, pkgName)
|
||||||
|
imports[pkgPath] = pkg
|
||||||
|
} else if pkg.Name() != pkgName {
|
||||||
|
errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.pkgCache[pkgPathOff] = pkg
|
||||||
|
|
||||||
|
nameIndex := make(map[string]uint64)
|
||||||
|
for nSyms := r.uint64(); nSyms > 0; nSyms-- {
|
||||||
|
name := p.stringAt(r.uint64())
|
||||||
|
nameIndex[name] = r.uint64()
|
||||||
|
}
|
||||||
|
|
||||||
|
p.pkgIndex[pkg] = nameIndex
|
||||||
|
pkgList[i] = pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle {
|
||||||
|
pkgs = make([]*types.Package, r.uint64())
|
||||||
|
for i := range pkgs {
|
||||||
|
pkg := p.pkgAt(r.uint64())
|
||||||
|
imps := make([]*types.Package, r.uint64())
|
||||||
|
for j := range imps {
|
||||||
|
imps[j] = p.pkgAt(r.uint64())
|
||||||
|
}
|
||||||
|
pkg.SetImports(imps)
|
||||||
|
pkgs[i] = pkg
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(pkgList) == 0 {
|
||||||
|
errorf("no packages found for %s", path)
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
pkgs = pkgList[:1]
|
||||||
|
|
||||||
|
// record all referenced packages as imports
|
||||||
|
list := append(([]*types.Package)(nil), pkgList[1:]...)
|
||||||
|
sort.Sort(byPath(list))
|
||||||
|
pkgs[0].SetImports(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
if pkg.Complete() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
names := make([]string, 0, len(p.pkgIndex[pkg]))
|
||||||
|
for name := range p.pkgIndex[pkg] {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
for _, name := range names {
|
||||||
|
p.doDecl(pkg, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// package was imported completely and without errors
|
||||||
|
pkg.MarkComplete()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConstraint can't be called if the constraint type is not yet complete.
|
||||||
|
// When type params are created in the 'P' case of (*importReader).obj(),
|
||||||
|
// the associated constraint type may not be complete due to recursion.
|
||||||
|
// Therefore, we defer calling SetConstraint there, and call it here instead
|
||||||
|
// after all types are complete.
|
||||||
|
for _, d := range p.later {
|
||||||
|
typeparams.SetTypeParamConstraint(d.t, d.constraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, typ := range p.interfaceList {
|
||||||
|
typ.Complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type setConstraintArgs struct {
|
||||||
|
t *typeparams.TypeParam
|
||||||
|
constraint types.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
type iimporter struct {
|
||||||
|
version int
|
||||||
|
ipath string
|
||||||
|
|
||||||
|
stringData []byte
|
||||||
|
stringCache map[uint64]string
|
||||||
|
pkgCache map[uint64]*types.Package
|
||||||
|
|
||||||
|
declData []byte
|
||||||
|
pkgIndex map[*types.Package]map[string]uint64
|
||||||
|
typCache map[uint64]types.Type
|
||||||
|
tparamIndex map[ident]types.Type
|
||||||
|
|
||||||
|
fake fakeFileSet
|
||||||
|
interfaceList []*types.Interface
|
||||||
|
|
||||||
|
// Arguments for calls to SetConstraint that are deferred due to recursive types
|
||||||
|
later []setConstraintArgs
|
||||||
|
|
||||||
|
indent int // for tracing support
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *iimporter) trace(format string, args ...interface{}) {
|
||||||
|
if !trace {
|
||||||
|
// Call sites should also be guarded, but having this check here allows
|
||||||
|
// easily enabling/disabling debug trace statements.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *iimporter) doDecl(pkg *types.Package, name string) {
|
||||||
|
if debug {
|
||||||
|
p.trace("import decl %s", name)
|
||||||
|
p.indent++
|
||||||
|
defer func() {
|
||||||
|
p.indent--
|
||||||
|
p.trace("=> %s", name)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
// See if we've already imported this declaration.
|
||||||
|
if obj := pkg.Scope().Lookup(name); obj != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
off, ok := p.pkgIndex[pkg][name]
|
||||||
|
if !ok {
|
||||||
|
errorf("%v.%v not in index", pkg, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := &importReader{p: p, currPkg: pkg}
|
||||||
|
r.declReader.Reset(p.declData[off:])
|
||||||
|
|
||||||
|
r.obj(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *iimporter) stringAt(off uint64) string {
|
||||||
|
if s, ok := p.stringCache[off]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
slen, n := binary.Uvarint(p.stringData[off:])
|
||||||
|
if n <= 0 {
|
||||||
|
errorf("varint failed")
|
||||||
|
}
|
||||||
|
spos := off + uint64(n)
|
||||||
|
s := string(p.stringData[spos : spos+slen])
|
||||||
|
p.stringCache[off] = s
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *iimporter) pkgAt(off uint64) *types.Package {
|
||||||
|
if pkg, ok := p.pkgCache[off]; ok {
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
|
path := p.stringAt(off)
|
||||||
|
errorf("missing package %q in %q", path, p.ipath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *iimporter) typAt(off uint64, base *types.Named) types.Type {
|
||||||
|
if t, ok := p.typCache[off]; ok && canReuse(base, t) {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
if off < predeclReserved {
|
||||||
|
errorf("predeclared type missing from cache: %v", off)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := &importReader{p: p}
|
||||||
|
r.declReader.Reset(p.declData[off-predeclReserved:])
|
||||||
|
t := r.doType(base)
|
||||||
|
|
||||||
|
if canReuse(base, t) {
|
||||||
|
p.typCache[off] = t
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// canReuse reports whether the type rhs on the RHS of the declaration for def
|
||||||
|
// may be re-used.
|
||||||
|
//
|
||||||
|
// Specifically, if def is non-nil and rhs is an interface type with methods, it
|
||||||
|
// may not be re-used because we have a convention of setting the receiver type
|
||||||
|
// for interface methods to def.
|
||||||
|
func canReuse(def *types.Named, rhs types.Type) bool {
|
||||||
|
if def == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
iface, _ := rhs.(*types.Interface)
|
||||||
|
if iface == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// Don't use iface.Empty() here as iface may not be complete.
|
||||||
|
return iface.NumEmbeddeds() == 0 && iface.NumExplicitMethods() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type importReader struct {
|
||||||
|
p *iimporter
|
||||||
|
declReader bytes.Reader
|
||||||
|
currPkg *types.Package
|
||||||
|
prevFile string
|
||||||
|
prevLine int64
|
||||||
|
prevColumn int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) obj(name string) {
|
||||||
|
tag := r.byte()
|
||||||
|
pos := r.pos()
|
||||||
|
|
||||||
|
switch tag {
|
||||||
|
case 'A':
|
||||||
|
typ := r.typ()
|
||||||
|
|
||||||
|
r.declare(types.NewTypeName(pos, r.currPkg, name, typ))
|
||||||
|
|
||||||
|
case 'C':
|
||||||
|
typ, val := r.value()
|
||||||
|
|
||||||
|
r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
|
||||||
|
|
||||||
|
case 'F', 'G':
|
||||||
|
var tparams []*typeparams.TypeParam
|
||||||
|
if tag == 'G' {
|
||||||
|
tparams = r.tparamList()
|
||||||
|
}
|
||||||
|
sig := r.signature(nil, nil, tparams)
|
||||||
|
r.declare(types.NewFunc(pos, r.currPkg, name, sig))
|
||||||
|
|
||||||
|
case 'T', 'U':
|
||||||
|
// Types can be recursive. We need to setup a stub
|
||||||
|
// declaration before recursing.
|
||||||
|
obj := types.NewTypeName(pos, r.currPkg, name, nil)
|
||||||
|
named := types.NewNamed(obj, nil, nil)
|
||||||
|
// Declare obj before calling r.tparamList, so the new type name is recognized
|
||||||
|
// if used in the constraint of one of its own typeparams (see #48280).
|
||||||
|
r.declare(obj)
|
||||||
|
if tag == 'U' {
|
||||||
|
tparams := r.tparamList()
|
||||||
|
typeparams.SetForNamed(named, tparams)
|
||||||
|
}
|
||||||
|
|
||||||
|
underlying := r.p.typAt(r.uint64(), named).Underlying()
|
||||||
|
named.SetUnderlying(underlying)
|
||||||
|
|
||||||
|
if !isInterface(underlying) {
|
||||||
|
for n := r.uint64(); n > 0; n-- {
|
||||||
|
mpos := r.pos()
|
||||||
|
mname := r.ident()
|
||||||
|
recv := r.param()
|
||||||
|
|
||||||
|
// If the receiver has any targs, set those as the
|
||||||
|
// rparams of the method (since those are the
|
||||||
|
// typeparams being used in the method sig/body).
|
||||||
|
base := baseType(recv.Type())
|
||||||
|
assert(base != nil)
|
||||||
|
targs := typeparams.NamedTypeArgs(base)
|
||||||
|
var rparams []*typeparams.TypeParam
|
||||||
|
if targs.Len() > 0 {
|
||||||
|
rparams = make([]*typeparams.TypeParam, targs.Len())
|
||||||
|
for i := range rparams {
|
||||||
|
rparams[i] = targs.At(i).(*typeparams.TypeParam)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msig := r.signature(recv, rparams, nil)
|
||||||
|
|
||||||
|
named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'P':
|
||||||
|
// We need to "declare" a typeparam in order to have a name that
|
||||||
|
// can be referenced recursively (if needed) in the type param's
|
||||||
|
// bound.
|
||||||
|
if r.p.version < iexportVersionGenerics {
|
||||||
|
errorf("unexpected type param type")
|
||||||
|
}
|
||||||
|
name0 := tparamName(name)
|
||||||
|
tn := types.NewTypeName(pos, r.currPkg, name0, nil)
|
||||||
|
t := typeparams.NewTypeParam(tn, nil)
|
||||||
|
|
||||||
|
// To handle recursive references to the typeparam within its
|
||||||
|
// bound, save the partial type in tparamIndex before reading the bounds.
|
||||||
|
id := ident{r.currPkg, name}
|
||||||
|
r.p.tparamIndex[id] = t
|
||||||
|
var implicit bool
|
||||||
|
if r.p.version >= iexportVersionGo1_18 {
|
||||||
|
implicit = r.bool()
|
||||||
|
}
|
||||||
|
constraint := r.typ()
|
||||||
|
if implicit {
|
||||||
|
iface, _ := constraint.(*types.Interface)
|
||||||
|
if iface == nil {
|
||||||
|
errorf("non-interface constraint marked implicit")
|
||||||
|
}
|
||||||
|
typeparams.MarkImplicit(iface)
|
||||||
|
}
|
||||||
|
// The constraint type may not be complete, if we
|
||||||
|
// are in the middle of a type recursion involving type
|
||||||
|
// constraints. So, we defer SetConstraint until we have
|
||||||
|
// completely set up all types in ImportData.
|
||||||
|
r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint})
|
||||||
|
|
||||||
|
case 'V':
|
||||||
|
typ := r.typ()
|
||||||
|
|
||||||
|
r.declare(types.NewVar(pos, r.currPkg, name, typ))
|
||||||
|
|
||||||
|
default:
|
||||||
|
errorf("unexpected tag: %v", tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) declare(obj types.Object) {
|
||||||
|
obj.Pkg().Scope().Insert(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) value() (typ types.Type, val constant.Value) {
|
||||||
|
typ = r.typ()
|
||||||
|
if r.p.version >= iexportVersionGo1_18 {
|
||||||
|
// TODO: add support for using the kind.
|
||||||
|
_ = constant.Kind(r.int64())
|
||||||
|
}
|
||||||
|
|
||||||
|
switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
|
||||||
|
case types.IsBoolean:
|
||||||
|
val = constant.MakeBool(r.bool())
|
||||||
|
|
||||||
|
case types.IsString:
|
||||||
|
val = constant.MakeString(r.string())
|
||||||
|
|
||||||
|
case types.IsInteger:
|
||||||
|
var x big.Int
|
||||||
|
r.mpint(&x, b)
|
||||||
|
val = constant.Make(&x)
|
||||||
|
|
||||||
|
case types.IsFloat:
|
||||||
|
val = r.mpfloat(b)
|
||||||
|
|
||||||
|
case types.IsComplex:
|
||||||
|
re := r.mpfloat(b)
|
||||||
|
im := r.mpfloat(b)
|
||||||
|
val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
|
||||||
|
|
||||||
|
default:
|
||||||
|
if b.Kind() == types.Invalid {
|
||||||
|
val = constant.MakeUnknown()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errorf("unexpected type %v", typ) // panics
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func intSize(b *types.Basic) (signed bool, maxBytes uint) {
|
||||||
|
if (b.Info() & types.IsUntyped) != 0 {
|
||||||
|
return true, 64
|
||||||
|
}
|
||||||
|
|
||||||
|
switch b.Kind() {
|
||||||
|
case types.Float32, types.Complex64:
|
||||||
|
return true, 3
|
||||||
|
case types.Float64, types.Complex128:
|
||||||
|
return true, 7
|
||||||
|
}
|
||||||
|
|
||||||
|
signed = (b.Info() & types.IsUnsigned) == 0
|
||||||
|
switch b.Kind() {
|
||||||
|
case types.Int8, types.Uint8:
|
||||||
|
maxBytes = 1
|
||||||
|
case types.Int16, types.Uint16:
|
||||||
|
maxBytes = 2
|
||||||
|
case types.Int32, types.Uint32:
|
||||||
|
maxBytes = 4
|
||||||
|
default:
|
||||||
|
maxBytes = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) mpint(x *big.Int, typ *types.Basic) {
|
||||||
|
signed, maxBytes := intSize(typ)
|
||||||
|
|
||||||
|
maxSmall := 256 - maxBytes
|
||||||
|
if signed {
|
||||||
|
maxSmall = 256 - 2*maxBytes
|
||||||
|
}
|
||||||
|
if maxBytes == 1 {
|
||||||
|
maxSmall = 256
|
||||||
|
}
|
||||||
|
|
||||||
|
n, _ := r.declReader.ReadByte()
|
||||||
|
if uint(n) < maxSmall {
|
||||||
|
v := int64(n)
|
||||||
|
if signed {
|
||||||
|
v >>= 1
|
||||||
|
if n&1 != 0 {
|
||||||
|
v = ^v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x.SetInt64(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := -n
|
||||||
|
if signed {
|
||||||
|
v = -(n &^ 1) >> 1
|
||||||
|
}
|
||||||
|
if v < 1 || uint(v) > maxBytes {
|
||||||
|
errorf("weird decoding: %v, %v => %v", n, signed, v)
|
||||||
|
}
|
||||||
|
b := make([]byte, v)
|
||||||
|
io.ReadFull(&r.declReader, b)
|
||||||
|
x.SetBytes(b)
|
||||||
|
if signed && n&1 != 0 {
|
||||||
|
x.Neg(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) mpfloat(typ *types.Basic) constant.Value {
|
||||||
|
var mant big.Int
|
||||||
|
r.mpint(&mant, typ)
|
||||||
|
var f big.Float
|
||||||
|
f.SetInt(&mant)
|
||||||
|
if f.Sign() != 0 {
|
||||||
|
f.SetMantExp(&f, int(r.int64()))
|
||||||
|
}
|
||||||
|
return constant.Make(&f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) ident() string {
|
||||||
|
return r.string()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) qualifiedIdent() (*types.Package, string) {
|
||||||
|
name := r.string()
|
||||||
|
pkg := r.pkg()
|
||||||
|
return pkg, name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) pos() token.Pos {
|
||||||
|
if r.p.version >= iexportVersionPosCol {
|
||||||
|
r.posv1()
|
||||||
|
} else {
|
||||||
|
r.posv0()
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.prevFile == "" && r.prevLine == 0 && r.prevColumn == 0 {
|
||||||
|
return token.NoPos
|
||||||
|
}
|
||||||
|
return r.p.fake.pos(r.prevFile, int(r.prevLine), int(r.prevColumn))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) posv0() {
|
||||||
|
delta := r.int64()
|
||||||
|
if delta != deltaNewFile {
|
||||||
|
r.prevLine += delta
|
||||||
|
} else if l := r.int64(); l == -1 {
|
||||||
|
r.prevLine += deltaNewFile
|
||||||
|
} else {
|
||||||
|
r.prevFile = r.string()
|
||||||
|
r.prevLine = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) posv1() {
|
||||||
|
delta := r.int64()
|
||||||
|
r.prevColumn += delta >> 1
|
||||||
|
if delta&1 != 0 {
|
||||||
|
delta = r.int64()
|
||||||
|
r.prevLine += delta >> 1
|
||||||
|
if delta&1 != 0 {
|
||||||
|
r.prevFile = r.string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) typ() types.Type {
|
||||||
|
return r.p.typAt(r.uint64(), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isInterface(t types.Type) bool {
|
||||||
|
_, ok := t.(*types.Interface)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) pkg() *types.Package { return r.p.pkgAt(r.uint64()) }
|
||||||
|
func (r *importReader) string() string { return r.p.stringAt(r.uint64()) }
|
||||||
|
|
||||||
|
func (r *importReader) doType(base *types.Named) (res types.Type) {
|
||||||
|
k := r.kind()
|
||||||
|
if debug {
|
||||||
|
r.p.trace("importing type %d (base: %s)", k, base)
|
||||||
|
r.p.indent++
|
||||||
|
defer func() {
|
||||||
|
r.p.indent--
|
||||||
|
r.p.trace("=> %s", res)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
switch k {
|
||||||
|
default:
|
||||||
|
errorf("unexpected kind tag in %q: %v", r.p.ipath, k)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case definedType:
|
||||||
|
pkg, name := r.qualifiedIdent()
|
||||||
|
r.p.doDecl(pkg, name)
|
||||||
|
return pkg.Scope().Lookup(name).(*types.TypeName).Type()
|
||||||
|
case pointerType:
|
||||||
|
return types.NewPointer(r.typ())
|
||||||
|
case sliceType:
|
||||||
|
return types.NewSlice(r.typ())
|
||||||
|
case arrayType:
|
||||||
|
n := r.uint64()
|
||||||
|
return types.NewArray(r.typ(), int64(n))
|
||||||
|
case chanType:
|
||||||
|
dir := chanDir(int(r.uint64()))
|
||||||
|
return types.NewChan(dir, r.typ())
|
||||||
|
case mapType:
|
||||||
|
return types.NewMap(r.typ(), r.typ())
|
||||||
|
case signatureType:
|
||||||
|
r.currPkg = r.pkg()
|
||||||
|
return r.signature(nil, nil, nil)
|
||||||
|
|
||||||
|
case structType:
|
||||||
|
r.currPkg = r.pkg()
|
||||||
|
|
||||||
|
fields := make([]*types.Var, r.uint64())
|
||||||
|
tags := make([]string, len(fields))
|
||||||
|
for i := range fields {
|
||||||
|
fpos := r.pos()
|
||||||
|
fname := r.ident()
|
||||||
|
ftyp := r.typ()
|
||||||
|
emb := r.bool()
|
||||||
|
tag := r.string()
|
||||||
|
|
||||||
|
fields[i] = types.NewField(fpos, r.currPkg, fname, ftyp, emb)
|
||||||
|
tags[i] = tag
|
||||||
|
}
|
||||||
|
return types.NewStruct(fields, tags)
|
||||||
|
|
||||||
|
case interfaceType:
|
||||||
|
r.currPkg = r.pkg()
|
||||||
|
|
||||||
|
embeddeds := make([]types.Type, r.uint64())
|
||||||
|
for i := range embeddeds {
|
||||||
|
_ = r.pos()
|
||||||
|
embeddeds[i] = r.typ()
|
||||||
|
}
|
||||||
|
|
||||||
|
methods := make([]*types.Func, r.uint64())
|
||||||
|
for i := range methods {
|
||||||
|
mpos := r.pos()
|
||||||
|
mname := r.ident()
|
||||||
|
|
||||||
|
// TODO(mdempsky): Matches bimport.go, but I
|
||||||
|
// don't agree with this.
|
||||||
|
var recv *types.Var
|
||||||
|
if base != nil {
|
||||||
|
recv = types.NewVar(token.NoPos, r.currPkg, "", base)
|
||||||
|
}
|
||||||
|
|
||||||
|
msig := r.signature(recv, nil, nil)
|
||||||
|
methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig)
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := newInterface(methods, embeddeds)
|
||||||
|
r.p.interfaceList = append(r.p.interfaceList, typ)
|
||||||
|
return typ
|
||||||
|
|
||||||
|
case typeParamType:
|
||||||
|
if r.p.version < iexportVersionGenerics {
|
||||||
|
errorf("unexpected type param type")
|
||||||
|
}
|
||||||
|
pkg, name := r.qualifiedIdent()
|
||||||
|
id := ident{pkg, name}
|
||||||
|
if t, ok := r.p.tparamIndex[id]; ok {
|
||||||
|
// We're already in the process of importing this typeparam.
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
// Otherwise, import the definition of the typeparam now.
|
||||||
|
r.p.doDecl(pkg, name)
|
||||||
|
return r.p.tparamIndex[id]
|
||||||
|
|
||||||
|
case instanceType:
|
||||||
|
if r.p.version < iexportVersionGenerics {
|
||||||
|
errorf("unexpected instantiation type")
|
||||||
|
}
|
||||||
|
// pos does not matter for instances: they are positioned on the original
|
||||||
|
// type.
|
||||||
|
_ = r.pos()
|
||||||
|
len := r.uint64()
|
||||||
|
targs := make([]types.Type, len)
|
||||||
|
for i := range targs {
|
||||||
|
targs[i] = r.typ()
|
||||||
|
}
|
||||||
|
baseType := r.typ()
|
||||||
|
// The imported instantiated type doesn't include any methods, so
|
||||||
|
// we must always use the methods of the base (orig) type.
|
||||||
|
// TODO provide a non-nil *Environment
|
||||||
|
t, _ := typeparams.Instantiate(nil, baseType, targs, false)
|
||||||
|
return t
|
||||||
|
|
||||||
|
case unionType:
|
||||||
|
if r.p.version < iexportVersionGenerics {
|
||||||
|
errorf("unexpected instantiation type")
|
||||||
|
}
|
||||||
|
terms := make([]*typeparams.Term, r.uint64())
|
||||||
|
for i := range terms {
|
||||||
|
terms[i] = typeparams.NewTerm(r.bool(), r.typ())
|
||||||
|
}
|
||||||
|
return typeparams.NewUnion(terms)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) kind() itag {
|
||||||
|
return itag(r.uint64())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) signature(recv *types.Var, rparams []*typeparams.TypeParam, tparams []*typeparams.TypeParam) *types.Signature {
|
||||||
|
params := r.paramList()
|
||||||
|
results := r.paramList()
|
||||||
|
variadic := params.Len() > 0 && r.bool()
|
||||||
|
return typeparams.NewSignatureType(recv, rparams, tparams, params, results, variadic)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) tparamList() []*typeparams.TypeParam {
|
||||||
|
n := r.uint64()
|
||||||
|
if n == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
xs := make([]*typeparams.TypeParam, n)
|
||||||
|
for i := range xs {
|
||||||
|
// Note: the standard library importer is tolerant of nil types here,
|
||||||
|
// though would panic in SetTypeParams.
|
||||||
|
xs[i] = r.typ().(*typeparams.TypeParam)
|
||||||
|
}
|
||||||
|
return xs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) paramList() *types.Tuple {
|
||||||
|
xs := make([]*types.Var, r.uint64())
|
||||||
|
for i := range xs {
|
||||||
|
xs[i] = r.param()
|
||||||
|
}
|
||||||
|
return types.NewTuple(xs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) param() *types.Var {
|
||||||
|
pos := r.pos()
|
||||||
|
name := r.ident()
|
||||||
|
typ := r.typ()
|
||||||
|
return types.NewParam(pos, r.currPkg, name, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) bool() bool {
|
||||||
|
return r.uint64() != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) int64() int64 {
|
||||||
|
n, err := binary.ReadVarint(&r.declReader)
|
||||||
|
if err != nil {
|
||||||
|
errorf("readVarint: %v", err)
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) uint64() uint64 {
|
||||||
|
n, err := binary.ReadUvarint(&r.declReader)
|
||||||
|
if err != nil {
|
||||||
|
errorf("readUvarint: %v", err)
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *importReader) byte() byte {
|
||||||
|
x, err := r.declReader.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
errorf("declReader.ReadByte: %v", err)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func baseType(typ types.Type) *types.Named {
|
||||||
|
// pointer receivers are never types.Named types
|
||||||
|
if p, _ := typ.(*types.Pointer); p != nil {
|
||||||
|
typ = p.Elem()
|
||||||
|
}
|
||||||
|
// receiver base types are always (possibly generic) types.Named types
|
||||||
|
n, _ := typ.(*types.Named)
|
||||||
|
return n
|
||||||
|
}
|
22
vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go
generated
vendored
Normal file
22
vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !go1.11
|
||||||
|
// +build !go1.11
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
import "go/types"
|
||||||
|
|
||||||
|
func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface {
|
||||||
|
named := make([]*types.Named, len(embeddeds))
|
||||||
|
for i, e := range embeddeds {
|
||||||
|
var ok bool
|
||||||
|
named[i], ok = e.(*types.Named)
|
||||||
|
if !ok {
|
||||||
|
panic("embedding of non-defined interfaces in interfaces is not supported before Go 1.11")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return types.NewInterface(methods, named)
|
||||||
|
}
|
14
vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go
generated
vendored
Normal file
14
vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build go1.11
|
||||||
|
// +build go1.11
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
import "go/types"
|
||||||
|
|
||||||
|
func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface {
|
||||||
|
return types.NewInterfaceType(methods, embeddeds)
|
||||||
|
}
|
16
vendor/golang.org/x/tools/go/internal/gcimporter/support_go117.go
generated
vendored
Normal file
16
vendor/golang.org/x/tools/go/internal/gcimporter/support_go117.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !go1.18
|
||||||
|
// +build !go1.18
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
import "go/types"
|
||||||
|
|
||||||
|
const iexportVersion = iexportVersionGo1_11
|
||||||
|
|
||||||
|
func additionalPredeclared() []types.Type {
|
||||||
|
return nil
|
||||||
|
}
|
23
vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go
generated
vendored
Normal file
23
vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
import "go/types"
|
||||||
|
|
||||||
|
const iexportVersion = iexportVersionGenerics
|
||||||
|
|
||||||
|
// additionalPredeclared returns additional predeclared types in go.1.18.
|
||||||
|
func additionalPredeclared() []types.Type {
|
||||||
|
return []types.Type{
|
||||||
|
// comparable
|
||||||
|
types.Universe.Lookup("comparable").Type(),
|
||||||
|
|
||||||
|
// any
|
||||||
|
types.Universe.Lookup("any").Type(),
|
||||||
|
}
|
||||||
|
}
|
10
vendor/golang.org/x/tools/go/internal/gcimporter/unified_no.go
generated
vendored
Normal file
10
vendor/golang.org/x/tools/go/internal/gcimporter/unified_no.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !(go1.18 && goexperiment.unified)
|
||||||
|
// +build !go1.18 !goexperiment.unified
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
const unifiedIR = false
|
10
vendor/golang.org/x/tools/go/internal/gcimporter/unified_yes.go
generated
vendored
Normal file
10
vendor/golang.org/x/tools/go/internal/gcimporter/unified_yes.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build go1.18 && goexperiment.unified
|
||||||
|
// +build go1.18,goexperiment.unified
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
const unifiedIR = true
|
19
vendor/golang.org/x/tools/go/internal/gcimporter/ureader_no.go
generated
vendored
Normal file
19
vendor/golang.org/x/tools/go/internal/gcimporter/ureader_no.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !go1.18
|
||||||
|
// +build !go1.18
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
|
||||||
|
err = fmt.Errorf("go/tools compiled with a Go version earlier than 1.18 cannot read unified IR export data")
|
||||||
|
return
|
||||||
|
}
|
612
vendor/golang.org/x/tools/go/internal/gcimporter/ureader_yes.go
generated
vendored
Normal file
612
vendor/golang.org/x/tools/go/internal/gcimporter/ureader_yes.go
generated
vendored
Normal file
@ -0,0 +1,612 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Derived from go/internal/gcimporter/ureader.go
|
||||||
|
|
||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/internal/pkgbits"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A pkgReader holds the shared state for reading a unified IR package
|
||||||
|
// description.
|
||||||
|
type pkgReader struct {
|
||||||
|
pkgbits.PkgDecoder
|
||||||
|
|
||||||
|
fake fakeFileSet
|
||||||
|
|
||||||
|
ctxt *types.Context
|
||||||
|
imports map[string]*types.Package // previously imported packages, indexed by path
|
||||||
|
|
||||||
|
// lazily initialized arrays corresponding to the unified IR
|
||||||
|
// PosBase, Pkg, and Type sections, respectively.
|
||||||
|
posBases []string // position bases (i.e., file names)
|
||||||
|
pkgs []*types.Package
|
||||||
|
typs []types.Type
|
||||||
|
|
||||||
|
// laterFns holds functions that need to be invoked at the end of
|
||||||
|
// import reading.
|
||||||
|
laterFns []func()
|
||||||
|
}
|
||||||
|
|
||||||
|
// later adds a function to be invoked at the end of import reading.
|
||||||
|
func (pr *pkgReader) later(fn func()) {
|
||||||
|
pr.laterFns = append(pr.laterFns, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// See cmd/compile/internal/noder.derivedInfo.
|
||||||
|
type derivedInfo struct {
|
||||||
|
idx pkgbits.Index
|
||||||
|
needed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// See cmd/compile/internal/noder.typeInfo.
|
||||||
|
type typeInfo struct {
|
||||||
|
idx pkgbits.Index
|
||||||
|
derived bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
|
||||||
|
s := string(data)
|
||||||
|
s = s[:strings.LastIndex(s, "\n$$\n")]
|
||||||
|
input := pkgbits.NewPkgDecoder(path, s)
|
||||||
|
pkg = readUnifiedPackage(fset, nil, imports, input)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// readUnifiedPackage reads a package description from the given
|
||||||
|
// unified IR export data decoder.
|
||||||
|
func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[string]*types.Package, input pkgbits.PkgDecoder) *types.Package {
|
||||||
|
pr := pkgReader{
|
||||||
|
PkgDecoder: input,
|
||||||
|
|
||||||
|
fake: fakeFileSet{
|
||||||
|
fset: fset,
|
||||||
|
files: make(map[string]*fileInfo),
|
||||||
|
},
|
||||||
|
|
||||||
|
ctxt: ctxt,
|
||||||
|
imports: imports,
|
||||||
|
|
||||||
|
posBases: make([]string, input.NumElems(pkgbits.RelocPosBase)),
|
||||||
|
pkgs: make([]*types.Package, input.NumElems(pkgbits.RelocPkg)),
|
||||||
|
typs: make([]types.Type, input.NumElems(pkgbits.RelocType)),
|
||||||
|
}
|
||||||
|
defer pr.fake.setLines()
|
||||||
|
|
||||||
|
r := pr.newReader(pkgbits.RelocMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic)
|
||||||
|
pkg := r.pkg()
|
||||||
|
r.Bool() // has init
|
||||||
|
|
||||||
|
for i, n := 0, r.Len(); i < n; i++ {
|
||||||
|
// As if r.obj(), but avoiding the Scope.Lookup call,
|
||||||
|
// to avoid eager loading of imports.
|
||||||
|
r.Sync(pkgbits.SyncObject)
|
||||||
|
assert(!r.Bool())
|
||||||
|
r.p.objIdx(r.Reloc(pkgbits.RelocObj))
|
||||||
|
assert(r.Len() == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Sync(pkgbits.SyncEOF)
|
||||||
|
|
||||||
|
for _, fn := range pr.laterFns {
|
||||||
|
fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg.MarkComplete()
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
// A reader holds the state for reading a single unified IR element
|
||||||
|
// within a package.
|
||||||
|
type reader struct {
|
||||||
|
pkgbits.Decoder
|
||||||
|
|
||||||
|
p *pkgReader
|
||||||
|
|
||||||
|
dict *readerDict
|
||||||
|
}
|
||||||
|
|
||||||
|
// A readerDict holds the state for type parameters that parameterize
|
||||||
|
// the current unified IR element.
|
||||||
|
type readerDict struct {
|
||||||
|
// bounds is a slice of typeInfos corresponding to the underlying
|
||||||
|
// bounds of the element's type parameters.
|
||||||
|
bounds []typeInfo
|
||||||
|
|
||||||
|
// tparams is a slice of the constructed TypeParams for the element.
|
||||||
|
tparams []*types.TypeParam
|
||||||
|
|
||||||
|
// devived is a slice of types derived from tparams, which may be
|
||||||
|
// instantiated while reading the current element.
|
||||||
|
derived []derivedInfo
|
||||||
|
derivedTypes []types.Type // lazily instantiated from derived
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader {
|
||||||
|
return &reader{
|
||||||
|
Decoder: pr.NewDecoder(k, idx, marker),
|
||||||
|
p: pr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@@ Positions
|
||||||
|
|
||||||
|
func (r *reader) pos() token.Pos {
|
||||||
|
r.Sync(pkgbits.SyncPos)
|
||||||
|
if !r.Bool() {
|
||||||
|
return token.NoPos
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(mdempsky): Delta encoding.
|
||||||
|
posBase := r.posBase()
|
||||||
|
line := r.Uint()
|
||||||
|
col := r.Uint()
|
||||||
|
return r.p.fake.pos(posBase, int(line), int(col))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) posBase() string {
|
||||||
|
return r.p.posBaseIdx(r.Reloc(pkgbits.RelocPosBase))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) string {
|
||||||
|
if b := pr.posBases[idx]; b != "" {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
r := pr.newReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase)
|
||||||
|
|
||||||
|
// Within types2, position bases have a lot more details (e.g.,
|
||||||
|
// keeping track of where //line directives appeared exactly).
|
||||||
|
//
|
||||||
|
// For go/types, we just track the file name.
|
||||||
|
|
||||||
|
filename := r.String()
|
||||||
|
|
||||||
|
if r.Bool() { // file base
|
||||||
|
// Was: "b = token.NewTrimmedFileBase(filename, true)"
|
||||||
|
} else { // line base
|
||||||
|
pos := r.pos()
|
||||||
|
line := r.Uint()
|
||||||
|
col := r.Uint()
|
||||||
|
|
||||||
|
// Was: "b = token.NewLineBase(pos, filename, true, line, col)"
|
||||||
|
_, _, _ = pos, line, col
|
||||||
|
}
|
||||||
|
|
||||||
|
b := filename
|
||||||
|
pr.posBases[idx] = b
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@@ Packages
|
||||||
|
|
||||||
|
func (r *reader) pkg() *types.Package {
|
||||||
|
r.Sync(pkgbits.SyncPkg)
|
||||||
|
return r.p.pkgIdx(r.Reloc(pkgbits.RelocPkg))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *pkgReader) pkgIdx(idx pkgbits.Index) *types.Package {
|
||||||
|
// TODO(mdempsky): Consider using some non-nil pointer to indicate
|
||||||
|
// the universe scope, so we don't need to keep re-reading it.
|
||||||
|
if pkg := pr.pkgs[idx]; pkg != nil {
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg := pr.newReader(pkgbits.RelocPkg, idx, pkgbits.SyncPkgDef).doPkg()
|
||||||
|
pr.pkgs[idx] = pkg
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) doPkg() *types.Package {
|
||||||
|
path := r.String()
|
||||||
|
switch path {
|
||||||
|
case "":
|
||||||
|
path = r.p.PkgPath()
|
||||||
|
case "builtin":
|
||||||
|
return nil // universe
|
||||||
|
case "unsafe":
|
||||||
|
return types.Unsafe
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkg := r.p.imports[path]; pkg != nil {
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
name := r.String()
|
||||||
|
|
||||||
|
pkg := types.NewPackage(path, name)
|
||||||
|
r.p.imports[path] = pkg
|
||||||
|
|
||||||
|
imports := make([]*types.Package, r.Len())
|
||||||
|
for i := range imports {
|
||||||
|
imports[i] = r.pkg()
|
||||||
|
}
|
||||||
|
pkg.SetImports(imports)
|
||||||
|
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@@ Types
|
||||||
|
|
||||||
|
func (r *reader) typ() types.Type {
|
||||||
|
return r.p.typIdx(r.typInfo(), r.dict)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) typInfo() typeInfo {
|
||||||
|
r.Sync(pkgbits.SyncType)
|
||||||
|
if r.Bool() {
|
||||||
|
return typeInfo{idx: pkgbits.Index(r.Len()), derived: true}
|
||||||
|
}
|
||||||
|
return typeInfo{idx: r.Reloc(pkgbits.RelocType), derived: false}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) types.Type {
|
||||||
|
idx := info.idx
|
||||||
|
var where *types.Type
|
||||||
|
if info.derived {
|
||||||
|
where = &dict.derivedTypes[idx]
|
||||||
|
idx = dict.derived[idx].idx
|
||||||
|
} else {
|
||||||
|
where = &pr.typs[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
if typ := *where; typ != nil {
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
|
||||||
|
r := pr.newReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx)
|
||||||
|
r.dict = dict
|
||||||
|
|
||||||
|
typ := r.doTyp()
|
||||||
|
assert(typ != nil)
|
||||||
|
|
||||||
|
// See comment in pkgReader.typIdx explaining how this happens.
|
||||||
|
if prev := *where; prev != nil {
|
||||||
|
return prev
|
||||||
|
}
|
||||||
|
|
||||||
|
*where = typ
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) doTyp() (res types.Type) {
|
||||||
|
switch tag := pkgbits.CodeType(r.Code(pkgbits.SyncType)); tag {
|
||||||
|
default:
|
||||||
|
errorf("unhandled type tag: %v", tag)
|
||||||
|
panic("unreachable")
|
||||||
|
|
||||||
|
case pkgbits.TypeBasic:
|
||||||
|
return types.Typ[r.Len()]
|
||||||
|
|
||||||
|
case pkgbits.TypeNamed:
|
||||||
|
obj, targs := r.obj()
|
||||||
|
name := obj.(*types.TypeName)
|
||||||
|
if len(targs) != 0 {
|
||||||
|
t, _ := types.Instantiate(r.p.ctxt, name.Type(), targs, false)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
return name.Type()
|
||||||
|
|
||||||
|
case pkgbits.TypeTypeParam:
|
||||||
|
return r.dict.tparams[r.Len()]
|
||||||
|
|
||||||
|
case pkgbits.TypeArray:
|
||||||
|
len := int64(r.Uint64())
|
||||||
|
return types.NewArray(r.typ(), len)
|
||||||
|
case pkgbits.TypeChan:
|
||||||
|
dir := types.ChanDir(r.Len())
|
||||||
|
return types.NewChan(dir, r.typ())
|
||||||
|
case pkgbits.TypeMap:
|
||||||
|
return types.NewMap(r.typ(), r.typ())
|
||||||
|
case pkgbits.TypePointer:
|
||||||
|
return types.NewPointer(r.typ())
|
||||||
|
case pkgbits.TypeSignature:
|
||||||
|
return r.signature(nil, nil, nil)
|
||||||
|
case pkgbits.TypeSlice:
|
||||||
|
return types.NewSlice(r.typ())
|
||||||
|
case pkgbits.TypeStruct:
|
||||||
|
return r.structType()
|
||||||
|
case pkgbits.TypeInterface:
|
||||||
|
return r.interfaceType()
|
||||||
|
case pkgbits.TypeUnion:
|
||||||
|
return r.unionType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) structType() *types.Struct {
|
||||||
|
fields := make([]*types.Var, r.Len())
|
||||||
|
var tags []string
|
||||||
|
for i := range fields {
|
||||||
|
pos := r.pos()
|
||||||
|
pkg, name := r.selector()
|
||||||
|
ftyp := r.typ()
|
||||||
|
tag := r.String()
|
||||||
|
embedded := r.Bool()
|
||||||
|
|
||||||
|
fields[i] = types.NewField(pos, pkg, name, ftyp, embedded)
|
||||||
|
if tag != "" {
|
||||||
|
for len(tags) < i {
|
||||||
|
tags = append(tags, "")
|
||||||
|
}
|
||||||
|
tags = append(tags, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return types.NewStruct(fields, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) unionType() *types.Union {
|
||||||
|
terms := make([]*types.Term, r.Len())
|
||||||
|
for i := range terms {
|
||||||
|
terms[i] = types.NewTerm(r.Bool(), r.typ())
|
||||||
|
}
|
||||||
|
return types.NewUnion(terms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) interfaceType() *types.Interface {
|
||||||
|
methods := make([]*types.Func, r.Len())
|
||||||
|
embeddeds := make([]types.Type, r.Len())
|
||||||
|
implicit := len(methods) == 0 && len(embeddeds) == 1 && r.Bool()
|
||||||
|
|
||||||
|
for i := range methods {
|
||||||
|
pos := r.pos()
|
||||||
|
pkg, name := r.selector()
|
||||||
|
mtyp := r.signature(nil, nil, nil)
|
||||||
|
methods[i] = types.NewFunc(pos, pkg, name, mtyp)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range embeddeds {
|
||||||
|
embeddeds[i] = r.typ()
|
||||||
|
}
|
||||||
|
|
||||||
|
iface := types.NewInterfaceType(methods, embeddeds)
|
||||||
|
if implicit {
|
||||||
|
iface.MarkImplicit()
|
||||||
|
}
|
||||||
|
return iface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) signature(recv *types.Var, rtparams, tparams []*types.TypeParam) *types.Signature {
|
||||||
|
r.Sync(pkgbits.SyncSignature)
|
||||||
|
|
||||||
|
params := r.params()
|
||||||
|
results := r.params()
|
||||||
|
variadic := r.Bool()
|
||||||
|
|
||||||
|
return types.NewSignatureType(recv, rtparams, tparams, params, results, variadic)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) params() *types.Tuple {
|
||||||
|
r.Sync(pkgbits.SyncParams)
|
||||||
|
|
||||||
|
params := make([]*types.Var, r.Len())
|
||||||
|
for i := range params {
|
||||||
|
params[i] = r.param()
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewTuple(params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) param() *types.Var {
|
||||||
|
r.Sync(pkgbits.SyncParam)
|
||||||
|
|
||||||
|
pos := r.pos()
|
||||||
|
pkg, name := r.localIdent()
|
||||||
|
typ := r.typ()
|
||||||
|
|
||||||
|
return types.NewParam(pos, pkg, name, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@@ Objects
|
||||||
|
|
||||||
|
func (r *reader) obj() (types.Object, []types.Type) {
|
||||||
|
r.Sync(pkgbits.SyncObject)
|
||||||
|
|
||||||
|
assert(!r.Bool())
|
||||||
|
|
||||||
|
pkg, name := r.p.objIdx(r.Reloc(pkgbits.RelocObj))
|
||||||
|
obj := pkgScope(pkg).Lookup(name)
|
||||||
|
|
||||||
|
targs := make([]types.Type, r.Len())
|
||||||
|
for i := range targs {
|
||||||
|
targs[i] = r.typ()
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj, targs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
||||||
|
rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1)
|
||||||
|
|
||||||
|
objPkg, objName := rname.qualifiedIdent()
|
||||||
|
assert(objName != "")
|
||||||
|
|
||||||
|
tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))
|
||||||
|
|
||||||
|
if tag == pkgbits.ObjStub {
|
||||||
|
assert(objPkg == nil || objPkg == types.Unsafe)
|
||||||
|
return objPkg, objName
|
||||||
|
}
|
||||||
|
|
||||||
|
if objPkg.Scope().Lookup(objName) == nil {
|
||||||
|
dict := pr.objDictIdx(idx)
|
||||||
|
|
||||||
|
r := pr.newReader(pkgbits.RelocObj, idx, pkgbits.SyncObject1)
|
||||||
|
r.dict = dict
|
||||||
|
|
||||||
|
declare := func(obj types.Object) {
|
||||||
|
objPkg.Scope().Insert(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tag {
|
||||||
|
default:
|
||||||
|
panic("weird")
|
||||||
|
|
||||||
|
case pkgbits.ObjAlias:
|
||||||
|
pos := r.pos()
|
||||||
|
typ := r.typ()
|
||||||
|
declare(types.NewTypeName(pos, objPkg, objName, typ))
|
||||||
|
|
||||||
|
case pkgbits.ObjConst:
|
||||||
|
pos := r.pos()
|
||||||
|
typ := r.typ()
|
||||||
|
val := r.Value()
|
||||||
|
declare(types.NewConst(pos, objPkg, objName, typ, val))
|
||||||
|
|
||||||
|
case pkgbits.ObjFunc:
|
||||||
|
pos := r.pos()
|
||||||
|
tparams := r.typeParamNames()
|
||||||
|
sig := r.signature(nil, nil, tparams)
|
||||||
|
declare(types.NewFunc(pos, objPkg, objName, sig))
|
||||||
|
|
||||||
|
case pkgbits.ObjType:
|
||||||
|
pos := r.pos()
|
||||||
|
|
||||||
|
obj := types.NewTypeName(pos, objPkg, objName, nil)
|
||||||
|
named := types.NewNamed(obj, nil, nil)
|
||||||
|
declare(obj)
|
||||||
|
|
||||||
|
named.SetTypeParams(r.typeParamNames())
|
||||||
|
|
||||||
|
// TODO(mdempsky): Rewrite receiver types to underlying is an
|
||||||
|
// Interface? The go/types importer does this (I think because
|
||||||
|
// unit tests expected that), but cmd/compile doesn't care
|
||||||
|
// about it, so maybe we can avoid worrying about that here.
|
||||||
|
rhs := r.typ()
|
||||||
|
r.p.later(func() {
|
||||||
|
underlying := rhs.Underlying()
|
||||||
|
named.SetUnderlying(underlying)
|
||||||
|
})
|
||||||
|
|
||||||
|
for i, n := 0, r.Len(); i < n; i++ {
|
||||||
|
named.AddMethod(r.method())
|
||||||
|
}
|
||||||
|
|
||||||
|
case pkgbits.ObjVar:
|
||||||
|
pos := r.pos()
|
||||||
|
typ := r.typ()
|
||||||
|
declare(types.NewVar(pos, objPkg, objName, typ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return objPkg, objName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
|
||||||
|
r := pr.newReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1)
|
||||||
|
|
||||||
|
var dict readerDict
|
||||||
|
|
||||||
|
if implicits := r.Len(); implicits != 0 {
|
||||||
|
errorf("unexpected object with %v implicit type parameter(s)", implicits)
|
||||||
|
}
|
||||||
|
|
||||||
|
dict.bounds = make([]typeInfo, r.Len())
|
||||||
|
for i := range dict.bounds {
|
||||||
|
dict.bounds[i] = r.typInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
dict.derived = make([]derivedInfo, r.Len())
|
||||||
|
dict.derivedTypes = make([]types.Type, len(dict.derived))
|
||||||
|
for i := range dict.derived {
|
||||||
|
dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function references follow, but reader doesn't need those
|
||||||
|
|
||||||
|
return &dict
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) typeParamNames() []*types.TypeParam {
|
||||||
|
r.Sync(pkgbits.SyncTypeParamNames)
|
||||||
|
|
||||||
|
// Note: This code assumes it only processes objects without
|
||||||
|
// implement type parameters. This is currently fine, because
|
||||||
|
// reader is only used to read in exported declarations, which are
|
||||||
|
// always package scoped.
|
||||||
|
|
||||||
|
if len(r.dict.bounds) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Careful: Type parameter lists may have cycles. To allow for this,
|
||||||
|
// we construct the type parameter list in two passes: first we
|
||||||
|
// create all the TypeNames and TypeParams, then we construct and
|
||||||
|
// set the bound type.
|
||||||
|
|
||||||
|
r.dict.tparams = make([]*types.TypeParam, len(r.dict.bounds))
|
||||||
|
for i := range r.dict.bounds {
|
||||||
|
pos := r.pos()
|
||||||
|
pkg, name := r.localIdent()
|
||||||
|
|
||||||
|
tname := types.NewTypeName(pos, pkg, name, nil)
|
||||||
|
r.dict.tparams[i] = types.NewTypeParam(tname, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
typs := make([]types.Type, len(r.dict.bounds))
|
||||||
|
for i, bound := range r.dict.bounds {
|
||||||
|
typs[i] = r.p.typIdx(bound, r.dict)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(mdempsky): This is subtle, elaborate further.
|
||||||
|
//
|
||||||
|
// We have to save tparams outside of the closure, because
|
||||||
|
// typeParamNames() can be called multiple times with the same
|
||||||
|
// dictionary instance.
|
||||||
|
//
|
||||||
|
// Also, this needs to happen later to make sure SetUnderlying has
|
||||||
|
// been called.
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): Is it safe to have a single "later" slice or do
|
||||||
|
// we need to have multiple passes? See comments on CL 386002 and
|
||||||
|
// go.dev/issue/52104.
|
||||||
|
tparams := r.dict.tparams
|
||||||
|
r.p.later(func() {
|
||||||
|
for i, typ := range typs {
|
||||||
|
tparams[i].SetConstraint(typ)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return r.dict.tparams
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) method() *types.Func {
|
||||||
|
r.Sync(pkgbits.SyncMethod)
|
||||||
|
pos := r.pos()
|
||||||
|
pkg, name := r.selector()
|
||||||
|
|
||||||
|
rparams := r.typeParamNames()
|
||||||
|
sig := r.signature(r.param(), rparams, nil)
|
||||||
|
|
||||||
|
_ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.
|
||||||
|
return types.NewFunc(pos, pkg, name, sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) qualifiedIdent() (*types.Package, string) { return r.ident(pkgbits.SyncSym) }
|
||||||
|
func (r *reader) localIdent() (*types.Package, string) { return r.ident(pkgbits.SyncLocalIdent) }
|
||||||
|
func (r *reader) selector() (*types.Package, string) { return r.ident(pkgbits.SyncSelector) }
|
||||||
|
|
||||||
|
func (r *reader) ident(marker pkgbits.SyncMarker) (*types.Package, string) {
|
||||||
|
r.Sync(marker)
|
||||||
|
return r.pkg(), r.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// pkgScope returns pkg.Scope().
|
||||||
|
// If pkg is nil, it returns types.Universe instead.
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): Remove after x/tools can depend on Go 1.19.
|
||||||
|
func pkgScope(pkg *types.Package) *types.Scope {
|
||||||
|
if pkg != nil {
|
||||||
|
return pkg.Scope()
|
||||||
|
}
|
||||||
|
return types.Universe
|
||||||
|
}
|
49
vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
generated
vendored
Normal file
49
vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package packagesdriver fetches type sizes for go/packages and go/analysis.
|
||||||
|
package packagesdriver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"go/types"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/gocommand"
|
||||||
|
)
|
||||||
|
|
||||||
|
var debug = false
|
||||||
|
|
||||||
|
func GetSizesGolist(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (types.Sizes, error) {
|
||||||
|
inv.Verb = "list"
|
||||||
|
inv.Args = []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"}
|
||||||
|
stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv)
|
||||||
|
var goarch, compiler string
|
||||||
|
if rawErr != nil {
|
||||||
|
if rawErrMsg := rawErr.Error(); strings.Contains(rawErrMsg, "cannot find main module") || strings.Contains(rawErrMsg, "go.mod file not found") {
|
||||||
|
// User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc.
|
||||||
|
// TODO(matloob): Is this a problem in practice?
|
||||||
|
inv.Verb = "env"
|
||||||
|
inv.Args = []string{"GOARCH"}
|
||||||
|
envout, enverr := gocmdRunner.Run(ctx, inv)
|
||||||
|
if enverr != nil {
|
||||||
|
return nil, enverr
|
||||||
|
}
|
||||||
|
goarch = strings.TrimSpace(envout.String())
|
||||||
|
compiler = "gc"
|
||||||
|
} else {
|
||||||
|
return nil, friendlyErr
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fields := strings.Fields(stdout.String())
|
||||||
|
if len(fields) < 2 {
|
||||||
|
return nil, fmt.Errorf("could not parse GOARCH and Go compiler in format \"<GOARCH> <compiler>\":\nstdout: <<%s>>\nstderr: <<%s>>",
|
||||||
|
stdout.String(), stderr.String())
|
||||||
|
}
|
||||||
|
goarch = fields[0]
|
||||||
|
compiler = fields[1]
|
||||||
|
}
|
||||||
|
return types.SizesFor(compiler, goarch), nil
|
||||||
|
}
|
77
vendor/golang.org/x/tools/go/internal/pkgbits/codes.go
generated
vendored
Normal file
77
vendor/golang.org/x/tools/go/internal/pkgbits/codes.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pkgbits
|
||||||
|
|
||||||
|
// A Code is an enum value that can be encoded into bitstreams.
|
||||||
|
//
|
||||||
|
// Code types are preferable for enum types, because they allow
|
||||||
|
// Decoder to detect desyncs.
|
||||||
|
type Code interface {
|
||||||
|
// Marker returns the SyncMarker for the Code's dynamic type.
|
||||||
|
Marker() SyncMarker
|
||||||
|
|
||||||
|
// Value returns the Code's ordinal value.
|
||||||
|
Value() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// A CodeVal distinguishes among go/constant.Value encodings.
|
||||||
|
type CodeVal int
|
||||||
|
|
||||||
|
func (c CodeVal) Marker() SyncMarker { return SyncVal }
|
||||||
|
func (c CodeVal) Value() int { return int(c) }
|
||||||
|
|
||||||
|
// Note: These values are public and cannot be changed without
|
||||||
|
// updating the go/types importers.
|
||||||
|
|
||||||
|
const (
|
||||||
|
ValBool CodeVal = iota
|
||||||
|
ValString
|
||||||
|
ValInt64
|
||||||
|
ValBigInt
|
||||||
|
ValBigRat
|
||||||
|
ValBigFloat
|
||||||
|
)
|
||||||
|
|
||||||
|
// A CodeType distinguishes among go/types.Type encodings.
|
||||||
|
type CodeType int
|
||||||
|
|
||||||
|
func (c CodeType) Marker() SyncMarker { return SyncType }
|
||||||
|
func (c CodeType) Value() int { return int(c) }
|
||||||
|
|
||||||
|
// Note: These values are public and cannot be changed without
|
||||||
|
// updating the go/types importers.
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeBasic CodeType = iota
|
||||||
|
TypeNamed
|
||||||
|
TypePointer
|
||||||
|
TypeSlice
|
||||||
|
TypeArray
|
||||||
|
TypeChan
|
||||||
|
TypeMap
|
||||||
|
TypeSignature
|
||||||
|
TypeStruct
|
||||||
|
TypeInterface
|
||||||
|
TypeUnion
|
||||||
|
TypeTypeParam
|
||||||
|
)
|
||||||
|
|
||||||
|
// A CodeObj distinguishes among go/types.Object encodings.
|
||||||
|
type CodeObj int
|
||||||
|
|
||||||
|
func (c CodeObj) Marker() SyncMarker { return SyncCodeObj }
|
||||||
|
func (c CodeObj) Value() int { return int(c) }
|
||||||
|
|
||||||
|
// Note: These values are public and cannot be changed without
|
||||||
|
// updating the go/types importers.
|
||||||
|
|
||||||
|
const (
|
||||||
|
ObjAlias CodeObj = iota
|
||||||
|
ObjConst
|
||||||
|
ObjType
|
||||||
|
ObjFunc
|
||||||
|
ObjVar
|
||||||
|
ObjStub
|
||||||
|
)
|
433
vendor/golang.org/x/tools/go/internal/pkgbits/decoder.go
generated
vendored
Normal file
433
vendor/golang.org/x/tools/go/internal/pkgbits/decoder.go
generated
vendored
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pkgbits
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"go/constant"
|
||||||
|
"go/token"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A PkgDecoder provides methods for decoding a package's Unified IR
|
||||||
|
// export data.
|
||||||
|
type PkgDecoder struct {
|
||||||
|
// version is the file format version.
|
||||||
|
version uint32
|
||||||
|
|
||||||
|
// sync indicates whether the file uses sync markers.
|
||||||
|
sync bool
|
||||||
|
|
||||||
|
// pkgPath is the package path for the package to be decoded.
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): Remove; unneeded since CL 391014.
|
||||||
|
pkgPath string
|
||||||
|
|
||||||
|
// elemData is the full data payload of the encoded package.
|
||||||
|
// Elements are densely and contiguously packed together.
|
||||||
|
//
|
||||||
|
// The last 8 bytes of elemData are the package fingerprint.
|
||||||
|
elemData string
|
||||||
|
|
||||||
|
// elemEnds stores the byte-offset end positions of element
|
||||||
|
// bitstreams within elemData.
|
||||||
|
//
|
||||||
|
// For example, element I's bitstream data starts at elemEnds[I-1]
|
||||||
|
// (or 0, if I==0) and ends at elemEnds[I].
|
||||||
|
//
|
||||||
|
// Note: elemEnds is indexed by absolute indices, not
|
||||||
|
// section-relative indices.
|
||||||
|
elemEnds []uint32
|
||||||
|
|
||||||
|
// elemEndsEnds stores the index-offset end positions of relocation
|
||||||
|
// sections within elemEnds.
|
||||||
|
//
|
||||||
|
// For example, section K's end positions start at elemEndsEnds[K-1]
|
||||||
|
// (or 0, if K==0) and end at elemEndsEnds[K].
|
||||||
|
elemEndsEnds [numRelocs]uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// PkgPath returns the package path for the package
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): Remove; unneeded since CL 391014.
|
||||||
|
func (pr *PkgDecoder) PkgPath() string { return pr.pkgPath }
|
||||||
|
|
||||||
|
// SyncMarkers reports whether pr uses sync markers.
|
||||||
|
func (pr *PkgDecoder) SyncMarkers() bool { return pr.sync }
|
||||||
|
|
||||||
|
// NewPkgDecoder returns a PkgDecoder initialized to read the Unified
|
||||||
|
// IR export data from input. pkgPath is the package path for the
|
||||||
|
// compilation unit that produced the export data.
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): Remove pkgPath parameter; unneeded since CL 391014.
|
||||||
|
func NewPkgDecoder(pkgPath, input string) PkgDecoder {
|
||||||
|
pr := PkgDecoder{
|
||||||
|
pkgPath: pkgPath,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(mdempsky): Implement direct indexing of input string to
|
||||||
|
// avoid copying the position information.
|
||||||
|
|
||||||
|
r := strings.NewReader(input)
|
||||||
|
|
||||||
|
assert(binary.Read(r, binary.LittleEndian, &pr.version) == nil)
|
||||||
|
|
||||||
|
switch pr.version {
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported version: %v", pr.version))
|
||||||
|
case 0:
|
||||||
|
// no flags
|
||||||
|
case 1:
|
||||||
|
var flags uint32
|
||||||
|
assert(binary.Read(r, binary.LittleEndian, &flags) == nil)
|
||||||
|
pr.sync = flags&flagSyncMarkers != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(binary.Read(r, binary.LittleEndian, pr.elemEndsEnds[:]) == nil)
|
||||||
|
|
||||||
|
pr.elemEnds = make([]uint32, pr.elemEndsEnds[len(pr.elemEndsEnds)-1])
|
||||||
|
assert(binary.Read(r, binary.LittleEndian, pr.elemEnds[:]) == nil)
|
||||||
|
|
||||||
|
pos, err := r.Seek(0, os.SEEK_CUR)
|
||||||
|
assert(err == nil)
|
||||||
|
|
||||||
|
pr.elemData = input[pos:]
|
||||||
|
assert(len(pr.elemData)-8 == int(pr.elemEnds[len(pr.elemEnds)-1]))
|
||||||
|
|
||||||
|
return pr
|
||||||
|
}
|
||||||
|
|
||||||
|
// NumElems returns the number of elements in section k.
|
||||||
|
func (pr *PkgDecoder) NumElems(k RelocKind) int {
|
||||||
|
count := int(pr.elemEndsEnds[k])
|
||||||
|
if k > 0 {
|
||||||
|
count -= int(pr.elemEndsEnds[k-1])
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
// TotalElems returns the total number of elements across all sections.
|
||||||
|
func (pr *PkgDecoder) TotalElems() int {
|
||||||
|
return len(pr.elemEnds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fingerprint returns the package fingerprint.
|
||||||
|
func (pr *PkgDecoder) Fingerprint() [8]byte {
|
||||||
|
var fp [8]byte
|
||||||
|
copy(fp[:], pr.elemData[len(pr.elemData)-8:])
|
||||||
|
return fp
|
||||||
|
}
|
||||||
|
|
||||||
|
// AbsIdx returns the absolute index for the given (section, index)
|
||||||
|
// pair.
|
||||||
|
func (pr *PkgDecoder) AbsIdx(k RelocKind, idx Index) int {
|
||||||
|
absIdx := int(idx)
|
||||||
|
if k > 0 {
|
||||||
|
absIdx += int(pr.elemEndsEnds[k-1])
|
||||||
|
}
|
||||||
|
if absIdx >= int(pr.elemEndsEnds[k]) {
|
||||||
|
errorf("%v:%v is out of bounds; %v", k, idx, pr.elemEndsEnds)
|
||||||
|
}
|
||||||
|
return absIdx
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataIdx returns the raw element bitstream for the given (section,
|
||||||
|
// index) pair.
|
||||||
|
func (pr *PkgDecoder) DataIdx(k RelocKind, idx Index) string {
|
||||||
|
absIdx := pr.AbsIdx(k, idx)
|
||||||
|
|
||||||
|
var start uint32
|
||||||
|
if absIdx > 0 {
|
||||||
|
start = pr.elemEnds[absIdx-1]
|
||||||
|
}
|
||||||
|
end := pr.elemEnds[absIdx]
|
||||||
|
|
||||||
|
return pr.elemData[start:end]
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringIdx returns the string value for the given string index.
|
||||||
|
func (pr *PkgDecoder) StringIdx(idx Index) string {
|
||||||
|
return pr.DataIdx(RelocString, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDecoder returns a Decoder for the given (section, index) pair,
|
||||||
|
// and decodes the given SyncMarker from the element bitstream.
|
||||||
|
func (pr *PkgDecoder) NewDecoder(k RelocKind, idx Index, marker SyncMarker) Decoder {
|
||||||
|
r := pr.NewDecoderRaw(k, idx)
|
||||||
|
r.Sync(marker)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDecoderRaw returns a Decoder for the given (section, index) pair.
|
||||||
|
//
|
||||||
|
// Most callers should use NewDecoder instead.
|
||||||
|
func (pr *PkgDecoder) NewDecoderRaw(k RelocKind, idx Index) Decoder {
|
||||||
|
r := Decoder{
|
||||||
|
common: pr,
|
||||||
|
k: k,
|
||||||
|
Idx: idx,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(mdempsky) r.data.Reset(...) after #44505 is resolved.
|
||||||
|
r.Data = *strings.NewReader(pr.DataIdx(k, idx))
|
||||||
|
|
||||||
|
r.Sync(SyncRelocs)
|
||||||
|
r.Relocs = make([]RelocEnt, r.Len())
|
||||||
|
for i := range r.Relocs {
|
||||||
|
r.Sync(SyncReloc)
|
||||||
|
r.Relocs[i] = RelocEnt{RelocKind(r.Len()), Index(r.Len())}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Decoder provides methods for decoding an individual element's
|
||||||
|
// bitstream data.
|
||||||
|
type Decoder struct {
|
||||||
|
common *PkgDecoder
|
||||||
|
|
||||||
|
Relocs []RelocEnt
|
||||||
|
Data strings.Reader
|
||||||
|
|
||||||
|
k RelocKind
|
||||||
|
Idx Index
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Decoder) checkErr(err error) {
|
||||||
|
if err != nil {
|
||||||
|
errorf("unexpected decoding error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Decoder) rawUvarint() uint64 {
|
||||||
|
x, err := binary.ReadUvarint(&r.Data)
|
||||||
|
r.checkErr(err)
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Decoder) rawVarint() int64 {
|
||||||
|
ux := r.rawUvarint()
|
||||||
|
|
||||||
|
// Zig-zag decode.
|
||||||
|
x := int64(ux >> 1)
|
||||||
|
if ux&1 != 0 {
|
||||||
|
x = ^x
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Decoder) rawReloc(k RelocKind, idx int) Index {
|
||||||
|
e := r.Relocs[idx]
|
||||||
|
assert(e.Kind == k)
|
||||||
|
return e.Idx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync decodes a sync marker from the element bitstream and asserts
|
||||||
|
// that it matches the expected marker.
|
||||||
|
//
|
||||||
|
// If r.common.sync is false, then Sync is a no-op.
|
||||||
|
func (r *Decoder) Sync(mWant SyncMarker) {
|
||||||
|
if !r.common.sync {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pos, _ := r.Data.Seek(0, os.SEEK_CUR) // TODO(mdempsky): io.SeekCurrent after #44505 is resolved
|
||||||
|
mHave := SyncMarker(r.rawUvarint())
|
||||||
|
writerPCs := make([]int, r.rawUvarint())
|
||||||
|
for i := range writerPCs {
|
||||||
|
writerPCs[i] = int(r.rawUvarint())
|
||||||
|
}
|
||||||
|
|
||||||
|
if mHave == mWant {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's some tension here between printing:
|
||||||
|
//
|
||||||
|
// (1) full file paths that tools can recognize (e.g., so emacs
|
||||||
|
// hyperlinks the "file:line" text for easy navigation), or
|
||||||
|
//
|
||||||
|
// (2) short file paths that are easier for humans to read (e.g., by
|
||||||
|
// omitting redundant or irrelevant details, so it's easier to
|
||||||
|
// focus on the useful bits that remain).
|
||||||
|
//
|
||||||
|
// The current formatting favors the former, as it seems more
|
||||||
|
// helpful in practice. But perhaps the formatting could be improved
|
||||||
|
// to better address both concerns. For example, use relative file
|
||||||
|
// paths if they would be shorter, or rewrite file paths to contain
|
||||||
|
// "$GOROOT" (like objabi.AbsFile does) if tools can be taught how
|
||||||
|
// to reliably expand that again.
|
||||||
|
|
||||||
|
fmt.Printf("export data desync: package %q, section %v, index %v, offset %v\n", r.common.pkgPath, r.k, r.Idx, pos)
|
||||||
|
|
||||||
|
fmt.Printf("\nfound %v, written at:\n", mHave)
|
||||||
|
if len(writerPCs) == 0 {
|
||||||
|
fmt.Printf("\t[stack trace unavailable; recompile package %q with -d=syncframes]\n", r.common.pkgPath)
|
||||||
|
}
|
||||||
|
for _, pc := range writerPCs {
|
||||||
|
fmt.Printf("\t%s\n", r.common.StringIdx(r.rawReloc(RelocString, pc)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\nexpected %v, reading at:\n", mWant)
|
||||||
|
var readerPCs [32]uintptr // TODO(mdempsky): Dynamically size?
|
||||||
|
n := runtime.Callers(2, readerPCs[:])
|
||||||
|
for _, pc := range fmtFrames(readerPCs[:n]...) {
|
||||||
|
fmt.Printf("\t%s\n", pc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We already printed a stack trace for the reader, so now we can
|
||||||
|
// simply exit. Printing a second one with panic or base.Fatalf
|
||||||
|
// would just be noise.
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool decodes and returns a bool value from the element bitstream.
|
||||||
|
func (r *Decoder) Bool() bool {
|
||||||
|
r.Sync(SyncBool)
|
||||||
|
x, err := r.Data.ReadByte()
|
||||||
|
r.checkErr(err)
|
||||||
|
assert(x < 2)
|
||||||
|
return x != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 decodes and returns an int64 value from the element bitstream.
|
||||||
|
func (r *Decoder) Int64() int64 {
|
||||||
|
r.Sync(SyncInt64)
|
||||||
|
return r.rawVarint()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 decodes and returns a uint64 value from the element bitstream.
|
||||||
|
func (r *Decoder) Uint64() uint64 {
|
||||||
|
r.Sync(SyncUint64)
|
||||||
|
return r.rawUvarint()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len decodes and returns a non-negative int value from the element bitstream.
|
||||||
|
func (r *Decoder) Len() int { x := r.Uint64(); v := int(x); assert(uint64(v) == x); return v }
|
||||||
|
|
||||||
|
// Int decodes and returns an int value from the element bitstream.
|
||||||
|
func (r *Decoder) Int() int { x := r.Int64(); v := int(x); assert(int64(v) == x); return v }
|
||||||
|
|
||||||
|
// Uint decodes and returns a uint value from the element bitstream.
|
||||||
|
func (r *Decoder) Uint() uint { x := r.Uint64(); v := uint(x); assert(uint64(v) == x); return v }
|
||||||
|
|
||||||
|
// Code decodes a Code value from the element bitstream and returns
|
||||||
|
// its ordinal value. It's the caller's responsibility to convert the
|
||||||
|
// result to an appropriate Code type.
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): Ideally this method would have signature "Code[T
|
||||||
|
// Code] T" instead, but we don't allow generic methods and the
|
||||||
|
// compiler can't depend on generics yet anyway.
|
||||||
|
func (r *Decoder) Code(mark SyncMarker) int {
|
||||||
|
r.Sync(mark)
|
||||||
|
return r.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reloc decodes a relocation of expected section k from the element
|
||||||
|
// bitstream and returns an index to the referenced element.
|
||||||
|
func (r *Decoder) Reloc(k RelocKind) Index {
|
||||||
|
r.Sync(SyncUseReloc)
|
||||||
|
return r.rawReloc(k, r.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
// String decodes and returns a string value from the element
|
||||||
|
// bitstream.
|
||||||
|
func (r *Decoder) String() string {
|
||||||
|
r.Sync(SyncString)
|
||||||
|
return r.common.StringIdx(r.Reloc(RelocString))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strings decodes and returns a variable-length slice of strings from
|
||||||
|
// the element bitstream.
|
||||||
|
func (r *Decoder) Strings() []string {
|
||||||
|
res := make([]string, r.Len())
|
||||||
|
for i := range res {
|
||||||
|
res[i] = r.String()
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value decodes and returns a constant.Value from the element
|
||||||
|
// bitstream.
|
||||||
|
func (r *Decoder) Value() constant.Value {
|
||||||
|
r.Sync(SyncValue)
|
||||||
|
isComplex := r.Bool()
|
||||||
|
val := r.scalar()
|
||||||
|
if isComplex {
|
||||||
|
val = constant.BinaryOp(val, token.ADD, constant.MakeImag(r.scalar()))
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Decoder) scalar() constant.Value {
|
||||||
|
switch tag := CodeVal(r.Code(SyncVal)); tag {
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unexpected scalar tag: %v", tag))
|
||||||
|
|
||||||
|
case ValBool:
|
||||||
|
return constant.MakeBool(r.Bool())
|
||||||
|
case ValString:
|
||||||
|
return constant.MakeString(r.String())
|
||||||
|
case ValInt64:
|
||||||
|
return constant.MakeInt64(r.Int64())
|
||||||
|
case ValBigInt:
|
||||||
|
return constant.Make(r.bigInt())
|
||||||
|
case ValBigRat:
|
||||||
|
num := r.bigInt()
|
||||||
|
denom := r.bigInt()
|
||||||
|
return constant.Make(new(big.Rat).SetFrac(num, denom))
|
||||||
|
case ValBigFloat:
|
||||||
|
return constant.Make(r.bigFloat())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Decoder) bigInt() *big.Int {
|
||||||
|
v := new(big.Int).SetBytes([]byte(r.String()))
|
||||||
|
if r.Bool() {
|
||||||
|
v.Neg(v)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Decoder) bigFloat() *big.Float {
|
||||||
|
v := new(big.Float).SetPrec(512)
|
||||||
|
assert(v.UnmarshalText([]byte(r.String())) == nil)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@@ Helpers
|
||||||
|
|
||||||
|
// TODO(mdempsky): These should probably be removed. I think they're a
|
||||||
|
// smell that the export data format is not yet quite right.
|
||||||
|
|
||||||
|
// PeekPkgPath returns the package path for the specified package
|
||||||
|
// index.
|
||||||
|
func (pr *PkgDecoder) PeekPkgPath(idx Index) string {
|
||||||
|
r := pr.NewDecoder(RelocPkg, idx, SyncPkgDef)
|
||||||
|
path := r.String()
|
||||||
|
if path == "" {
|
||||||
|
path = pr.pkgPath
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeekObj returns the package path, object name, and CodeObj for the
|
||||||
|
// specified object index.
|
||||||
|
func (pr *PkgDecoder) PeekObj(idx Index) (string, string, CodeObj) {
|
||||||
|
r := pr.NewDecoder(RelocName, idx, SyncObject1)
|
||||||
|
r.Sync(SyncSym)
|
||||||
|
r.Sync(SyncPkg)
|
||||||
|
path := pr.PeekPkgPath(r.Reloc(RelocPkg))
|
||||||
|
name := r.String()
|
||||||
|
assert(name != "")
|
||||||
|
|
||||||
|
tag := CodeObj(r.Code(SyncCodeObj))
|
||||||
|
|
||||||
|
return path, name, tag
|
||||||
|
}
|
32
vendor/golang.org/x/tools/go/internal/pkgbits/doc.go
generated
vendored
Normal file
32
vendor/golang.org/x/tools/go/internal/pkgbits/doc.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package pkgbits implements low-level coding abstractions for
|
||||||
|
// Unified IR's export data format.
|
||||||
|
//
|
||||||
|
// At a low-level, a package is a collection of bitstream elements.
|
||||||
|
// Each element has a "kind" and a dense, non-negative index.
|
||||||
|
// Elements can be randomly accessed given their kind and index.
|
||||||
|
//
|
||||||
|
// Individual elements are sequences of variable-length values (e.g.,
|
||||||
|
// integers, booleans, strings, go/constant values, cross-references
|
||||||
|
// to other elements). Package pkgbits provides APIs for encoding and
|
||||||
|
// decoding these low-level values, but the details of mapping
|
||||||
|
// higher-level Go constructs into elements is left to higher-level
|
||||||
|
// abstractions.
|
||||||
|
//
|
||||||
|
// Elements may cross-reference each other with "relocations." For
|
||||||
|
// example, an element representing a pointer type has a relocation
|
||||||
|
// referring to the element type.
|
||||||
|
//
|
||||||
|
// Go constructs may be composed as a constellation of multiple
|
||||||
|
// elements. For example, a declared function may have one element to
|
||||||
|
// describe the object (e.g., its name, type, position), and a
|
||||||
|
// separate element to describe its function body. This allows readers
|
||||||
|
// some flexibility in efficiently seeking or re-reading data (e.g.,
|
||||||
|
// inlining requires re-reading the function body for each inlined
|
||||||
|
// call, without needing to re-read the object-level details).
|
||||||
|
//
|
||||||
|
// This is a copy of internal/pkgbits in the Go implementation.
|
||||||
|
package pkgbits
|
379
vendor/golang.org/x/tools/go/internal/pkgbits/encoder.go
generated
vendored
Normal file
379
vendor/golang.org/x/tools/go/internal/pkgbits/encoder.go
generated
vendored
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pkgbits
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/binary"
|
||||||
|
"go/constant"
|
||||||
|
"io"
|
||||||
|
"math/big"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// currentVersion is the current version number.
|
||||||
|
//
|
||||||
|
// - v0: initial prototype
|
||||||
|
//
|
||||||
|
// - v1: adds the flags uint32 word
|
||||||
|
const currentVersion uint32 = 1
|
||||||
|
|
||||||
|
// A PkgEncoder provides methods for encoding a package's Unified IR
|
||||||
|
// export data.
|
||||||
|
type PkgEncoder struct {
|
||||||
|
// elems holds the bitstream for previously encoded elements.
|
||||||
|
elems [numRelocs][]string
|
||||||
|
|
||||||
|
// stringsIdx maps previously encoded strings to their index within
|
||||||
|
// the RelocString section, to allow deduplication. That is,
|
||||||
|
// elems[RelocString][stringsIdx[s]] == s (if present).
|
||||||
|
stringsIdx map[string]Index
|
||||||
|
|
||||||
|
// syncFrames is the number of frames to write at each sync
|
||||||
|
// marker. A negative value means sync markers are omitted.
|
||||||
|
syncFrames int
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyncMarkers reports whether pw uses sync markers.
|
||||||
|
func (pw *PkgEncoder) SyncMarkers() bool { return pw.syncFrames >= 0 }
|
||||||
|
|
||||||
|
// NewPkgEncoder returns an initialized PkgEncoder.
|
||||||
|
//
|
||||||
|
// syncFrames is the number of caller frames that should be serialized
|
||||||
|
// at Sync points. Serializing additional frames results in larger
|
||||||
|
// export data files, but can help diagnosing desync errors in
|
||||||
|
// higher-level Unified IR reader/writer code. If syncFrames is
|
||||||
|
// negative, then sync markers are omitted entirely.
|
||||||
|
func NewPkgEncoder(syncFrames int) PkgEncoder {
|
||||||
|
return PkgEncoder{
|
||||||
|
stringsIdx: make(map[string]Index),
|
||||||
|
syncFrames: syncFrames,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DumpTo writes the package's encoded data to out0 and returns the
|
||||||
|
// package fingerprint.
|
||||||
|
func (pw *PkgEncoder) DumpTo(out0 io.Writer) (fingerprint [8]byte) {
|
||||||
|
h := md5.New()
|
||||||
|
out := io.MultiWriter(out0, h)
|
||||||
|
|
||||||
|
writeUint32 := func(x uint32) {
|
||||||
|
assert(binary.Write(out, binary.LittleEndian, x) == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
writeUint32(currentVersion)
|
||||||
|
|
||||||
|
var flags uint32
|
||||||
|
if pw.SyncMarkers() {
|
||||||
|
flags |= flagSyncMarkers
|
||||||
|
}
|
||||||
|
writeUint32(flags)
|
||||||
|
|
||||||
|
// Write elemEndsEnds.
|
||||||
|
var sum uint32
|
||||||
|
for _, elems := range &pw.elems {
|
||||||
|
sum += uint32(len(elems))
|
||||||
|
writeUint32(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write elemEnds.
|
||||||
|
sum = 0
|
||||||
|
for _, elems := range &pw.elems {
|
||||||
|
for _, elem := range elems {
|
||||||
|
sum += uint32(len(elem))
|
||||||
|
writeUint32(sum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write elemData.
|
||||||
|
for _, elems := range &pw.elems {
|
||||||
|
for _, elem := range elems {
|
||||||
|
_, err := io.WriteString(out, elem)
|
||||||
|
assert(err == nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write fingerprint.
|
||||||
|
copy(fingerprint[:], h.Sum(nil))
|
||||||
|
_, err := out0.Write(fingerprint[:])
|
||||||
|
assert(err == nil)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringIdx adds a string value to the strings section, if not
|
||||||
|
// already present, and returns its index.
|
||||||
|
func (pw *PkgEncoder) StringIdx(s string) Index {
|
||||||
|
if idx, ok := pw.stringsIdx[s]; ok {
|
||||||
|
assert(pw.elems[RelocString][idx] == s)
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := Index(len(pw.elems[RelocString]))
|
||||||
|
pw.elems[RelocString] = append(pw.elems[RelocString], s)
|
||||||
|
pw.stringsIdx[s] = idx
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncoder returns an Encoder for a new element within the given
|
||||||
|
// section, and encodes the given SyncMarker as the start of the
|
||||||
|
// element bitstream.
|
||||||
|
func (pw *PkgEncoder) NewEncoder(k RelocKind, marker SyncMarker) Encoder {
|
||||||
|
e := pw.NewEncoderRaw(k)
|
||||||
|
e.Sync(marker)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncoderRaw returns an Encoder for a new element within the given
|
||||||
|
// section.
|
||||||
|
//
|
||||||
|
// Most callers should use NewEncoder instead.
|
||||||
|
func (pw *PkgEncoder) NewEncoderRaw(k RelocKind) Encoder {
|
||||||
|
idx := Index(len(pw.elems[k]))
|
||||||
|
pw.elems[k] = append(pw.elems[k], "") // placeholder
|
||||||
|
|
||||||
|
return Encoder{
|
||||||
|
p: pw,
|
||||||
|
k: k,
|
||||||
|
Idx: idx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// An Encoder provides methods for encoding an individual element's
|
||||||
|
// bitstream data.
|
||||||
|
type Encoder struct {
|
||||||
|
p *PkgEncoder
|
||||||
|
|
||||||
|
Relocs []RelocEnt
|
||||||
|
Data bytes.Buffer // accumulated element bitstream data
|
||||||
|
|
||||||
|
encodingRelocHeader bool
|
||||||
|
|
||||||
|
k RelocKind
|
||||||
|
Idx Index // index within relocation section
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush finalizes the element's bitstream and returns its Index.
|
||||||
|
func (w *Encoder) Flush() Index {
|
||||||
|
var sb bytes.Buffer // TODO(mdempsky): strings.Builder after #44505 is resolved
|
||||||
|
|
||||||
|
// Backup the data so we write the relocations at the front.
|
||||||
|
var tmp bytes.Buffer
|
||||||
|
io.Copy(&tmp, &w.Data)
|
||||||
|
|
||||||
|
// TODO(mdempsky): Consider writing these out separately so they're
|
||||||
|
// easier to strip, along with function bodies, so that we can prune
|
||||||
|
// down to just the data that's relevant to go/types.
|
||||||
|
if w.encodingRelocHeader {
|
||||||
|
panic("encodingRelocHeader already true; recursive flush?")
|
||||||
|
}
|
||||||
|
w.encodingRelocHeader = true
|
||||||
|
w.Sync(SyncRelocs)
|
||||||
|
w.Len(len(w.Relocs))
|
||||||
|
for _, rEnt := range w.Relocs {
|
||||||
|
w.Sync(SyncReloc)
|
||||||
|
w.Len(int(rEnt.Kind))
|
||||||
|
w.Len(int(rEnt.Idx))
|
||||||
|
}
|
||||||
|
|
||||||
|
io.Copy(&sb, &w.Data)
|
||||||
|
io.Copy(&sb, &tmp)
|
||||||
|
w.p.elems[w.k][w.Idx] = sb.String()
|
||||||
|
|
||||||
|
return w.Idx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Encoder) checkErr(err error) {
|
||||||
|
if err != nil {
|
||||||
|
errorf("unexpected encoding error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Encoder) rawUvarint(x uint64) {
|
||||||
|
var buf [binary.MaxVarintLen64]byte
|
||||||
|
n := binary.PutUvarint(buf[:], x)
|
||||||
|
_, err := w.Data.Write(buf[:n])
|
||||||
|
w.checkErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Encoder) rawVarint(x int64) {
|
||||||
|
// Zig-zag encode.
|
||||||
|
ux := uint64(x) << 1
|
||||||
|
if x < 0 {
|
||||||
|
ux = ^ux
|
||||||
|
}
|
||||||
|
|
||||||
|
w.rawUvarint(ux)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Encoder) rawReloc(r RelocKind, idx Index) int {
|
||||||
|
// TODO(mdempsky): Use map for lookup; this takes quadratic time.
|
||||||
|
for i, rEnt := range w.Relocs {
|
||||||
|
if rEnt.Kind == r && rEnt.Idx == idx {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i := len(w.Relocs)
|
||||||
|
w.Relocs = append(w.Relocs, RelocEnt{r, idx})
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Encoder) Sync(m SyncMarker) {
|
||||||
|
if !w.p.SyncMarkers() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing out stack frame string references requires working
|
||||||
|
// relocations, but writing out the relocations themselves involves
|
||||||
|
// sync markers. To prevent infinite recursion, we simply trim the
|
||||||
|
// stack frame for sync markers within the relocation header.
|
||||||
|
var frames []string
|
||||||
|
if !w.encodingRelocHeader && w.p.syncFrames > 0 {
|
||||||
|
pcs := make([]uintptr, w.p.syncFrames)
|
||||||
|
n := runtime.Callers(2, pcs)
|
||||||
|
frames = fmtFrames(pcs[:n]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(mdempsky): Save space by writing out stack frames as a
|
||||||
|
// linked list so we can share common stack frames.
|
||||||
|
w.rawUvarint(uint64(m))
|
||||||
|
w.rawUvarint(uint64(len(frames)))
|
||||||
|
for _, frame := range frames {
|
||||||
|
w.rawUvarint(uint64(w.rawReloc(RelocString, w.p.StringIdx(frame))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool encodes and writes a bool value into the element bitstream,
|
||||||
|
// and then returns the bool value.
|
||||||
|
//
|
||||||
|
// For simple, 2-alternative encodings, the idiomatic way to call Bool
|
||||||
|
// is something like:
|
||||||
|
//
|
||||||
|
// if w.Bool(x != 0) {
|
||||||
|
// // alternative #1
|
||||||
|
// } else {
|
||||||
|
// // alternative #2
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// For multi-alternative encodings, use Code instead.
|
||||||
|
func (w *Encoder) Bool(b bool) bool {
|
||||||
|
w.Sync(SyncBool)
|
||||||
|
var x byte
|
||||||
|
if b {
|
||||||
|
x = 1
|
||||||
|
}
|
||||||
|
err := w.Data.WriteByte(x)
|
||||||
|
w.checkErr(err)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 encodes and writes an int64 value into the element bitstream.
|
||||||
|
func (w *Encoder) Int64(x int64) {
|
||||||
|
w.Sync(SyncInt64)
|
||||||
|
w.rawVarint(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64 encodes and writes a uint64 value into the element bitstream.
|
||||||
|
func (w *Encoder) Uint64(x uint64) {
|
||||||
|
w.Sync(SyncUint64)
|
||||||
|
w.rawUvarint(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len encodes and writes a non-negative int value into the element bitstream.
|
||||||
|
func (w *Encoder) Len(x int) { assert(x >= 0); w.Uint64(uint64(x)) }
|
||||||
|
|
||||||
|
// Int encodes and writes an int value into the element bitstream.
|
||||||
|
func (w *Encoder) Int(x int) { w.Int64(int64(x)) }
|
||||||
|
|
||||||
|
// Len encodes and writes a uint value into the element bitstream.
|
||||||
|
func (w *Encoder) Uint(x uint) { w.Uint64(uint64(x)) }
|
||||||
|
|
||||||
|
// Reloc encodes and writes a relocation for the given (section,
|
||||||
|
// index) pair into the element bitstream.
|
||||||
|
//
|
||||||
|
// Note: Only the index is formally written into the element
|
||||||
|
// bitstream, so bitstream decoders must know from context which
|
||||||
|
// section an encoded relocation refers to.
|
||||||
|
func (w *Encoder) Reloc(r RelocKind, idx Index) {
|
||||||
|
w.Sync(SyncUseReloc)
|
||||||
|
w.Len(w.rawReloc(r, idx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code encodes and writes a Code value into the element bitstream.
|
||||||
|
func (w *Encoder) Code(c Code) {
|
||||||
|
w.Sync(c.Marker())
|
||||||
|
w.Len(c.Value())
|
||||||
|
}
|
||||||
|
|
||||||
|
// String encodes and writes a string value into the element
|
||||||
|
// bitstream.
|
||||||
|
//
|
||||||
|
// Internally, strings are deduplicated by adding them to the strings
|
||||||
|
// section (if not already present), and then writing a relocation
|
||||||
|
// into the element bitstream.
|
||||||
|
func (w *Encoder) String(s string) {
|
||||||
|
w.Sync(SyncString)
|
||||||
|
w.Reloc(RelocString, w.p.StringIdx(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strings encodes and writes a variable-length slice of strings into
|
||||||
|
// the element bitstream.
|
||||||
|
func (w *Encoder) Strings(ss []string) {
|
||||||
|
w.Len(len(ss))
|
||||||
|
for _, s := range ss {
|
||||||
|
w.String(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value encodes and writes a constant.Value into the element
|
||||||
|
// bitstream.
|
||||||
|
func (w *Encoder) Value(val constant.Value) {
|
||||||
|
w.Sync(SyncValue)
|
||||||
|
if w.Bool(val.Kind() == constant.Complex) {
|
||||||
|
w.scalar(constant.Real(val))
|
||||||
|
w.scalar(constant.Imag(val))
|
||||||
|
} else {
|
||||||
|
w.scalar(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Encoder) scalar(val constant.Value) {
|
||||||
|
switch v := constant.Val(val).(type) {
|
||||||
|
default:
|
||||||
|
errorf("unhandled %v (%v)", val, val.Kind())
|
||||||
|
case bool:
|
||||||
|
w.Code(ValBool)
|
||||||
|
w.Bool(v)
|
||||||
|
case string:
|
||||||
|
w.Code(ValString)
|
||||||
|
w.String(v)
|
||||||
|
case int64:
|
||||||
|
w.Code(ValInt64)
|
||||||
|
w.Int64(v)
|
||||||
|
case *big.Int:
|
||||||
|
w.Code(ValBigInt)
|
||||||
|
w.bigInt(v)
|
||||||
|
case *big.Rat:
|
||||||
|
w.Code(ValBigRat)
|
||||||
|
w.bigInt(v.Num())
|
||||||
|
w.bigInt(v.Denom())
|
||||||
|
case *big.Float:
|
||||||
|
w.Code(ValBigFloat)
|
||||||
|
w.bigFloat(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Encoder) bigInt(v *big.Int) {
|
||||||
|
b := v.Bytes()
|
||||||
|
w.String(string(b)) // TODO: More efficient encoding.
|
||||||
|
w.Bool(v.Sign() < 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Encoder) bigFloat(v *big.Float) {
|
||||||
|
b := v.Append(nil, 'p', -1)
|
||||||
|
w.String(string(b)) // TODO: More efficient encoding.
|
||||||
|
}
|
9
vendor/golang.org/x/tools/go/internal/pkgbits/flags.go
generated
vendored
Normal file
9
vendor/golang.org/x/tools/go/internal/pkgbits/flags.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pkgbits
|
||||||
|
|
||||||
|
const (
|
||||||
|
flagSyncMarkers = 1 << iota // file format contains sync markers
|
||||||
|
)
|
21
vendor/golang.org/x/tools/go/internal/pkgbits/frames_go1.go
generated
vendored
Normal file
21
vendor/golang.org/x/tools/go/internal/pkgbits/frames_go1.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !go1.7
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
// TODO(mdempsky): Remove after #44505 is resolved
|
||||||
|
|
||||||
|
package pkgbits
|
||||||
|
|
||||||
|
import "runtime"
|
||||||
|
|
||||||
|
func walkFrames(pcs []uintptr, visit frameVisitor) {
|
||||||
|
for _, pc := range pcs {
|
||||||
|
fn := runtime.FuncForPC(pc)
|
||||||
|
file, line := fn.FileLine(pc)
|
||||||
|
|
||||||
|
visit(file, line, fn.Name(), pc-fn.Entry())
|
||||||
|
}
|
||||||
|
}
|
28
vendor/golang.org/x/tools/go/internal/pkgbits/frames_go17.go
generated
vendored
Normal file
28
vendor/golang.org/x/tools/go/internal/pkgbits/frames_go17.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build go1.7
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package pkgbits
|
||||||
|
|
||||||
|
import "runtime"
|
||||||
|
|
||||||
|
// walkFrames calls visit for each call frame represented by pcs.
|
||||||
|
//
|
||||||
|
// pcs should be a slice of PCs, as returned by runtime.Callers.
|
||||||
|
func walkFrames(pcs []uintptr, visit frameVisitor) {
|
||||||
|
if len(pcs) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
frames := runtime.CallersFrames(pcs)
|
||||||
|
for {
|
||||||
|
frame, more := frames.Next()
|
||||||
|
visit(frame.File, frame.Line, frame.Function, frame.PC-frame.Entry)
|
||||||
|
if !more {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
vendor/golang.org/x/tools/go/internal/pkgbits/reloc.go
generated
vendored
Normal file
42
vendor/golang.org/x/tools/go/internal/pkgbits/reloc.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pkgbits
|
||||||
|
|
||||||
|
// A RelocKind indicates a particular section within a unified IR export.
|
||||||
|
type RelocKind int
|
||||||
|
|
||||||
|
// An Index represents a bitstream element index within a particular
|
||||||
|
// section.
|
||||||
|
type Index int
|
||||||
|
|
||||||
|
// A relocEnt (relocation entry) is an entry in an element's local
|
||||||
|
// reference table.
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): Rename this too.
|
||||||
|
type RelocEnt struct {
|
||||||
|
Kind RelocKind
|
||||||
|
Idx Index
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserved indices within the meta relocation section.
|
||||||
|
const (
|
||||||
|
PublicRootIdx Index = 0
|
||||||
|
PrivateRootIdx Index = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RelocString RelocKind = iota
|
||||||
|
RelocMeta
|
||||||
|
RelocPosBase
|
||||||
|
RelocPkg
|
||||||
|
RelocName
|
||||||
|
RelocType
|
||||||
|
RelocObj
|
||||||
|
RelocObjExt
|
||||||
|
RelocObjDict
|
||||||
|
RelocBody
|
||||||
|
|
||||||
|
numRelocs = iota
|
||||||
|
)
|
17
vendor/golang.org/x/tools/go/internal/pkgbits/support.go
generated
vendored
Normal file
17
vendor/golang.org/x/tools/go/internal/pkgbits/support.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pkgbits
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func assert(b bool) {
|
||||||
|
if !b {
|
||||||
|
panic("assertion failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func errorf(format string, args ...interface{}) {
|
||||||
|
panic(fmt.Errorf(format, args...))
|
||||||
|
}
|
113
vendor/golang.org/x/tools/go/internal/pkgbits/sync.go
generated
vendored
Normal file
113
vendor/golang.org/x/tools/go/internal/pkgbits/sync.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pkgbits
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// fmtFrames formats a backtrace for reporting reader/writer desyncs.
|
||||||
|
func fmtFrames(pcs ...uintptr) []string {
|
||||||
|
res := make([]string, 0, len(pcs))
|
||||||
|
walkFrames(pcs, func(file string, line int, name string, offset uintptr) {
|
||||||
|
// Trim package from function name. It's just redundant noise.
|
||||||
|
name = strings.TrimPrefix(name, "cmd/compile/internal/noder.")
|
||||||
|
|
||||||
|
res = append(res, fmt.Sprintf("%s:%v: %s +0x%v", file, line, name, offset))
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
type frameVisitor func(file string, line int, name string, offset uintptr)
|
||||||
|
|
||||||
|
// SyncMarker is an enum type that represents markers that may be
|
||||||
|
// written to export data to ensure the reader and writer stay
|
||||||
|
// synchronized.
|
||||||
|
type SyncMarker int
|
||||||
|
|
||||||
|
//go:generate stringer -type=SyncMarker -trimprefix=Sync
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ SyncMarker = iota
|
||||||
|
|
||||||
|
// Public markers (known to go/types importers).
|
||||||
|
|
||||||
|
// Low-level coding markers.
|
||||||
|
SyncEOF
|
||||||
|
SyncBool
|
||||||
|
SyncInt64
|
||||||
|
SyncUint64
|
||||||
|
SyncString
|
||||||
|
SyncValue
|
||||||
|
SyncVal
|
||||||
|
SyncRelocs
|
||||||
|
SyncReloc
|
||||||
|
SyncUseReloc
|
||||||
|
|
||||||
|
// Higher-level object and type markers.
|
||||||
|
SyncPublic
|
||||||
|
SyncPos
|
||||||
|
SyncPosBase
|
||||||
|
SyncObject
|
||||||
|
SyncObject1
|
||||||
|
SyncPkg
|
||||||
|
SyncPkgDef
|
||||||
|
SyncMethod
|
||||||
|
SyncType
|
||||||
|
SyncTypeIdx
|
||||||
|
SyncTypeParamNames
|
||||||
|
SyncSignature
|
||||||
|
SyncParams
|
||||||
|
SyncParam
|
||||||
|
SyncCodeObj
|
||||||
|
SyncSym
|
||||||
|
SyncLocalIdent
|
||||||
|
SyncSelector
|
||||||
|
|
||||||
|
// Private markers (only known to cmd/compile).
|
||||||
|
SyncPrivate
|
||||||
|
|
||||||
|
SyncFuncExt
|
||||||
|
SyncVarExt
|
||||||
|
SyncTypeExt
|
||||||
|
SyncPragma
|
||||||
|
|
||||||
|
SyncExprList
|
||||||
|
SyncExprs
|
||||||
|
SyncExpr
|
||||||
|
SyncExprType
|
||||||
|
SyncAssign
|
||||||
|
SyncOp
|
||||||
|
SyncFuncLit
|
||||||
|
SyncCompLit
|
||||||
|
|
||||||
|
SyncDecl
|
||||||
|
SyncFuncBody
|
||||||
|
SyncOpenScope
|
||||||
|
SyncCloseScope
|
||||||
|
SyncCloseAnotherScope
|
||||||
|
SyncDeclNames
|
||||||
|
SyncDeclName
|
||||||
|
|
||||||
|
SyncStmts
|
||||||
|
SyncBlockStmt
|
||||||
|
SyncIfStmt
|
||||||
|
SyncForStmt
|
||||||
|
SyncSwitchStmt
|
||||||
|
SyncRangeStmt
|
||||||
|
SyncCaseClause
|
||||||
|
SyncCommClause
|
||||||
|
SyncSelectStmt
|
||||||
|
SyncDecls
|
||||||
|
SyncLabeledStmt
|
||||||
|
SyncUseObjLocal
|
||||||
|
SyncAddLocal
|
||||||
|
SyncLinkname
|
||||||
|
SyncStmt1
|
||||||
|
SyncStmtsEnd
|
||||||
|
SyncLabel
|
||||||
|
SyncOptLabel
|
||||||
|
)
|
89
vendor/golang.org/x/tools/go/internal/pkgbits/syncmarker_string.go
generated
vendored
Normal file
89
vendor/golang.org/x/tools/go/internal/pkgbits/syncmarker_string.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Code generated by "stringer -type=SyncMarker -trimprefix=Sync"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package pkgbits
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[SyncEOF-1]
|
||||||
|
_ = x[SyncBool-2]
|
||||||
|
_ = x[SyncInt64-3]
|
||||||
|
_ = x[SyncUint64-4]
|
||||||
|
_ = x[SyncString-5]
|
||||||
|
_ = x[SyncValue-6]
|
||||||
|
_ = x[SyncVal-7]
|
||||||
|
_ = x[SyncRelocs-8]
|
||||||
|
_ = x[SyncReloc-9]
|
||||||
|
_ = x[SyncUseReloc-10]
|
||||||
|
_ = x[SyncPublic-11]
|
||||||
|
_ = x[SyncPos-12]
|
||||||
|
_ = x[SyncPosBase-13]
|
||||||
|
_ = x[SyncObject-14]
|
||||||
|
_ = x[SyncObject1-15]
|
||||||
|
_ = x[SyncPkg-16]
|
||||||
|
_ = x[SyncPkgDef-17]
|
||||||
|
_ = x[SyncMethod-18]
|
||||||
|
_ = x[SyncType-19]
|
||||||
|
_ = x[SyncTypeIdx-20]
|
||||||
|
_ = x[SyncTypeParamNames-21]
|
||||||
|
_ = x[SyncSignature-22]
|
||||||
|
_ = x[SyncParams-23]
|
||||||
|
_ = x[SyncParam-24]
|
||||||
|
_ = x[SyncCodeObj-25]
|
||||||
|
_ = x[SyncSym-26]
|
||||||
|
_ = x[SyncLocalIdent-27]
|
||||||
|
_ = x[SyncSelector-28]
|
||||||
|
_ = x[SyncPrivate-29]
|
||||||
|
_ = x[SyncFuncExt-30]
|
||||||
|
_ = x[SyncVarExt-31]
|
||||||
|
_ = x[SyncTypeExt-32]
|
||||||
|
_ = x[SyncPragma-33]
|
||||||
|
_ = x[SyncExprList-34]
|
||||||
|
_ = x[SyncExprs-35]
|
||||||
|
_ = x[SyncExpr-36]
|
||||||
|
_ = x[SyncExprType-37]
|
||||||
|
_ = x[SyncAssign-38]
|
||||||
|
_ = x[SyncOp-39]
|
||||||
|
_ = x[SyncFuncLit-40]
|
||||||
|
_ = x[SyncCompLit-41]
|
||||||
|
_ = x[SyncDecl-42]
|
||||||
|
_ = x[SyncFuncBody-43]
|
||||||
|
_ = x[SyncOpenScope-44]
|
||||||
|
_ = x[SyncCloseScope-45]
|
||||||
|
_ = x[SyncCloseAnotherScope-46]
|
||||||
|
_ = x[SyncDeclNames-47]
|
||||||
|
_ = x[SyncDeclName-48]
|
||||||
|
_ = x[SyncStmts-49]
|
||||||
|
_ = x[SyncBlockStmt-50]
|
||||||
|
_ = x[SyncIfStmt-51]
|
||||||
|
_ = x[SyncForStmt-52]
|
||||||
|
_ = x[SyncSwitchStmt-53]
|
||||||
|
_ = x[SyncRangeStmt-54]
|
||||||
|
_ = x[SyncCaseClause-55]
|
||||||
|
_ = x[SyncCommClause-56]
|
||||||
|
_ = x[SyncSelectStmt-57]
|
||||||
|
_ = x[SyncDecls-58]
|
||||||
|
_ = x[SyncLabeledStmt-59]
|
||||||
|
_ = x[SyncUseObjLocal-60]
|
||||||
|
_ = x[SyncAddLocal-61]
|
||||||
|
_ = x[SyncLinkname-62]
|
||||||
|
_ = x[SyncStmt1-63]
|
||||||
|
_ = x[SyncStmtsEnd-64]
|
||||||
|
_ = x[SyncLabel-65]
|
||||||
|
_ = x[SyncOptLabel-66]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _SyncMarker_name = "EOFBoolInt64Uint64StringValueValRelocsRelocUseRelocPublicPosPosBaseObjectObject1PkgPkgDefMethodTypeTypeIdxTypeParamNamesSignatureParamsParamCodeObjSymLocalIdentSelectorPrivateFuncExtVarExtTypeExtPragmaExprListExprsExprExprTypeAssignOpFuncLitCompLitDeclFuncBodyOpenScopeCloseScopeCloseAnotherScopeDeclNamesDeclNameStmtsBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtUseObjLocalAddLocalLinknameStmt1StmtsEndLabelOptLabel"
|
||||||
|
|
||||||
|
var _SyncMarker_index = [...]uint16{0, 3, 7, 12, 18, 24, 29, 32, 38, 43, 51, 57, 60, 67, 73, 80, 83, 89, 95, 99, 106, 120, 129, 135, 140, 147, 150, 160, 168, 175, 182, 188, 195, 201, 209, 214, 218, 226, 232, 234, 241, 248, 252, 260, 269, 279, 296, 305, 313, 318, 327, 333, 340, 350, 359, 369, 379, 389, 394, 405, 416, 424, 432, 437, 445, 450, 458}
|
||||||
|
|
||||||
|
func (i SyncMarker) String() string {
|
||||||
|
i -= 1
|
||||||
|
if i < 0 || i >= SyncMarker(len(_SyncMarker_index)-1) {
|
||||||
|
return "SyncMarker(" + strconv.FormatInt(int64(i+1), 10) + ")"
|
||||||
|
}
|
||||||
|
return _SyncMarker_name[_SyncMarker_index[i]:_SyncMarker_index[i+1]]
|
||||||
|
}
|
220
vendor/golang.org/x/tools/go/packages/doc.go
generated
vendored
Normal file
220
vendor/golang.org/x/tools/go/packages/doc.go
generated
vendored
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package packages loads Go packages for inspection and analysis.
|
||||||
|
|
||||||
|
The Load function takes as input a list of patterns and return a list of Package
|
||||||
|
structs describing individual packages matched by those patterns.
|
||||||
|
The LoadMode controls the amount of detail in the loaded packages.
|
||||||
|
|
||||||
|
Load passes most patterns directly to the underlying build tool,
|
||||||
|
but all patterns with the prefix "query=", where query is a
|
||||||
|
non-empty string of letters from [a-z], are reserved and may be
|
||||||
|
interpreted as query operators.
|
||||||
|
|
||||||
|
Two query operators are currently supported: "file" and "pattern".
|
||||||
|
|
||||||
|
The query "file=path/to/file.go" matches the package or packages enclosing
|
||||||
|
the Go source file path/to/file.go. For example "file=~/go/src/fmt/print.go"
|
||||||
|
might return the packages "fmt" and "fmt [fmt.test]".
|
||||||
|
|
||||||
|
The query "pattern=string" causes "string" to be passed directly to
|
||||||
|
the underlying build tool. In most cases this is unnecessary,
|
||||||
|
but an application can use Load("pattern=" + x) as an escaping mechanism
|
||||||
|
to ensure that x is not interpreted as a query operator if it contains '='.
|
||||||
|
|
||||||
|
All other query operators are reserved for future use and currently
|
||||||
|
cause Load to report an error.
|
||||||
|
|
||||||
|
The Package struct provides basic information about the package, including
|
||||||
|
|
||||||
|
- ID, a unique identifier for the package in the returned set;
|
||||||
|
- GoFiles, the names of the package's Go source files;
|
||||||
|
- Imports, a map from source import strings to the Packages they name;
|
||||||
|
- Types, the type information for the package's exported symbols;
|
||||||
|
- Syntax, the parsed syntax trees for the package's source code; and
|
||||||
|
- TypeInfo, the result of a complete type-check of the package syntax trees.
|
||||||
|
|
||||||
|
(See the documentation for type Package for the complete list of fields
|
||||||
|
and more detailed descriptions.)
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
Load(nil, "bytes", "unicode...")
|
||||||
|
|
||||||
|
returns four Package structs describing the standard library packages
|
||||||
|
bytes, unicode, unicode/utf16, and unicode/utf8. Note that one pattern
|
||||||
|
can match multiple packages and that a package might be matched by
|
||||||
|
multiple patterns: in general it is not possible to determine which
|
||||||
|
packages correspond to which patterns.
|
||||||
|
|
||||||
|
Note that the list returned by Load contains only the packages matched
|
||||||
|
by the patterns. Their dependencies can be found by walking the import
|
||||||
|
graph using the Imports fields.
|
||||||
|
|
||||||
|
The Load function can be configured by passing a pointer to a Config as
|
||||||
|
the first argument. A nil Config is equivalent to the zero Config, which
|
||||||
|
causes Load to run in LoadFiles mode, collecting minimal information.
|
||||||
|
See the documentation for type Config for details.
|
||||||
|
|
||||||
|
As noted earlier, the Config.Mode controls the amount of detail
|
||||||
|
reported about the loaded packages. See the documentation for type LoadMode
|
||||||
|
for details.
|
||||||
|
|
||||||
|
Most tools should pass their command-line arguments (after any flags)
|
||||||
|
uninterpreted to the loader, so that the loader can interpret them
|
||||||
|
according to the conventions of the underlying build system.
|
||||||
|
See the Example function for typical usage.
|
||||||
|
*/
|
||||||
|
package packages // import "golang.org/x/tools/go/packages"
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Motivation and design considerations
|
||||||
|
|
||||||
|
The new package's design solves problems addressed by two existing
|
||||||
|
packages: go/build, which locates and describes packages, and
|
||||||
|
golang.org/x/tools/go/loader, which loads, parses and type-checks them.
|
||||||
|
The go/build.Package structure encodes too much of the 'go build' way
|
||||||
|
of organizing projects, leaving us in need of a data type that describes a
|
||||||
|
package of Go source code independent of the underlying build system.
|
||||||
|
We wanted something that works equally well with go build and vgo, and
|
||||||
|
also other build systems such as Bazel and Blaze, making it possible to
|
||||||
|
construct analysis tools that work in all these environments.
|
||||||
|
Tools such as errcheck and staticcheck were essentially unavailable to
|
||||||
|
the Go community at Google, and some of Google's internal tools for Go
|
||||||
|
are unavailable externally.
|
||||||
|
This new package provides a uniform way to obtain package metadata by
|
||||||
|
querying each of these build systems, optionally supporting their
|
||||||
|
preferred command-line notations for packages, so that tools integrate
|
||||||
|
neatly with users' build environments. The Metadata query function
|
||||||
|
executes an external query tool appropriate to the current workspace.
|
||||||
|
|
||||||
|
Loading packages always returns the complete import graph "all the way down",
|
||||||
|
even if all you want is information about a single package, because the query
|
||||||
|
mechanisms of all the build systems we currently support ({go,vgo} list, and
|
||||||
|
blaze/bazel aspect-based query) cannot provide detailed information
|
||||||
|
about one package without visiting all its dependencies too, so there is
|
||||||
|
no additional asymptotic cost to providing transitive information.
|
||||||
|
(This property might not be true of a hypothetical 5th build system.)
|
||||||
|
|
||||||
|
In calls to TypeCheck, all initial packages, and any package that
|
||||||
|
transitively depends on one of them, must be loaded from source.
|
||||||
|
Consider A->B->C->D->E: if A,C are initial, A,B,C must be loaded from
|
||||||
|
source; D may be loaded from export data, and E may not be loaded at all
|
||||||
|
(though it's possible that D's export data mentions it, so a
|
||||||
|
types.Package may be created for it and exposed.)
|
||||||
|
|
||||||
|
The old loader had a feature to suppress type-checking of function
|
||||||
|
bodies on a per-package basis, primarily intended to reduce the work of
|
||||||
|
obtaining type information for imported packages. Now that imports are
|
||||||
|
satisfied by export data, the optimization no longer seems necessary.
|
||||||
|
|
||||||
|
Despite some early attempts, the old loader did not exploit export data,
|
||||||
|
instead always using the equivalent of WholeProgram mode. This was due
|
||||||
|
to the complexity of mixing source and export data packages (now
|
||||||
|
resolved by the upward traversal mentioned above), and because export data
|
||||||
|
files were nearly always missing or stale. Now that 'go build' supports
|
||||||
|
caching, all the underlying build systems can guarantee to produce
|
||||||
|
export data in a reasonable (amortized) time.
|
||||||
|
|
||||||
|
Test "main" packages synthesized by the build system are now reported as
|
||||||
|
first-class packages, avoiding the need for clients (such as go/ssa) to
|
||||||
|
reinvent this generation logic.
|
||||||
|
|
||||||
|
One way in which go/packages is simpler than the old loader is in its
|
||||||
|
treatment of in-package tests. In-package tests are packages that
|
||||||
|
consist of all the files of the library under test, plus the test files.
|
||||||
|
The old loader constructed in-package tests by a two-phase process of
|
||||||
|
mutation called "augmentation": first it would construct and type check
|
||||||
|
all the ordinary library packages and type-check the packages that
|
||||||
|
depend on them; then it would add more (test) files to the package and
|
||||||
|
type-check again. This two-phase approach had four major problems:
|
||||||
|
1) in processing the tests, the loader modified the library package,
|
||||||
|
leaving no way for a client application to see both the test
|
||||||
|
package and the library package; one would mutate into the other.
|
||||||
|
2) because test files can declare additional methods on types defined in
|
||||||
|
the library portion of the package, the dispatch of method calls in
|
||||||
|
the library portion was affected by the presence of the test files.
|
||||||
|
This should have been a clue that the packages were logically
|
||||||
|
different.
|
||||||
|
3) this model of "augmentation" assumed at most one in-package test
|
||||||
|
per library package, which is true of projects using 'go build',
|
||||||
|
but not other build systems.
|
||||||
|
4) because of the two-phase nature of test processing, all packages that
|
||||||
|
import the library package had to be processed before augmentation,
|
||||||
|
forcing a "one-shot" API and preventing the client from calling Load
|
||||||
|
in several times in sequence as is now possible in WholeProgram mode.
|
||||||
|
(TypeCheck mode has a similar one-shot restriction for a different reason.)
|
||||||
|
|
||||||
|
Early drafts of this package supported "multi-shot" operation.
|
||||||
|
Although it allowed clients to make a sequence of calls (or concurrent
|
||||||
|
calls) to Load, building up the graph of Packages incrementally,
|
||||||
|
it was of marginal value: it complicated the API
|
||||||
|
(since it allowed some options to vary across calls but not others),
|
||||||
|
it complicated the implementation,
|
||||||
|
it cannot be made to work in Types mode, as explained above,
|
||||||
|
and it was less efficient than making one combined call (when this is possible).
|
||||||
|
Among the clients we have inspected, none made multiple calls to load
|
||||||
|
but could not be easily and satisfactorily modified to make only a single call.
|
||||||
|
However, applications changes may be required.
|
||||||
|
For example, the ssadump command loads the user-specified packages
|
||||||
|
and in addition the runtime package. It is tempting to simply append
|
||||||
|
"runtime" to the user-provided list, but that does not work if the user
|
||||||
|
specified an ad-hoc package such as [a.go b.go].
|
||||||
|
Instead, ssadump no longer requests the runtime package,
|
||||||
|
but seeks it among the dependencies of the user-specified packages,
|
||||||
|
and emits an error if it is not found.
|
||||||
|
|
||||||
|
Overlays: The Overlay field in the Config allows providing alternate contents
|
||||||
|
for Go source files, by providing a mapping from file path to contents.
|
||||||
|
go/packages will pull in new imports added in overlay files when go/packages
|
||||||
|
is run in LoadImports mode or greater.
|
||||||
|
Overlay support for the go list driver isn't complete yet: if the file doesn't
|
||||||
|
exist on disk, it will only be recognized in an overlay if it is a non-test file
|
||||||
|
and the package would be reported even without the overlay.
|
||||||
|
|
||||||
|
Questions & Tasks
|
||||||
|
|
||||||
|
- Add GOARCH/GOOS?
|
||||||
|
They are not portable concepts, but could be made portable.
|
||||||
|
Our goal has been to allow users to express themselves using the conventions
|
||||||
|
of the underlying build system: if the build system honors GOARCH
|
||||||
|
during a build and during a metadata query, then so should
|
||||||
|
applications built atop that query mechanism.
|
||||||
|
Conversely, if the target architecture of the build is determined by
|
||||||
|
command-line flags, the application can pass the relevant
|
||||||
|
flags through to the build system using a command such as:
|
||||||
|
myapp -query_flag="--cpu=amd64" -query_flag="--os=darwin"
|
||||||
|
However, this approach is low-level, unwieldy, and non-portable.
|
||||||
|
GOOS and GOARCH seem important enough to warrant a dedicated option.
|
||||||
|
|
||||||
|
- How should we handle partial failures such as a mixture of good and
|
||||||
|
malformed patterns, existing and non-existent packages, successful and
|
||||||
|
failed builds, import failures, import cycles, and so on, in a call to
|
||||||
|
Load?
|
||||||
|
|
||||||
|
- Support bazel, blaze, and go1.10 list, not just go1.11 list.
|
||||||
|
|
||||||
|
- Handle (and test) various partial success cases, e.g.
|
||||||
|
a mixture of good packages and:
|
||||||
|
invalid patterns
|
||||||
|
nonexistent packages
|
||||||
|
empty packages
|
||||||
|
packages with malformed package or import declarations
|
||||||
|
unreadable files
|
||||||
|
import cycles
|
||||||
|
other parse errors
|
||||||
|
type errors
|
||||||
|
Make sure we record errors at the correct place in the graph.
|
||||||
|
|
||||||
|
- Missing packages among initial arguments are not reported.
|
||||||
|
Return bogus packages for them, like golist does.
|
||||||
|
|
||||||
|
- "undeclared name" errors (for example) are reported out of source file
|
||||||
|
order. I suspect this is due to the breadth-first resolution now used
|
||||||
|
by go/types. Is that a bug? Discuss with gri.
|
||||||
|
|
||||||
|
*/
|
101
vendor/golang.org/x/tools/go/packages/external.go
generated
vendored
Normal file
101
vendor/golang.org/x/tools/go/packages/external.go
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This file enables an external tool to intercept package requests.
|
||||||
|
// If the tool is present then its results are used in preference to
|
||||||
|
// the go list command.
|
||||||
|
|
||||||
|
package packages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
exec "golang.org/x/sys/execabs"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The Driver Protocol
|
||||||
|
//
|
||||||
|
// The driver, given the inputs to a call to Load, returns metadata about the packages specified.
|
||||||
|
// This allows for different build systems to support go/packages by telling go/packages how the
|
||||||
|
// packages' source is organized.
|
||||||
|
// The driver is a binary, either specified by the GOPACKAGESDRIVER environment variable or in
|
||||||
|
// the path as gopackagesdriver. It's given the inputs to load in its argv. See the package
|
||||||
|
// documentation in doc.go for the full description of the patterns that need to be supported.
|
||||||
|
// A driver receives as a JSON-serialized driverRequest struct in standard input and will
|
||||||
|
// produce a JSON-serialized driverResponse (see definition in packages.go) in its standard output.
|
||||||
|
|
||||||
|
// driverRequest is used to provide the portion of Load's Config that is needed by a driver.
|
||||||
|
type driverRequest struct {
|
||||||
|
Mode LoadMode `json:"mode"`
|
||||||
|
// Env specifies the environment the underlying build system should be run in.
|
||||||
|
Env []string `json:"env"`
|
||||||
|
// BuildFlags are flags that should be passed to the underlying build system.
|
||||||
|
BuildFlags []string `json:"build_flags"`
|
||||||
|
// Tests specifies whether the patterns should also return test packages.
|
||||||
|
Tests bool `json:"tests"`
|
||||||
|
// Overlay maps file paths (relative to the driver's working directory) to the byte contents
|
||||||
|
// of overlay files.
|
||||||
|
Overlay map[string][]byte `json:"overlay"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// findExternalDriver returns the file path of a tool that supplies
|
||||||
|
// the build system package structure, or "" if not found."
|
||||||
|
// If GOPACKAGESDRIVER is set in the environment findExternalTool returns its
|
||||||
|
// value, otherwise it searches for a binary named gopackagesdriver on the PATH.
|
||||||
|
func findExternalDriver(cfg *Config) driver {
|
||||||
|
const toolPrefix = "GOPACKAGESDRIVER="
|
||||||
|
tool := ""
|
||||||
|
for _, env := range cfg.Env {
|
||||||
|
if val := strings.TrimPrefix(env, toolPrefix); val != env {
|
||||||
|
tool = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tool != "" && tool == "off" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if tool == "" {
|
||||||
|
var err error
|
||||||
|
tool, err = exec.LookPath("gopackagesdriver")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return func(cfg *Config, words ...string) (*driverResponse, error) {
|
||||||
|
req, err := json.Marshal(driverRequest{
|
||||||
|
Mode: cfg.Mode,
|
||||||
|
Env: cfg.Env,
|
||||||
|
BuildFlags: cfg.BuildFlags,
|
||||||
|
Tests: cfg.Tests,
|
||||||
|
Overlay: cfg.Overlay,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to encode message to driver tool: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
stderr := new(bytes.Buffer)
|
||||||
|
cmd := exec.CommandContext(cfg.Context, tool, words...)
|
||||||
|
cmd.Dir = cfg.Dir
|
||||||
|
cmd.Env = cfg.Env
|
||||||
|
cmd.Stdin = bytes.NewReader(req)
|
||||||
|
cmd.Stdout = buf
|
||||||
|
cmd.Stderr = stderr
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr)
|
||||||
|
}
|
||||||
|
if len(stderr.Bytes()) != 0 && os.Getenv("GOPACKAGESPRINTDRIVERERRORS") != "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cmd), stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
var response driverResponse
|
||||||
|
if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &response, nil
|
||||||
|
}
|
||||||
|
}
|
1173
vendor/golang.org/x/tools/go/packages/golist.go
generated
vendored
Normal file
1173
vendor/golang.org/x/tools/go/packages/golist.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
575
vendor/golang.org/x/tools/go/packages/golist_overlay.go
generated
vendored
Normal file
575
vendor/golang.org/x/tools/go/packages/golist_overlay.go
generated
vendored
Normal file
@ -0,0 +1,575 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package packages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/gocommand"
|
||||||
|
)
|
||||||
|
|
||||||
|
// processGolistOverlay provides rudimentary support for adding
|
||||||
|
// files that don't exist on disk to an overlay. The results can be
|
||||||
|
// sometimes incorrect.
|
||||||
|
// TODO(matloob): Handle unsupported cases, including the following:
|
||||||
|
// - determining the correct package to add given a new import path
|
||||||
|
func (state *golistState) processGolistOverlay(response *responseDeduper) (modifiedPkgs, needPkgs []string, err error) {
|
||||||
|
havePkgs := make(map[string]string) // importPath -> non-test package ID
|
||||||
|
needPkgsSet := make(map[string]bool)
|
||||||
|
modifiedPkgsSet := make(map[string]bool)
|
||||||
|
|
||||||
|
pkgOfDir := make(map[string][]*Package)
|
||||||
|
for _, pkg := range response.dr.Packages {
|
||||||
|
// This is an approximation of import path to id. This can be
|
||||||
|
// wrong for tests, vendored packages, and a number of other cases.
|
||||||
|
havePkgs[pkg.PkgPath] = pkg.ID
|
||||||
|
dir, err := commonDir(pkg.GoFiles)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if dir != "" {
|
||||||
|
pkgOfDir[dir] = append(pkgOfDir[dir], pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no new imports are added, it is safe to avoid loading any needPkgs.
|
||||||
|
// Otherwise, it's hard to tell which package is actually being loaded
|
||||||
|
// (due to vendoring) and whether any modified package will show up
|
||||||
|
// in the transitive set of dependencies (because new imports are added,
|
||||||
|
// potentially modifying the transitive set of dependencies).
|
||||||
|
var overlayAddsImports bool
|
||||||
|
|
||||||
|
// If both a package and its test package are created by the overlay, we
|
||||||
|
// need the real package first. Process all non-test files before test
|
||||||
|
// files, and make the whole process deterministic while we're at it.
|
||||||
|
var overlayFiles []string
|
||||||
|
for opath := range state.cfg.Overlay {
|
||||||
|
overlayFiles = append(overlayFiles, opath)
|
||||||
|
}
|
||||||
|
sort.Slice(overlayFiles, func(i, j int) bool {
|
||||||
|
iTest := strings.HasSuffix(overlayFiles[i], "_test.go")
|
||||||
|
jTest := strings.HasSuffix(overlayFiles[j], "_test.go")
|
||||||
|
if iTest != jTest {
|
||||||
|
return !iTest // non-tests are before tests.
|
||||||
|
}
|
||||||
|
return overlayFiles[i] < overlayFiles[j]
|
||||||
|
})
|
||||||
|
for _, opath := range overlayFiles {
|
||||||
|
contents := state.cfg.Overlay[opath]
|
||||||
|
base := filepath.Base(opath)
|
||||||
|
dir := filepath.Dir(opath)
|
||||||
|
var pkg *Package // if opath belongs to both a package and its test variant, this will be the test variant
|
||||||
|
var testVariantOf *Package // if opath is a test file, this is the package it is testing
|
||||||
|
var fileExists bool
|
||||||
|
isTestFile := strings.HasSuffix(opath, "_test.go")
|
||||||
|
pkgName, ok := extractPackageName(opath, contents)
|
||||||
|
if !ok {
|
||||||
|
// Don't bother adding a file that doesn't even have a parsable package statement
|
||||||
|
// to the overlay.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// If all the overlay files belong to a different package, change the
|
||||||
|
// package name to that package.
|
||||||
|
maybeFixPackageName(pkgName, isTestFile, pkgOfDir[dir])
|
||||||
|
nextPackage:
|
||||||
|
for _, p := range response.dr.Packages {
|
||||||
|
if pkgName != p.Name && p.ID != "command-line-arguments" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, f := range p.GoFiles {
|
||||||
|
if !sameFile(filepath.Dir(f), dir) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Make sure to capture information on the package's test variant, if needed.
|
||||||
|
if isTestFile && !hasTestFiles(p) {
|
||||||
|
// TODO(matloob): Are there packages other than the 'production' variant
|
||||||
|
// of a package that this can match? This shouldn't match the test main package
|
||||||
|
// because the file is generated in another directory.
|
||||||
|
testVariantOf = p
|
||||||
|
continue nextPackage
|
||||||
|
} else if !isTestFile && hasTestFiles(p) {
|
||||||
|
// We're examining a test variant, but the overlaid file is
|
||||||
|
// a non-test file. Because the overlay implementation
|
||||||
|
// (currently) only adds a file to one package, skip this
|
||||||
|
// package, so that we can add the file to the production
|
||||||
|
// variant of the package. (https://golang.org/issue/36857
|
||||||
|
// tracks handling overlays on both the production and test
|
||||||
|
// variant of a package).
|
||||||
|
continue nextPackage
|
||||||
|
}
|
||||||
|
if pkg != nil && p != pkg && pkg.PkgPath == p.PkgPath {
|
||||||
|
// We have already seen the production version of the
|
||||||
|
// for which p is a test variant.
|
||||||
|
if hasTestFiles(p) {
|
||||||
|
testVariantOf = pkg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkg = p
|
||||||
|
if filepath.Base(f) == base {
|
||||||
|
fileExists = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The overlay could have included an entirely new package or an
|
||||||
|
// ad-hoc package. An ad-hoc package is one that we have manually
|
||||||
|
// constructed from inadequate `go list` results for a file= query.
|
||||||
|
// It will have the ID command-line-arguments.
|
||||||
|
if pkg == nil || pkg.ID == "command-line-arguments" {
|
||||||
|
// Try to find the module or gopath dir the file is contained in.
|
||||||
|
// Then for modules, add the module opath to the beginning.
|
||||||
|
pkgPath, ok, err := state.getPkgPath(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var forTest string // only set for x tests
|
||||||
|
isXTest := strings.HasSuffix(pkgName, "_test")
|
||||||
|
if isXTest {
|
||||||
|
forTest = pkgPath
|
||||||
|
pkgPath += "_test"
|
||||||
|
}
|
||||||
|
id := pkgPath
|
||||||
|
if isTestFile {
|
||||||
|
if isXTest {
|
||||||
|
id = fmt.Sprintf("%s [%s.test]", pkgPath, forTest)
|
||||||
|
} else {
|
||||||
|
id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pkg != nil {
|
||||||
|
// TODO(rstambler): We should change the package's path and ID
|
||||||
|
// here. The only issue is that this messes with the roots.
|
||||||
|
} else {
|
||||||
|
// Try to reclaim a package with the same ID, if it exists in the response.
|
||||||
|
for _, p := range response.dr.Packages {
|
||||||
|
if reclaimPackage(p, id, opath, contents) {
|
||||||
|
pkg = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Otherwise, create a new package.
|
||||||
|
if pkg == nil {
|
||||||
|
pkg = &Package{
|
||||||
|
PkgPath: pkgPath,
|
||||||
|
ID: id,
|
||||||
|
Name: pkgName,
|
||||||
|
Imports: make(map[string]*Package),
|
||||||
|
}
|
||||||
|
response.addPackage(pkg)
|
||||||
|
havePkgs[pkg.PkgPath] = id
|
||||||
|
// Add the production package's sources for a test variant.
|
||||||
|
if isTestFile && !isXTest && testVariantOf != nil {
|
||||||
|
pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...)
|
||||||
|
pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...)
|
||||||
|
// Add the package under test and its imports to the test variant.
|
||||||
|
pkg.forTest = testVariantOf.PkgPath
|
||||||
|
for k, v := range testVariantOf.Imports {
|
||||||
|
pkg.Imports[k] = &Package{ID: v.ID}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isXTest {
|
||||||
|
pkg.forTest = forTest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !fileExists {
|
||||||
|
pkg.GoFiles = append(pkg.GoFiles, opath)
|
||||||
|
// TODO(matloob): Adding the file to CompiledGoFiles can exhibit the wrong behavior
|
||||||
|
// if the file will be ignored due to its build tags.
|
||||||
|
pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, opath)
|
||||||
|
modifiedPkgsSet[pkg.ID] = true
|
||||||
|
}
|
||||||
|
imports, err := extractImports(opath, contents)
|
||||||
|
if err != nil {
|
||||||
|
// Let the parser or type checker report errors later.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, imp := range imports {
|
||||||
|
// TODO(rstambler): If the package is an x test and the import has
|
||||||
|
// a test variant, make sure to replace it.
|
||||||
|
if _, found := pkg.Imports[imp]; found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
overlayAddsImports = true
|
||||||
|
id, ok := havePkgs[imp]
|
||||||
|
if !ok {
|
||||||
|
var err error
|
||||||
|
id, err = state.resolveImport(dir, imp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkg.Imports[imp] = &Package{ID: id}
|
||||||
|
// Add dependencies to the non-test variant version of this package as well.
|
||||||
|
if testVariantOf != nil {
|
||||||
|
testVariantOf.Imports[imp] = &Package{ID: id}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// toPkgPath guesses the package path given the id.
|
||||||
|
toPkgPath := func(sourceDir, id string) (string, error) {
|
||||||
|
if i := strings.IndexByte(id, ' '); i >= 0 {
|
||||||
|
return state.resolveImport(sourceDir, id[:i])
|
||||||
|
}
|
||||||
|
return state.resolveImport(sourceDir, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that new packages have been created, do another pass to determine
|
||||||
|
// the new set of missing packages.
|
||||||
|
for _, pkg := range response.dr.Packages {
|
||||||
|
for _, imp := range pkg.Imports {
|
||||||
|
if len(pkg.GoFiles) == 0 {
|
||||||
|
return nil, nil, fmt.Errorf("cannot resolve imports for package %q with no Go files", pkg.PkgPath)
|
||||||
|
}
|
||||||
|
pkgPath, err := toPkgPath(filepath.Dir(pkg.GoFiles[0]), imp.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if _, ok := havePkgs[pkgPath]; !ok {
|
||||||
|
needPkgsSet[pkgPath] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if overlayAddsImports {
|
||||||
|
needPkgs = make([]string, 0, len(needPkgsSet))
|
||||||
|
for pkg := range needPkgsSet {
|
||||||
|
needPkgs = append(needPkgs, pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modifiedPkgs = make([]string, 0, len(modifiedPkgsSet))
|
||||||
|
for pkg := range modifiedPkgsSet {
|
||||||
|
modifiedPkgs = append(modifiedPkgs, pkg)
|
||||||
|
}
|
||||||
|
return modifiedPkgs, needPkgs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveImport finds the ID of a package given its import path.
|
||||||
|
// In particular, it will find the right vendored copy when in GOPATH mode.
|
||||||
|
func (state *golistState) resolveImport(sourceDir, importPath string) (string, error) {
|
||||||
|
env, err := state.getEnv()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if env["GOMOD"] != "" {
|
||||||
|
return importPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
searchDir := sourceDir
|
||||||
|
for {
|
||||||
|
vendorDir := filepath.Join(searchDir, "vendor")
|
||||||
|
exists, ok := state.vendorDirs[vendorDir]
|
||||||
|
if !ok {
|
||||||
|
info, err := os.Stat(vendorDir)
|
||||||
|
exists = err == nil && info.IsDir()
|
||||||
|
state.vendorDirs[vendorDir] = exists
|
||||||
|
}
|
||||||
|
|
||||||
|
if exists {
|
||||||
|
vendoredPath := filepath.Join(vendorDir, importPath)
|
||||||
|
if info, err := os.Stat(vendoredPath); err == nil && info.IsDir() {
|
||||||
|
// We should probably check for .go files here, but shame on anyone who fools us.
|
||||||
|
path, ok, err := state.getPkgPath(vendoredPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We know we've hit the top of the filesystem when we Dir / and get /,
|
||||||
|
// or C:\ and get C:\, etc.
|
||||||
|
next := filepath.Dir(searchDir)
|
||||||
|
if next == searchDir {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
searchDir = next
|
||||||
|
}
|
||||||
|
return importPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasTestFiles(p *Package) bool {
|
||||||
|
for _, f := range p.GoFiles {
|
||||||
|
if strings.HasSuffix(f, "_test.go") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// determineRootDirs returns a mapping from absolute directories that could
|
||||||
|
// contain code to their corresponding import path prefixes.
|
||||||
|
func (state *golistState) determineRootDirs() (map[string]string, error) {
|
||||||
|
env, err := state.getEnv()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if env["GOMOD"] != "" {
|
||||||
|
state.rootsOnce.Do(func() {
|
||||||
|
state.rootDirs, state.rootDirsError = state.determineRootDirsModules()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
state.rootsOnce.Do(func() {
|
||||||
|
state.rootDirs, state.rootDirsError = state.determineRootDirsGOPATH()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return state.rootDirs, state.rootDirsError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (state *golistState) determineRootDirsModules() (map[string]string, error) {
|
||||||
|
// List all of the modules--the first will be the directory for the main
|
||||||
|
// module. Any replaced modules will also need to be treated as roots.
|
||||||
|
// Editing files in the module cache isn't a great idea, so we don't
|
||||||
|
// plan to ever support that.
|
||||||
|
out, err := state.invokeGo("list", "-m", "-json", "all")
|
||||||
|
if err != nil {
|
||||||
|
// 'go list all' will fail if we're outside of a module and
|
||||||
|
// GO111MODULE=on. Try falling back without 'all'.
|
||||||
|
var innerErr error
|
||||||
|
out, innerErr = state.invokeGo("list", "-m", "-json")
|
||||||
|
if innerErr != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
roots := map[string]string{}
|
||||||
|
modules := map[string]string{}
|
||||||
|
var i int
|
||||||
|
for dec := json.NewDecoder(out); dec.More(); {
|
||||||
|
mod := new(gocommand.ModuleJSON)
|
||||||
|
if err := dec.Decode(mod); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if mod.Dir != "" && mod.Path != "" {
|
||||||
|
// This is a valid module; add it to the map.
|
||||||
|
absDir, err := filepath.Abs(mod.Dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
modules[absDir] = mod.Path
|
||||||
|
// The first result is the main module.
|
||||||
|
if i == 0 || mod.Replace != nil && mod.Replace.Path != "" {
|
||||||
|
roots[absDir] = mod.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return roots, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (state *golistState) determineRootDirsGOPATH() (map[string]string, error) {
|
||||||
|
m := map[string]string{}
|
||||||
|
for _, dir := range filepath.SplitList(state.mustGetEnv()["GOPATH"]) {
|
||||||
|
absDir, err := filepath.Abs(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m[filepath.Join(absDir, "src")] = ""
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractImports(filename string, contents []byte) ([]string, error) {
|
||||||
|
f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset?
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res []string
|
||||||
|
for _, imp := range f.Imports {
|
||||||
|
quotedPath := imp.Path.Value
|
||||||
|
path, err := strconv.Unquote(quotedPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res = append(res, path)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// reclaimPackage attempts to reuse a package that failed to load in an overlay.
|
||||||
|
//
|
||||||
|
// If the package has errors and has no Name, GoFiles, or Imports,
|
||||||
|
// then it's possible that it doesn't yet exist on disk.
|
||||||
|
func reclaimPackage(pkg *Package, id string, filename string, contents []byte) bool {
|
||||||
|
// TODO(rstambler): Check the message of the actual error?
|
||||||
|
// It differs between $GOPATH and module mode.
|
||||||
|
if pkg.ID != id {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(pkg.Errors) != 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if pkg.Name != "" || pkg.ExportFile != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(pkg.GoFiles) > 0 || len(pkg.CompiledGoFiles) > 0 || len(pkg.OtherFiles) > 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(pkg.Imports) > 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
pkgName, ok := extractPackageName(filename, contents)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
pkg.Name = pkgName
|
||||||
|
pkg.Errors = nil
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractPackageName(filename string, contents []byte) (string, bool) {
|
||||||
|
// TODO(rstambler): Check the message of the actual error?
|
||||||
|
// It differs between $GOPATH and module mode.
|
||||||
|
f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.PackageClauseOnly) // TODO(matloob): reuse fileset?
|
||||||
|
if err != nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return f.Name.Name, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// commonDir returns the directory that all files are in, "" if files is empty,
|
||||||
|
// or an error if they aren't in the same directory.
|
||||||
|
func commonDir(files []string) (string, error) {
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
for _, f := range files {
|
||||||
|
seen[filepath.Dir(f)] = true
|
||||||
|
}
|
||||||
|
if len(seen) > 1 {
|
||||||
|
return "", fmt.Errorf("files (%v) are in more than one directory: %v", files, seen)
|
||||||
|
}
|
||||||
|
for k := range seen {
|
||||||
|
// seen has only one element; return it.
|
||||||
|
return k, nil
|
||||||
|
}
|
||||||
|
return "", nil // no files
|
||||||
|
}
|
||||||
|
|
||||||
|
// It is possible that the files in the disk directory dir have a different package
|
||||||
|
// name from newName, which is deduced from the overlays. If they all have a different
|
||||||
|
// package name, and they all have the same package name, then that name becomes
|
||||||
|
// the package name.
|
||||||
|
// It returns true if it changes the package name, false otherwise.
|
||||||
|
func maybeFixPackageName(newName string, isTestFile bool, pkgsOfDir []*Package) {
|
||||||
|
names := make(map[string]int)
|
||||||
|
for _, p := range pkgsOfDir {
|
||||||
|
names[p.Name]++
|
||||||
|
}
|
||||||
|
if len(names) != 1 {
|
||||||
|
// some files are in different packages
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var oldName string
|
||||||
|
for k := range names {
|
||||||
|
oldName = k
|
||||||
|
}
|
||||||
|
if newName == oldName {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// We might have a case where all of the package names in the directory are
|
||||||
|
// the same, but the overlay file is for an x test, which belongs to its
|
||||||
|
// own package. If the x test does not yet exist on disk, we may not yet
|
||||||
|
// have its package name on disk, but we should not rename the packages.
|
||||||
|
//
|
||||||
|
// We use a heuristic to determine if this file belongs to an x test:
|
||||||
|
// The test file should have a package name whose package name has a _test
|
||||||
|
// suffix or looks like "newName_test".
|
||||||
|
maybeXTest := strings.HasPrefix(oldName+"_test", newName) || strings.HasSuffix(newName, "_test")
|
||||||
|
if isTestFile && maybeXTest {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, p := range pkgsOfDir {
|
||||||
|
p.Name = newName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is copy-pasted from
|
||||||
|
// https://github.com/golang/go/blob/9706f510a5e2754595d716bd64be8375997311fb/src/cmd/go/internal/search/search.go#L360.
|
||||||
|
// It should be deleted when we remove support for overlays from go/packages.
|
||||||
|
//
|
||||||
|
// NOTE: This does not handle any ./... or ./ style queries, as this function
|
||||||
|
// doesn't know the working directory.
|
||||||
|
//
|
||||||
|
// matchPattern(pattern)(name) reports whether
|
||||||
|
// name matches pattern. Pattern is a limited glob
|
||||||
|
// pattern in which '...' means 'any string' and there
|
||||||
|
// is no other special syntax.
|
||||||
|
// Unfortunately, there are two special cases. Quoting "go help packages":
|
||||||
|
//
|
||||||
|
// First, /... at the end of the pattern can match an empty string,
|
||||||
|
// so that net/... matches both net and packages in its subdirectories, like net/http.
|
||||||
|
// Second, any slash-separated pattern element containing a wildcard never
|
||||||
|
// participates in a match of the "vendor" element in the path of a vendored
|
||||||
|
// package, so that ./... does not match packages in subdirectories of
|
||||||
|
// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
|
||||||
|
// Note, however, that a directory named vendor that itself contains code
|
||||||
|
// is not a vendored package: cmd/vendor would be a command named vendor,
|
||||||
|
// and the pattern cmd/... matches it.
|
||||||
|
func matchPattern(pattern string) func(name string) bool {
|
||||||
|
// Convert pattern to regular expression.
|
||||||
|
// The strategy for the trailing /... is to nest it in an explicit ? expression.
|
||||||
|
// The strategy for the vendor exclusion is to change the unmatchable
|
||||||
|
// vendor strings to a disallowed code point (vendorChar) and to use
|
||||||
|
// "(anything but that codepoint)*" as the implementation of the ... wildcard.
|
||||||
|
// This is a bit complicated but the obvious alternative,
|
||||||
|
// namely a hand-written search like in most shell glob matchers,
|
||||||
|
// is too easy to make accidentally exponential.
|
||||||
|
// Using package regexp guarantees linear-time matching.
|
||||||
|
|
||||||
|
const vendorChar = "\x00"
|
||||||
|
|
||||||
|
if strings.Contains(pattern, vendorChar) {
|
||||||
|
return func(name string) bool { return false }
|
||||||
|
}
|
||||||
|
|
||||||
|
re := regexp.QuoteMeta(pattern)
|
||||||
|
re = replaceVendor(re, vendorChar)
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
|
||||||
|
re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
|
||||||
|
case re == vendorChar+`/\.\.\.`:
|
||||||
|
re = `(/vendor|/` + vendorChar + `/\.\.\.)`
|
||||||
|
case strings.HasSuffix(re, `/\.\.\.`):
|
||||||
|
re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
|
||||||
|
}
|
||||||
|
re = strings.ReplaceAll(re, `\.\.\.`, `[^`+vendorChar+`]*`)
|
||||||
|
|
||||||
|
reg := regexp.MustCompile(`^` + re + `$`)
|
||||||
|
|
||||||
|
return func(name string) bool {
|
||||||
|
if strings.Contains(name, vendorChar) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return reg.MatchString(replaceVendor(name, vendorChar))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// replaceVendor returns the result of replacing
|
||||||
|
// non-trailing vendor path elements in x with repl.
|
||||||
|
func replaceVendor(x, repl string) string {
|
||||||
|
if !strings.Contains(x, "vendor") {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
elem := strings.Split(x, "/")
|
||||||
|
for i := 0; i < len(elem)-1; i++ {
|
||||||
|
if elem[i] == "vendor" {
|
||||||
|
elem[i] = repl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(elem, "/")
|
||||||
|
}
|
57
vendor/golang.org/x/tools/go/packages/loadmode_string.go
generated
vendored
Normal file
57
vendor/golang.org/x/tools/go/packages/loadmode_string.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 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 packages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var allModes = []LoadMode{
|
||||||
|
NeedName,
|
||||||
|
NeedFiles,
|
||||||
|
NeedCompiledGoFiles,
|
||||||
|
NeedImports,
|
||||||
|
NeedDeps,
|
||||||
|
NeedExportFile,
|
||||||
|
NeedTypes,
|
||||||
|
NeedSyntax,
|
||||||
|
NeedTypesInfo,
|
||||||
|
NeedTypesSizes,
|
||||||
|
}
|
||||||
|
|
||||||
|
var modeStrings = []string{
|
||||||
|
"NeedName",
|
||||||
|
"NeedFiles",
|
||||||
|
"NeedCompiledGoFiles",
|
||||||
|
"NeedImports",
|
||||||
|
"NeedDeps",
|
||||||
|
"NeedExportFile",
|
||||||
|
"NeedTypes",
|
||||||
|
"NeedSyntax",
|
||||||
|
"NeedTypesInfo",
|
||||||
|
"NeedTypesSizes",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod LoadMode) String() string {
|
||||||
|
m := mod
|
||||||
|
if m == 0 {
|
||||||
|
return "LoadMode(0)"
|
||||||
|
}
|
||||||
|
var out []string
|
||||||
|
for i, x := range allModes {
|
||||||
|
if x > m {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (m & x) != 0 {
|
||||||
|
out = append(out, modeStrings[i])
|
||||||
|
m = m ^ x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if m != 0 {
|
||||||
|
out = append(out, "Unknown")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("LoadMode(%s)", strings.Join(out, "|"))
|
||||||
|
}
|
1273
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
Normal file
1273
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
59
vendor/golang.org/x/tools/go/packages/visit.go
generated
vendored
Normal file
59
vendor/golang.org/x/tools/go/packages/visit.go
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package packages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Visit visits all the packages in the import graph whose roots are
|
||||||
|
// pkgs, calling the optional pre function the first time each package
|
||||||
|
// is encountered (preorder), and the optional post function after a
|
||||||
|
// package's dependencies have been visited (postorder).
|
||||||
|
// The boolean result of pre(pkg) determines whether
|
||||||
|
// the imports of package pkg are visited.
|
||||||
|
func Visit(pkgs []*Package, pre func(*Package) bool, post func(*Package)) {
|
||||||
|
seen := make(map[*Package]bool)
|
||||||
|
var visit func(*Package)
|
||||||
|
visit = func(pkg *Package) {
|
||||||
|
if !seen[pkg] {
|
||||||
|
seen[pkg] = true
|
||||||
|
|
||||||
|
if pre == nil || pre(pkg) {
|
||||||
|
paths := make([]string, 0, len(pkg.Imports))
|
||||||
|
for path := range pkg.Imports {
|
||||||
|
paths = append(paths, path)
|
||||||
|
}
|
||||||
|
sort.Strings(paths) // Imports is a map, this makes visit stable
|
||||||
|
for _, path := range paths {
|
||||||
|
visit(pkg.Imports[path])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if post != nil {
|
||||||
|
post(pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
visit(pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintErrors prints to os.Stderr the accumulated errors of all
|
||||||
|
// packages in the import graph rooted at pkgs, dependencies first.
|
||||||
|
// PrintErrors returns the number of errors printed.
|
||||||
|
func PrintErrors(pkgs []*Package) int {
|
||||||
|
var n int
|
||||||
|
Visit(pkgs, nil, func(pkg *Package) {
|
||||||
|
for _, err := range pkg.Errors {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return n
|
||||||
|
}
|
85
vendor/golang.org/x/tools/internal/event/core/event.go
generated
vendored
Normal file
85
vendor/golang.org/x/tools/internal/event/core/event.go
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 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 core provides support for event based telemetry.
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/event/label"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event holds the information about an event of note that occurred.
|
||||||
|
type Event struct {
|
||||||
|
at time.Time
|
||||||
|
|
||||||
|
// As events are often on the stack, storing the first few labels directly
|
||||||
|
// in the event can avoid an allocation at all for the very common cases of
|
||||||
|
// simple events.
|
||||||
|
// The length needs to be large enough to cope with the majority of events
|
||||||
|
// but no so large as to cause undue stack pressure.
|
||||||
|
// A log message with two values will use 3 labels (one for each value and
|
||||||
|
// one for the message itself).
|
||||||
|
|
||||||
|
static [3]label.Label // inline storage for the first few labels
|
||||||
|
dynamic []label.Label // dynamically sized storage for remaining labels
|
||||||
|
}
|
||||||
|
|
||||||
|
// eventLabelMap implements label.Map for a the labels of an Event.
|
||||||
|
type eventLabelMap struct {
|
||||||
|
event Event
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ev Event) At() time.Time { return ev.at }
|
||||||
|
|
||||||
|
func (ev Event) Format(f fmt.State, r rune) {
|
||||||
|
if !ev.at.IsZero() {
|
||||||
|
fmt.Fprint(f, ev.at.Format("2006/01/02 15:04:05 "))
|
||||||
|
}
|
||||||
|
for index := 0; ev.Valid(index); index++ {
|
||||||
|
if l := ev.Label(index); l.Valid() {
|
||||||
|
fmt.Fprintf(f, "\n\t%v", l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ev Event) Valid(index int) bool {
|
||||||
|
return index >= 0 && index < len(ev.static)+len(ev.dynamic)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ev Event) Label(index int) label.Label {
|
||||||
|
if index < len(ev.static) {
|
||||||
|
return ev.static[index]
|
||||||
|
}
|
||||||
|
return ev.dynamic[index-len(ev.static)]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ev Event) Find(key label.Key) label.Label {
|
||||||
|
for _, l := range ev.static {
|
||||||
|
if l.Key() == key {
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, l := range ev.dynamic {
|
||||||
|
if l.Key() == key {
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return label.Label{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeEvent(static [3]label.Label, labels []label.Label) Event {
|
||||||
|
return Event{
|
||||||
|
static: static,
|
||||||
|
dynamic: labels,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloneEvent event returns a copy of the event with the time adjusted to at.
|
||||||
|
func CloneEvent(ev Event, at time.Time) Event {
|
||||||
|
ev.at = at
|
||||||
|
return ev
|
||||||
|
}
|
70
vendor/golang.org/x/tools/internal/event/core/export.go
generated
vendored
Normal file
70
vendor/golang.org/x/tools/internal/event/core/export.go
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 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 core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/event/label"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Exporter is a function that handles events.
|
||||||
|
// It may return a modified context and event.
|
||||||
|
type Exporter func(context.Context, Event, label.Map) context.Context
|
||||||
|
|
||||||
|
var (
|
||||||
|
exporter unsafe.Pointer
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetExporter sets the global exporter function that handles all events.
|
||||||
|
// The exporter is called synchronously from the event call site, so it should
|
||||||
|
// return quickly so as not to hold up user code.
|
||||||
|
func SetExporter(e Exporter) {
|
||||||
|
p := unsafe.Pointer(&e)
|
||||||
|
if e == nil {
|
||||||
|
// &e is always valid, and so p is always valid, but for the early abort
|
||||||
|
// of ProcessEvent to be efficient it needs to make the nil check on the
|
||||||
|
// pointer without having to dereference it, so we make the nil function
|
||||||
|
// also a nil pointer
|
||||||
|
p = nil
|
||||||
|
}
|
||||||
|
atomic.StorePointer(&exporter, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// deliver is called to deliver an event to the supplied exporter.
|
||||||
|
// it will fill in the time.
|
||||||
|
func deliver(ctx context.Context, exporter Exporter, ev Event) context.Context {
|
||||||
|
// add the current time to the event
|
||||||
|
ev.at = time.Now()
|
||||||
|
// hand the event off to the current exporter
|
||||||
|
return exporter(ctx, ev, ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export is called to deliver an event to the global exporter if set.
|
||||||
|
func Export(ctx context.Context, ev Event) context.Context {
|
||||||
|
// get the global exporter and abort early if there is not one
|
||||||
|
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
|
||||||
|
if exporterPtr == nil {
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
return deliver(ctx, *exporterPtr, ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportPair is called to deliver a start event to the supplied exporter.
|
||||||
|
// It also returns a function that will deliver the end event to the same
|
||||||
|
// exporter.
|
||||||
|
// It will fill in the time.
|
||||||
|
func ExportPair(ctx context.Context, begin, end Event) (context.Context, func()) {
|
||||||
|
// get the global exporter and abort early if there is not one
|
||||||
|
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
|
||||||
|
if exporterPtr == nil {
|
||||||
|
return ctx, func() {}
|
||||||
|
}
|
||||||
|
ctx = deliver(ctx, *exporterPtr, begin)
|
||||||
|
return ctx, func() { deliver(ctx, *exporterPtr, end) }
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user