upload/azure: use the new azure/azblob API on Fedora 33+ & RHEL

Fedora 33 and rawhide got an updated version of the azblob library. Sadly, it
introduced a non-compatible API change. This commit does the same thing as
a67baf5a did for kolo/xmlrpc:

We now have two wrappers around the affected part of the API. Fedora 32 uses
the wrapper around the old API, whereas Fedora 33 and 34 (and RHEL with its
vendored deps) use the wrapper around the new API. The switch is implemented
using go build flags and spec file magic.

See a67baf5a for more thoughts.

Also, there's v0.11.1-0.20201209121048-6df5d9af221d in go.mod, why?

The maintainers of azblob probably tagged a wrong commit with v0.12.0 which
breaks go. The long v0.11.1-.* version is basically the proper v0.12.0 commit.
See https://github.com/Azure/azure-storage-blob-go/issues/236 for more
information.

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
This commit is contained in:
Ondřej Budai 2021-01-05 13:44:27 +01:00 committed by Ondřej Budai
parent 946a0b425a
commit 1b05192298
214 changed files with 25345 additions and 98843 deletions

5
go.mod
View file

@ -4,7 +4,7 @@ go 1.13
require ( require (
github.com/Azure/azure-sdk-for-go v41.3.0+incompatible github.com/Azure/azure-sdk-for-go v41.3.0+incompatible
github.com/Azure/azure-storage-blob-go v0.8.0 github.com/Azure/azure-storage-blob-go v0.11.1-0.20201209121048-6df5d9af221d
github.com/Azure/go-autorest/autorest v0.10.0 github.com/Azure/go-autorest/autorest v0.10.0
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 github.com/Azure/go-autorest/autorest/azure/auth v0.4.2
github.com/Azure/go-autorest/autorest/to v0.3.0 // indirect github.com/Azure/go-autorest/autorest/to v0.3.0 // indirect
@ -22,10 +22,9 @@ require (
github.com/julienschmidt/httprouter v1.2.0 github.com/julienschmidt/httprouter v1.2.0
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b
github.com/labstack/echo/v4 v4.1.11 github.com/labstack/echo/v4 v4.1.11
github.com/pkg/errors v0.9.1 // indirect
github.com/stretchr/testify v1.5.1 github.com/stretchr/testify v1.5.1
github.com/ubccr/kerby v0.0.0-20170626144437-201a958fc453 github.com/ubccr/kerby v0.0.0-20170626144437-201a958fc453
github.com/vmware/govmomi v0.23.0 github.com/vmware/govmomi v0.23.0
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 golang.org/x/sys v0.0.0-20200828194041-157a740278f4
) )

33
go.sum
View file

@ -1,9 +1,11 @@
github.com/Azure/azure-pipeline-go v0.2.1 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZOMdj5HYo= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
github.com/Azure/azure-sdk-for-go v41.3.0+incompatible h1:W5px0x53aa47nmIAuF1XWR1ZzFuUnkJBGUuzHnNp+Nk= github.com/Azure/azure-sdk-for-go v41.3.0+incompatible h1:W5px0x53aa47nmIAuF1XWR1ZzFuUnkJBGUuzHnNp+Nk=
github.com/Azure/azure-sdk-for-go v41.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v41.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-storage-blob-go v0.8.0 h1:53qhf0Oxa0nOjgbDeeYPUeyiNmafAFEY95rZLK0Tj6o= github.com/Azure/azure-storage-blob-go v0.11.1-0.20201209121048-6df5d9af221d h1:YEjZNZ0HS7ITX+BJ7wUXtTk6GXM3g8xftaqQ94XU/cs=
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= github.com/Azure/azure-storage-blob-go v0.11.1-0.20201209121048-6df5d9af221d/go.mod h1:A0u4VjtpgZJ7Y7um/+ix2DHBuEKFC6sEIlj0xc13a4Q=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest v0.9.3 h1:OZEIaBbMdUE/Js+BQKlpO81XlISgipr6yDJ+PSwsgi4= github.com/Azure/go-autorest/autorest v0.9.3 h1:OZEIaBbMdUE/Js+BQKlpO81XlISgipr6yDJ+PSwsgi4=
@ -15,6 +17,8 @@ github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0= github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0=
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.9.2 h1:Aze/GQeAN1RRbGmnUJvUj+tFGBzFdIg3293/A9rbxC4=
github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE=
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwpKNMpV+/FTWjwEbuPD495Tk= github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwpKNMpV+/FTWjwEbuPD495Tk=
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM=
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U= github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U=
@ -22,10 +26,14 @@ github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc=
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8= github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8=
github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
github.com/Azure/go-autorest/autorest/validation v0.2.0 h1:15vMO4y76dehZSq7pAaOLQxC6dZYsSrj2GQpflyM/L4= github.com/Azure/go-autorest/autorest/validation v0.2.0 h1:15vMO4y76dehZSq7pAaOLQxC6dZYsSrj2GQpflyM/L4=
@ -34,6 +42,8 @@ github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1Gn
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aws/aws-sdk-go v1.25.37 h1:gBtB/F3dophWpsUQKN/Kni+JzYEH2mGHF4hWNtfED1w= github.com/aws/aws-sdk-go v1.25.37 h1:gBtB/F3dophWpsUQKN/Kni+JzYEH2mGHF4hWNtfED1w=
@ -89,14 +99,16 @@ github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIG
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149 h1:HfxbT6/JcvIljmERptWhwa8XzP7H3T+Z2N26gTsaDaA= github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -123,6 +135,8 @@ golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -136,10 +150,11 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo= golang.org/x/sys v0.0.0-20200828194041-157a740278f4 h1:kCCpuwSAoYJPkNc6x0xT9yTtV4oKtARo4RGBQWOfg9E=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -152,6 +167,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=

View file

@ -82,7 +82,7 @@ func UploadImage(credentials Credentials, metadata ImageMetadata, fileName strin
} }
// Create page blob URL. Page blob is required for VM images // Create page blob URL. Page blob is required for VM images
blobURL := containerURL.NewPageBlobURL(metadata.ImageName) blobURL := newPageBlobURL(containerURL, metadata.ImageName)
_, err = blobURL.Create(ctx, stat.Size(), 0, azblob.BlobHTTPHeaders{}, azblob.Metadata{}, azblob.BlobAccessConditions{}) _, err = blobURL.Create(ctx, stat.Size(), 0, azblob.BlobHTTPHeaders{}, azblob.Metadata{}, azblob.BlobAccessConditions{})
if err != nil { if err != nil {
return fmt.Errorf("cannot create the blob URL: %v", err) return fmt.Errorf("cannot create the blob URL: %v", err)

View file

@ -0,0 +1,46 @@
// +build !azblob_oldapi
//
// This file provides a wrapper around azure/azblob PageBlobURL.
//
// Version 0.12 of the azblob library changed the API of PageBlobURL.
// (see https://github.com/Azure/azure-storage-blob-go/blob/master/BreakingChanges.md)
// This means that different APIs are available in Fedora 32 and 33 (it does
// not matter for RHEL as it uses vendored libraries).
// This wrapper allows us to use both azblob's APIs using buildflags.
//
// This file is a wrapper for azblob equal or newer than 0.12.
package azure
import (
"context"
"io"
"github.com/Azure/azure-storage-blob-go/azblob"
)
type PageBlobURL struct {
impl azblob.PageBlobURL
}
func newPageBlobURL(containerURL azblob.ContainerURL, blobName string) PageBlobURL {
pageblobURL := containerURL.NewPageBlobURL(blobName)
return PageBlobURL{pageblobURL}
}
func (pb PageBlobURL) Create(ctx context.Context, size int64, sequenceNumber int64, h azblob.BlobHTTPHeaders, metadata azblob.Metadata, ac azblob.BlobAccessConditions) (*azblob.PageBlobCreateResponse, error) {
return pb.impl.Create(ctx, size, sequenceNumber, h, metadata, ac, azblob.PremiumPageBlobAccessTierNone, azblob.BlobTagsMap{}, azblob.ClientProvidedKeyOptions{})
}
func (pb PageBlobURL) SetHTTPHeaders(ctx context.Context, h azblob.BlobHTTPHeaders, ac azblob.BlobAccessConditions) (*azblob.BlobSetHTTPHeadersResponse, error) {
return pb.impl.SetHTTPHeaders(ctx, h, ac)
}
func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.ReadSeeker, ac azblob.PageBlobAccessConditions, transactionalMD5 []byte) (*azblob.PageBlobUploadPagesResponse, error) {
return pb.impl.UploadPages(ctx, offset, body, ac, transactionalMD5, azblob.ClientProvidedKeyOptions{})
}
func (pb PageBlobURL) GetProperties(ctx context.Context, ac azblob.BlobAccessConditions) (*azblob.BlobGetPropertiesResponse, error) {
return pb.impl.GetProperties(ctx, ac, azblob.ClientProvidedKeyOptions{})
}

View file

@ -0,0 +1,46 @@
// +build azblob_oldapi
//
// This file provides a wrapper around azure/azblob PageBlobURL.
//
// Version 0.12 of the azblob library changed the API of PageBlobURL.
// (see https://github.com/Azure/azure-storage-blob-go/blob/master/BreakingChanges.md)
// This means that different APIs are available in Fedora 32 and 33 (it does
// not matter for RHEL as it uses vendored libraries).
// This wrapper allows us to use both azblob's APIs using buildflags.
//
// This file is a wrapper for azblob older than 0.12.
package azure
import (
"context"
"io"
"github.com/Azure/azure-storage-blob-go/azblob"
)
type PageBlobURL struct {
impl azblob.PageBlobURL
}
func newPageBlobURL(containerURL azblob.ContainerURL, blobName string) PageBlobURL {
pageblobURL := containerURL.NewPageBlobURL(blobName)
return PageBlobURL{pageblobURL}
}
func (pb PageBlobURL) Create(ctx context.Context, size int64, sequenceNumber int64, h azblob.BlobHTTPHeaders, metadata azblob.Metadata, ac azblob.BlobAccessConditions) (*azblob.PageBlobCreateResponse, error) {
return pb.impl.Create(ctx, size, sequenceNumber, h, metadata, ac)
}
func (pb PageBlobURL) SetHTTPHeaders(ctx context.Context, h azblob.BlobHTTPHeaders, ac azblob.BlobAccessConditions) (*azblob.BlobSetHTTPHeadersResponse, error) {
return pb.impl.SetHTTPHeaders(ctx, h, ac)
}
func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.ReadSeeker, ac azblob.PageBlobAccessConditions, transactionalMD5 []byte) (*azblob.PageBlobUploadPagesResponse, error) {
return pb.impl.UploadPages(ctx, offset, body, ac, transactionalMD5)
}
func (pb PageBlobURL) GetProperties(ctx context.Context, ac azblob.BlobAccessConditions) (*azblob.BlobGetPropertiesResponse, error) {
return pb.impl.GetProperties(ctx, ac)
}

View file

@ -91,17 +91,19 @@ Obsoletes: osbuild-composer-koji <= 23
%endif %endif
%if 0%{?fedora} && 0%{?fedora} <= 32 %if 0%{?fedora} && 0%{?fedora} <= 32
# Fedora 32 and older ships a different kolo/xmlrpc API. We cannot specify # Fedora 32 and older ships different kolo/xmlrpc and azure/azblob APIs. We
# build tags in gobuild macro because the macro itself specifies build tags. # cannot specify build tags in gobuild macro because the macro itself
# and -tags argument cannot be used more than once. # specifies build tags and -tags argument cannot be used more than once.
# Therefore, this ugly hack with build tags switcharoo is required. # Therefore, this ugly hack with build tags switcharoo is required.
# Remove when F32 is EOL. # Remove when F32 is EOL.
# Remove the build constraint from the wrapper of the old API # Remove the build constraint from the wrappers of the old APIs
sed -i "s$// +build kolo_xmlrpc_oldapi$// +build !kolo_xmlrpc_oldapi$" internal/upload/koji/xmlrpc-response-oldapi.go sed -i "s$// +build kolo_xmlrpc_oldapi$// +build !kolo_xmlrpc_oldapi$" internal/upload/koji/xmlrpc-response-oldapi.go
sed -i "s$// +build azblob_oldapi$// +build !azblob_oldapi$" internal/upload/azure/page_blob_url_oldapi.go
# Add a build constraint to the wrapper of the new API # Add a build constraint to the wrappers of the new APIs
sed -i "s$// +build !kolo_xmlrpc_oldapi$// +build kolo_xmlrpc_oldapi$" internal/upload/koji/xmlrpc-response.go sed -i "s$// +build !kolo_xmlrpc_oldapi$// +build kolo_xmlrpc_oldapi$" internal/upload/koji/xmlrpc-response.go
sed -i "s$// +build !azblob_oldapi$// +build azblob_oldapi$" internal/upload/azure/page_blob_url.go
%endif %endif
%build %build

View file

@ -49,6 +49,9 @@ func (e *ErrorNode) Error(msg string) string {
// Cause returns the error that preceded this error. // Cause returns the error that preceded this error.
func (e *ErrorNode) Cause() error { return e.cause } func (e *ErrorNode) Cause() error { return e.cause }
// Unwrap provides compatibility for Go 1.13 error chains.
func (e *ErrorNode) Unwrap() error { return e.cause }
// Temporary returns true if the error occurred due to a temporary condition. // Temporary returns true if the error occurred due to a temporary condition.
func (e ErrorNode) Temporary() bool { func (e ErrorNode) Temporary() bool {
type temporary interface { type temporary interface {

View file

@ -1,69 +0,0 @@
package azblob
import "sync/atomic"
// AtomicMorpherInt32 identifies a method passed to and invoked by the AtomicMorphInt32 function.
// The AtomicMorpher callback is passed a startValue and based on this value it returns
// what the new value should be and the result that AtomicMorph should return to its caller.
type atomicMorpherInt32 func(startVal int32) (val int32, morphResult interface{})
const targetAndMorpherMustNotBeNil = "target and morpher must not be nil"
// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function.
func atomicMorphInt32(target *int32, morpher atomicMorpherInt32) interface{} {
for {
currentVal := atomic.LoadInt32(target)
desiredVal, morphResult := morpher(currentVal)
if atomic.CompareAndSwapInt32(target, currentVal, desiredVal) {
return morphResult
}
}
}
// AtomicMorpherUint32 identifies a method passed to and invoked by the AtomicMorph function.
// The AtomicMorpher callback is passed a startValue and based on this value it returns
// what the new value should be and the result that AtomicMorph should return to its caller.
type atomicMorpherUint32 func(startVal uint32) (val uint32, morphResult interface{})
// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function.
func atomicMorphUint32(target *uint32, morpher atomicMorpherUint32) interface{} {
for {
currentVal := atomic.LoadUint32(target)
desiredVal, morphResult := morpher(currentVal)
if atomic.CompareAndSwapUint32(target, currentVal, desiredVal) {
return morphResult
}
}
}
// AtomicMorpherUint64 identifies a method passed to and invoked by the AtomicMorphUint64 function.
// The AtomicMorpher callback is passed a startValue and based on this value it returns
// what the new value should be and the result that AtomicMorph should return to its caller.
type atomicMorpherInt64 func(startVal int64) (val int64, morphResult interface{})
// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function.
func atomicMorphInt64(target *int64, morpher atomicMorpherInt64) interface{} {
for {
currentVal := atomic.LoadInt64(target)
desiredVal, morphResult := morpher(currentVal)
if atomic.CompareAndSwapInt64(target, currentVal, desiredVal) {
return morphResult
}
}
}
// AtomicMorpherUint64 identifies a method passed to and invoked by the AtomicMorphUint64 function.
// The AtomicMorpher callback is passed a startValue and based on this value it returns
// what the new value should be and the result that AtomicMorph should return to its caller.
type atomicMorpherUint64 func(startVal uint64) (val uint64, morphResult interface{})
// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function.
func atomicMorphUint64(target *uint64, morpher atomicMorpherUint64) interface{} {
for {
currentVal := atomic.LoadUint64(target)
desiredVal, morphResult := morpher(currentVal)
if atomic.CompareAndSwapUint64(target, currentVal, desiredVal) {
return morphResult
}
}
}

View file

@ -0,0 +1,24 @@
package azblob
import (
"errors"
)
type bytesWriter []byte
func newBytesWriter(b []byte) bytesWriter {
return b
}
func (c bytesWriter) WriteAt(b []byte, off int64) (int, error) {
if off >= int64(len(c)) || off < 0 {
return 0, errors.New("Offset value is out of range")
}
n := copy(c[int(off):], b)
if n < len(b) {
return n, errors.New("Not enough space for all bytes")
}
return n, nil
}

View file

@ -0,0 +1,237 @@
package azblob
import (
"bytes"
"context"
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"io"
"sync"
guuid "github.com/google/uuid"
)
// blockWriter provides methods to upload blocks that represent a file to a server and commit them.
// This allows us to provide a local implementation that fakes the server for hermetic testing.
type blockWriter interface {
StageBlock(context.Context, string, io.ReadSeeker, LeaseAccessConditions, []byte, ClientProvidedKeyOptions) (*BlockBlobStageBlockResponse, error)
CommitBlockList(context.Context, []string, BlobHTTPHeaders, Metadata, BlobAccessConditions, AccessTierType, BlobTagsMap, ClientProvidedKeyOptions) (*BlockBlobCommitBlockListResponse, error)
}
// copyFromReader copies a source io.Reader to blob storage using concurrent uploads.
// TODO(someone): The existing model provides a buffer size and buffer limit as limiting factors. The buffer size is probably
// useless other than needing to be above some number, as the network stack is going to hack up the buffer over some size. The
// max buffers is providing a cap on how much memory we use (by multiplying it times the buffer size) and how many go routines can upload
// at a time. I think having a single max memory dial would be more efficient. We can choose an internal buffer size that works
// well, 4 MiB or 8 MiB, and autoscale to as many goroutines within the memory limit. This gives a single dial to tweak and we can
// choose a max value for the memory setting based on internal transfers within Azure (which will give us the maximum throughput model).
// We can even provide a utility to dial this number in for customer networks to optimize their copies.
func copyFromReader(ctx context.Context, from io.Reader, to blockWriter, o UploadStreamToBlockBlobOptions) (*BlockBlobCommitBlockListResponse, error) {
o.defaults()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
cp := &copier{
ctx: ctx,
cancel: cancel,
reader: from,
to: to,
id: newID(),
o: o,
ch: make(chan copierChunk, 1),
errCh: make(chan error, 1),
buffers: sync.Pool{
New: func() interface{} {
return make([]byte, o.BufferSize)
},
},
}
// Starts the pools of concurrent writers.
cp.wg.Add(o.MaxBuffers)
for i := 0; i < o.MaxBuffers; i++ {
go cp.writer()
}
// Send all our chunks until we get an error.
var err error
for {
if err = cp.sendChunk(); err != nil {
break
}
}
// If the error is not EOF, then we have a problem.
if err != nil && !errors.Is(err, io.EOF) {
return nil, err
}
// Close out our upload.
if err := cp.close(); err != nil {
return nil, err
}
return cp.result, nil
}
// copier streams a file via chunks in parallel from a reader representing a file.
// Do not use directly, instead use copyFromReader().
type copier struct {
// ctx holds the context of a copier. This is normally a faux pas to store a Context in a struct. In this case,
// the copier has the lifetime of a function call, so its fine.
ctx context.Context
cancel context.CancelFunc
// reader is the source to be written to storage.
reader io.Reader
// to is the location we are writing our chunks to.
to blockWriter
id *id
o UploadStreamToBlockBlobOptions
// num is the current chunk we are on.
num int32
// ch is used to pass the next chunk of data from our reader to one of the writers.
ch chan copierChunk
// errCh is used to hold the first error from our concurrent writers.
errCh chan error
// wg provides a count of how many writers we are waiting to finish.
wg sync.WaitGroup
// buffers provides a pool of chunks that can be reused.
buffers sync.Pool
// result holds the final result from blob storage after we have submitted all chunks.
result *BlockBlobCommitBlockListResponse
}
type copierChunk struct {
buffer []byte
id string
}
// getErr returns an error by priority. First, if a function set an error, it returns that error. Next, if the Context has an error
// it returns that error. Otherwise it is nil. getErr supports only returning an error once per copier.
func (c *copier) getErr() error {
select {
case err := <-c.errCh:
return err
default:
}
return c.ctx.Err()
}
// sendChunk reads data from out internal reader, creates a chunk, and sends it to be written via a channel.
// sendChunk returns io.EOF when the reader returns an io.EOF or io.ErrUnexpectedEOF.
func (c *copier) sendChunk() error {
if err := c.getErr(); err != nil {
return err
}
buffer := c.buffers.Get().([]byte)
n, err := io.ReadFull(c.reader, buffer)
switch {
case err == nil && n == 0:
return nil
case err == nil:
c.ch <- copierChunk{
buffer: buffer[0:n],
id: c.id.next(),
}
return nil
case err != nil && (err == io.EOF || err == io.ErrUnexpectedEOF) && n == 0:
return io.EOF
}
if err == io.EOF || err == io.ErrUnexpectedEOF {
c.ch <- copierChunk{
buffer: buffer[0:n],
id: c.id.next(),
}
return io.EOF
}
if err := c.getErr(); err != nil {
return err
}
return err
}
// writer writes chunks sent on a channel.
func (c *copier) writer() {
defer c.wg.Done()
for chunk := range c.ch {
if err := c.write(chunk); err != nil {
if !errors.Is(err, context.Canceled) {
select {
case c.errCh <- err:
c.cancel()
default:
}
return
}
}
}
}
// write uploads a chunk to blob storage.
func (c *copier) write(chunk copierChunk) error {
defer c.buffers.Put(chunk.buffer)
if err := c.ctx.Err(); err != nil {
return err
}
_, err := c.to.StageBlock(c.ctx, chunk.id, bytes.NewReader(chunk.buffer), c.o.AccessConditions.LeaseAccessConditions, nil, c.o.ClientProvidedKeyOptions)
if err != nil {
return fmt.Errorf("write error: %w", err)
}
return nil
}
// close commits our blocks to blob storage and closes our writer.
func (c *copier) close() error {
close(c.ch)
c.wg.Wait()
if err := c.getErr(); err != nil {
return err
}
var err error
c.result, err = c.to.CommitBlockList(c.ctx, c.id.issued(), c.o.BlobHTTPHeaders, c.o.Metadata, c.o.AccessConditions, c.o.BlobAccessTier, c.o.BlobTagsMap, c.o.ClientProvidedKeyOptions)
return err
}
// id allows the creation of unique IDs based on UUID4 + an int32. This auto-increments.
type id struct {
u [64]byte
num uint32
all []string
}
// newID constructs a new id.
func newID() *id {
uu := guuid.New()
u := [64]byte{}
copy(u[:], uu[:])
return &id{u: u}
}
// next returns the next ID. This is not thread-safe.
func (id *id) next() string {
defer func() { id.num++ }()
binary.BigEndian.PutUint32((id.u[len(guuid.UUID{}):]), id.num)
str := base64.StdEncoding.EncodeToString(id.u[:])
id.all = append(id.all, str)
return str
}
// issued returns all ids that have been issued. This returned value shares the internal slice so it is not safe to modify the return.
// The value is only valid until the next time next() is called.
func (id *id) issued() []string {
return id.all
}

View file

@ -0,0 +1 @@
package azblob

View file

@ -55,24 +55,32 @@ type UploadToBlockBlobOptions struct {
// AccessConditions indicates the access conditions for the block blob. // AccessConditions indicates the access conditions for the block blob.
AccessConditions BlobAccessConditions AccessConditions BlobAccessConditions
// BlobAccessTier indicates the tier of blob
BlobAccessTier AccessTierType
// BlobTagsMap
BlobTagsMap BlobTagsMap
// ClientProvidedKeyOptions indicates the client provided key by name and/or by value to encrypt/decrypt data.
ClientProvidedKeyOptions ClientProvidedKeyOptions
// Parallelism indicates the maximum number of blocks to upload in parallel (0=default) // Parallelism indicates the maximum number of blocks to upload in parallel (0=default)
Parallelism uint16 Parallelism uint16
} }
// UploadBufferToBlockBlob uploads a buffer in blocks to a block blob. // uploadReaderAtToBlockBlob uploads a buffer in blocks to a block blob.
func UploadBufferToBlockBlob(ctx context.Context, b []byte, func uploadReaderAtToBlockBlob(ctx context.Context, reader io.ReaderAt, readerSize int64,
blockBlobURL BlockBlobURL, o UploadToBlockBlobOptions) (CommonResponse, error) { blockBlobURL BlockBlobURL, o UploadToBlockBlobOptions) (CommonResponse, error) {
bufferSize := int64(len(b))
if o.BlockSize == 0 { if o.BlockSize == 0 {
// If bufferSize > (BlockBlobMaxStageBlockBytes * BlockBlobMaxBlocks), then error // If bufferSize > (BlockBlobMaxStageBlockBytes * BlockBlobMaxBlocks), then error
if bufferSize > BlockBlobMaxStageBlockBytes*BlockBlobMaxBlocks { if readerSize > BlockBlobMaxStageBlockBytes*BlockBlobMaxBlocks {
return nil, errors.New("buffer is too large to upload to a block blob") return nil, errors.New("buffer is too large to upload to a block blob")
} }
// If bufferSize <= BlockBlobMaxUploadBlobBytes, then Upload should be used with just 1 I/O request // If bufferSize <= BlockBlobMaxUploadBlobBytes, then Upload should be used with just 1 I/O request
if bufferSize <= BlockBlobMaxUploadBlobBytes { if readerSize <= BlockBlobMaxUploadBlobBytes {
o.BlockSize = BlockBlobMaxUploadBlobBytes // Default if unspecified o.BlockSize = BlockBlobMaxUploadBlobBytes // Default if unspecified
} else { } else {
o.BlockSize = bufferSize / BlockBlobMaxBlocks // buffer / max blocks = block size to use all 50,000 blocks o.BlockSize = readerSize / BlockBlobMaxBlocks // buffer / max blocks = block size to use all 50,000 blocks
if o.BlockSize < BlobDefaultDownloadBlockSize { // If the block size is smaller than 4MB, round up to 4MB if o.BlockSize < BlobDefaultDownloadBlockSize { // If the block size is smaller than 4MB, round up to 4MB
o.BlockSize = BlobDefaultDownloadBlockSize o.BlockSize = BlobDefaultDownloadBlockSize
} }
@ -80,31 +88,31 @@ func UploadBufferToBlockBlob(ctx context.Context, b []byte,
} }
} }
if bufferSize <= BlockBlobMaxUploadBlobBytes { if readerSize <= BlockBlobMaxUploadBlobBytes {
// If the size can fit in 1 Upload call, do it this way // If the size can fit in 1 Upload call, do it this way
var body io.ReadSeeker = bytes.NewReader(b) var body io.ReadSeeker = io.NewSectionReader(reader, 0, readerSize)
if o.Progress != nil { if o.Progress != nil {
body = pipeline.NewRequestBodyProgress(body, o.Progress) body = pipeline.NewRequestBodyProgress(body, o.Progress)
} }
return blockBlobURL.Upload(ctx, body, o.BlobHTTPHeaders, o.Metadata, o.AccessConditions) return blockBlobURL.Upload(ctx, body, o.BlobHTTPHeaders, o.Metadata, o.AccessConditions, o.BlobAccessTier, o.BlobTagsMap, o.ClientProvidedKeyOptions)
} }
var numBlocks = uint16(((bufferSize - 1) / o.BlockSize) + 1) var numBlocks = uint16(((readerSize - 1) / o.BlockSize) + 1)
blockIDList := make([]string, numBlocks) // Base-64 encoded block IDs blockIDList := make([]string, numBlocks) // Base-64 encoded block IDs
progress := int64(0) progress := int64(0)
progressLock := &sync.Mutex{} progressLock := &sync.Mutex{}
err := DoBatchTransfer(ctx, BatchTransferOptions{ err := DoBatchTransfer(ctx, BatchTransferOptions{
OperationName: "UploadBufferToBlockBlob", OperationName: "uploadReaderAtToBlockBlob",
TransferSize: bufferSize, TransferSize: readerSize,
ChunkSize: o.BlockSize, ChunkSize: o.BlockSize,
Parallelism: o.Parallelism, Parallelism: o.Parallelism,
Operation: func(offset int64, count int64, ctx context.Context) error { Operation: func(offset int64, count int64, ctx context.Context) error {
// This function is called once per block. // This function is called once per block.
// It is passed this block's offset within the buffer and its count of bytes // It is passed this block's offset within the buffer and its count of bytes
// Prepare to read the proper block/section of the buffer // Prepare to read the proper block/section of the buffer
var body io.ReadSeeker = bytes.NewReader(b[offset : offset+count]) var body io.ReadSeeker = io.NewSectionReader(reader, offset, count)
blockNum := offset / o.BlockSize blockNum := offset / o.BlockSize
if o.Progress != nil { if o.Progress != nil {
blockProgress := int64(0) blockProgress := int64(0)
@ -122,7 +130,7 @@ func UploadBufferToBlockBlob(ctx context.Context, b []byte,
// Block IDs are unique values to avoid issue if 2+ clients are uploading blocks // Block IDs are unique values to avoid issue if 2+ clients are uploading blocks
// at the same time causing PutBlockList to get a mix of blocks from all the clients. // at the same time causing PutBlockList to get a mix of blocks from all the clients.
blockIDList[blockNum] = base64.StdEncoding.EncodeToString(newUUID().bytes()) blockIDList[blockNum] = base64.StdEncoding.EncodeToString(newUUID().bytes())
_, err := blockBlobURL.StageBlock(ctx, blockIDList[blockNum], body, o.AccessConditions.LeaseAccessConditions, nil) _, err := blockBlobURL.StageBlock(ctx, blockIDList[blockNum], body, o.AccessConditions.LeaseAccessConditions, nil, o.ClientProvidedKeyOptions)
return err return err
}, },
}) })
@ -130,7 +138,13 @@ func UploadBufferToBlockBlob(ctx context.Context, b []byte,
return nil, err return nil, err
} }
// All put blocks were successful, call Put Block List to finalize the blob // All put blocks were successful, call Put Block List to finalize the blob
return blockBlobURL.CommitBlockList(ctx, blockIDList, o.BlobHTTPHeaders, o.Metadata, o.AccessConditions) return blockBlobURL.CommitBlockList(ctx, blockIDList, o.BlobHTTPHeaders, o.Metadata, o.AccessConditions, o.BlobAccessTier, o.BlobTagsMap, o.ClientProvidedKeyOptions)
}
// UploadBufferToBlockBlob uploads a buffer in blocks to a block blob.
func UploadBufferToBlockBlob(ctx context.Context, b []byte,
blockBlobURL BlockBlobURL, o UploadToBlockBlobOptions) (CommonResponse, error) {
return uploadReaderAtToBlockBlob(ctx, bytes.NewReader(b), int64(len(b)), blockBlobURL, o)
} }
// UploadFileToBlockBlob uploads a file in blocks to a block blob. // UploadFileToBlockBlob uploads a file in blocks to a block blob.
@ -141,15 +155,7 @@ func UploadFileToBlockBlob(ctx context.Context, file *os.File,
if err != nil { if err != nil {
return nil, err return nil, err
} }
m := mmf{} // Default to an empty slice; used for 0-size file return uploadReaderAtToBlockBlob(ctx, file, stat.Size(), blockBlobURL, o)
if stat.Size() != 0 {
m, err = newMMF(file, false, 0, int(stat.Size()))
if err != nil {
return nil, err
}
defer m.unmap()
}
return UploadBufferToBlockBlob(ctx, m, blockBlobURL, o)
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -167,6 +173,9 @@ type DownloadFromBlobOptions struct {
// AccessConditions indicates the access conditions used when making HTTP GET requests against the blob. // AccessConditions indicates the access conditions used when making HTTP GET requests against the blob.
AccessConditions BlobAccessConditions AccessConditions BlobAccessConditions
// ClientProvidedKeyOptions indicates the client provided key by name and/or by value to encrypt/decrypt data.
ClientProvidedKeyOptions ClientProvidedKeyOptions
// Parallelism indicates the maximum number of blocks to download in parallel (0=default) // Parallelism indicates the maximum number of blocks to download in parallel (0=default)
Parallelism uint16 Parallelism uint16
@ -174,9 +183,9 @@ type DownloadFromBlobOptions struct {
RetryReaderOptionsPerBlock RetryReaderOptions RetryReaderOptionsPerBlock RetryReaderOptions
} }
// downloadBlobToBuffer downloads an Azure blob to a buffer with parallel. // downloadBlobToWriterAt downloads an Azure blob to a buffer with parallel.
func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64, func downloadBlobToWriterAt(ctx context.Context, blobURL BlobURL, offset int64, count int64,
b []byte, o DownloadFromBlobOptions, initialDownloadResponse *DownloadResponse) error { writer io.WriterAt, o DownloadFromBlobOptions, initialDownloadResponse *DownloadResponse) error {
if o.BlockSize == 0 { if o.BlockSize == 0 {
o.BlockSize = BlobDefaultDownloadBlockSize o.BlockSize = BlobDefaultDownloadBlockSize
} }
@ -186,7 +195,7 @@ func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, co
count = initialDownloadResponse.ContentLength() - offset // if we have the length, use it count = initialDownloadResponse.ContentLength() - offset // if we have the length, use it
} else { } else {
// If we don't have the length at all, get it // If we don't have the length at all, get it
dr, err := blobURL.Download(ctx, 0, CountToEnd, o.AccessConditions, false) dr, err := blobURL.Download(ctx, 0, CountToEnd, o.AccessConditions, false, o.ClientProvidedKeyOptions)
if err != nil { if err != nil {
return err return err
} }
@ -194,17 +203,22 @@ func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, co
} }
} }
if count <= 0 {
// The file is empty, there is nothing to download.
return nil
}
// Prepare and do parallel download. // Prepare and do parallel download.
progress := int64(0) progress := int64(0)
progressLock := &sync.Mutex{} progressLock := &sync.Mutex{}
err := DoBatchTransfer(ctx, BatchTransferOptions{ err := DoBatchTransfer(ctx, BatchTransferOptions{
OperationName: "downloadBlobToBuffer", OperationName: "downloadBlobToWriterAt",
TransferSize: count, TransferSize: count,
ChunkSize: o.BlockSize, ChunkSize: o.BlockSize,
Parallelism: o.Parallelism, Parallelism: o.Parallelism,
Operation: func(chunkStart int64, count int64, ctx context.Context) error { Operation: func(chunkStart int64, count int64, ctx context.Context) error {
dr, err := blobURL.Download(ctx, chunkStart+offset, count, o.AccessConditions, false) dr, err := blobURL.Download(ctx, chunkStart+offset, count, o.AccessConditions, false, o.ClientProvidedKeyOptions)
if err != nil { if err != nil {
return err return err
} }
@ -222,7 +236,7 @@ func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, co
progressLock.Unlock() progressLock.Unlock()
}) })
} }
_, err = io.ReadFull(body, b[chunkStart:chunkStart+count]) _, err = io.Copy(newSectionWriter(writer, chunkStart, count), body)
body.Close() body.Close()
return err return err
}, },
@ -237,7 +251,7 @@ func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, co
// Offset and count are optional, pass 0 for both to download the entire blob. // Offset and count are optional, pass 0 for both to download the entire blob.
func DownloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64, func DownloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64,
b []byte, o DownloadFromBlobOptions) error { b []byte, o DownloadFromBlobOptions) error {
return downloadBlobToBuffer(ctx, blobURL, offset, count, b, o, nil) return downloadBlobToWriterAt(ctx, blobURL, offset, count, newBytesWriter(b), o, nil)
} }
// DownloadBlobToFile downloads an Azure blob to a local file. // DownloadBlobToFile downloads an Azure blob to a local file.
@ -250,7 +264,7 @@ func DownloadBlobToFile(ctx context.Context, blobURL BlobURL, offset int64, coun
if count == CountToEnd { if count == CountToEnd {
// Try to get Azure blob's size // Try to get Azure blob's size
props, err := blobURL.GetProperties(ctx, o.AccessConditions) props, err := blobURL.GetProperties(ctx, o.AccessConditions, o.ClientProvidedKeyOptions)
if err != nil { if err != nil {
return err return err
} }
@ -271,13 +285,7 @@ func DownloadBlobToFile(ctx context.Context, blobURL BlobURL, offset int64, coun
} }
if size > 0 { if size > 0 {
// 3. Set mmap and call downloadBlobToBuffer. return downloadBlobToWriterAt(ctx, blobURL, offset, size, file, o, nil)
m, err := newMMF(file, true, 0, int(size))
if err != nil {
return err
}
defer m.unmap()
return downloadBlobToBuffer(ctx, blobURL, offset, size, m, o, nil)
} else { // if the blob's size is 0, there is no need in downloading it } else { // if the blob's size is 0, there is no need in downloading it
return nil return nil
} }
@ -301,6 +309,10 @@ func DoBatchTransfer(ctx context.Context, o BatchTransferOptions) error {
return errors.New("ChunkSize cannot be 0") return errors.New("ChunkSize cannot be 0")
} }
if o.Parallelism == 0 {
o.Parallelism = 5 // default Parallelism
}
// Prepare and do parallel operations. // Prepare and do parallel operations.
numChunks := uint16(((o.TransferSize - 1) / o.ChunkSize) + 1) numChunks := uint16(((o.TransferSize - 1) / o.ChunkSize) + 1)
operationChannel := make(chan func() error, o.Parallelism) // Create the channel that release 'Parallelism' goroutines concurrently operationChannel := make(chan func() error, o.Parallelism) // Create the channel that release 'Parallelism' goroutines concurrently
@ -309,9 +321,6 @@ func DoBatchTransfer(ctx context.Context, o BatchTransferOptions) error {
defer cancel() defer cancel()
// Create the goroutines that process each operation (in parallel). // Create the goroutines that process each operation (in parallel).
if o.Parallelism == 0 {
o.Parallelism = 5 // default Parallelism
}
for g := uint16(0); g < o.Parallelism; g++ { for g := uint16(0); g < o.Parallelism; g++ {
//grIndex := g //grIndex := g
go func() { go func() {
@ -352,192 +361,47 @@ func DoBatchTransfer(ctx context.Context, o BatchTransferOptions) error {
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
const _1MiB = 1024 * 1024
type UploadStreamToBlockBlobOptions struct { type UploadStreamToBlockBlobOptions struct {
BufferSize int // BufferSize sizes the buffer used to read data from source. If < 1 MiB, defaults to 1 MiB.
MaxBuffers int BufferSize int
BlobHTTPHeaders BlobHTTPHeaders // MaxBuffers defines the number of simultaneous uploads will be performed to upload the file.
Metadata Metadata MaxBuffers int
AccessConditions BlobAccessConditions BlobHTTPHeaders BlobHTTPHeaders
Metadata Metadata
AccessConditions BlobAccessConditions
BlobAccessTier AccessTierType
BlobTagsMap BlobTagsMap
ClientProvidedKeyOptions ClientProvidedKeyOptions
} }
func (u *UploadStreamToBlockBlobOptions) defaults() {
if u.MaxBuffers == 0 {
u.MaxBuffers = 1
}
if u.BufferSize < _1MiB {
u.BufferSize = _1MiB
}
}
// UploadStreamToBlockBlob copies the file held in io.Reader to the Blob at blockBlobURL.
// A Context deadline or cancellation will cause this to error.
func UploadStreamToBlockBlob(ctx context.Context, reader io.Reader, blockBlobURL BlockBlobURL, func UploadStreamToBlockBlob(ctx context.Context, reader io.Reader, blockBlobURL BlockBlobURL,
o UploadStreamToBlockBlobOptions) (CommonResponse, error) { o UploadStreamToBlockBlobOptions) (CommonResponse, error) {
result, err := uploadStream(ctx, reader, o.defaults()
UploadStreamOptions{BufferSize: o.BufferSize, MaxBuffers: o.MaxBuffers},
&uploadStreamToBlockBlobOptions{b: blockBlobURL, o: o, blockIDPrefix: newUUID()}) result, err := copyFromReader(ctx, reader, blockBlobURL, o)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return result.(CommonResponse), nil
} return result, nil
type uploadStreamToBlockBlobOptions struct {
b BlockBlobURL
o UploadStreamToBlockBlobOptions
blockIDPrefix uuid // UUID used with all blockIDs
maxBlockNum uint32 // defaults to 0
firstBlock []byte // Used only if maxBlockNum is 0
}
func (t *uploadStreamToBlockBlobOptions) start(ctx context.Context) (interface{}, error) {
return nil, nil
}
func (t *uploadStreamToBlockBlobOptions) chunk(ctx context.Context, num uint32, buffer []byte) error {
if num == 0 {
t.firstBlock = buffer
// If whole payload fits in 1 block, don't stage it; End will upload it with 1 I/O operation
// If the payload is exactly the same size as the buffer, there may be more content coming in.
if len(buffer) < t.o.BufferSize {
return nil
}
}
// Else, upload a staged block...
atomicMorphUint32(&t.maxBlockNum, func(startVal uint32) (val uint32, morphResult interface{}) {
// Atomically remember (in t.numBlocks) the maximum block num we've ever seen
if startVal < num {
return num, nil
}
return startVal, nil
})
blockID := newUuidBlockID(t.blockIDPrefix).WithBlockNumber(num).ToBase64()
_, err := t.b.StageBlock(ctx, blockID, bytes.NewReader(buffer), LeaseAccessConditions{}, nil)
return err
}
func (t *uploadStreamToBlockBlobOptions) end(ctx context.Context) (interface{}, error) {
// If the first block had the exact same size as the buffer
// we would have staged it as a block thinking that there might be more data coming
if t.maxBlockNum == 0 && len(t.firstBlock) != t.o.BufferSize {
// If whole payload fits in 1 block (block #0), upload it with 1 I/O operation
return t.b.Upload(ctx, bytes.NewReader(t.firstBlock),
t.o.BlobHTTPHeaders, t.o.Metadata, t.o.AccessConditions)
}
// Multiple blocks staged, commit them all now
blockID := newUuidBlockID(t.blockIDPrefix)
blockIDs := make([]string, t.maxBlockNum+1)
for bn := uint32(0); bn <= t.maxBlockNum; bn++ {
blockIDs[bn] = blockID.WithBlockNumber(bn).ToBase64()
}
return t.b.CommitBlockList(ctx, blockIDs, t.o.BlobHTTPHeaders, t.o.Metadata, t.o.AccessConditions)
}
////////////////////////////////////////////////////////////////////////////////////////////////////
type iTransfer interface {
start(ctx context.Context) (interface{}, error)
chunk(ctx context.Context, num uint32, buffer []byte) error
end(ctx context.Context) (interface{}, error)
} }
// UploadStreamOptions (defunct) was used internally. This will be removed or made private in a future version.
type UploadStreamOptions struct { type UploadStreamOptions struct {
MaxBuffers int
BufferSize int BufferSize int
} MaxBuffers int
type firstErr struct {
lock sync.Mutex
finalError error
}
func (fe *firstErr) set(err error) {
fe.lock.Lock()
if fe.finalError == nil {
fe.finalError = err
}
fe.lock.Unlock()
}
func (fe *firstErr) get() (err error) {
fe.lock.Lock()
err = fe.finalError
fe.lock.Unlock()
return
}
func uploadStream(ctx context.Context, reader io.Reader, o UploadStreamOptions, t iTransfer) (interface{}, error) {
firstErr := firstErr{}
ctx, cancel := context.WithCancel(ctx) // New context so that any failure cancels everything
defer cancel()
wg := sync.WaitGroup{} // Used to know when all outgoing messages have finished processing
type OutgoingMsg struct {
chunkNum uint32
buffer []byte
}
// Create a channel to hold the buffers usable for incoming datsa
incoming := make(chan []byte, o.MaxBuffers)
outgoing := make(chan OutgoingMsg, o.MaxBuffers) // Channel holding outgoing buffers
if result, err := t.start(ctx); err != nil {
return result, err
}
numBuffers := 0 // The number of buffers & out going goroutines created so far
injectBuffer := func() {
// For each Buffer, create it and a goroutine to upload it
incoming <- make([]byte, o.BufferSize) // Add the new buffer to the incoming channel so this goroutine can from the reader into it
numBuffers++
go func() {
for outgoingMsg := range outgoing {
// Upload the outgoing buffer
err := t.chunk(ctx, outgoingMsg.chunkNum, outgoingMsg.buffer)
wg.Done() // Indicate this buffer was sent
if nil != err {
// NOTE: finalErr could be assigned to multiple times here which is OK,
// some error will be returned.
firstErr.set(err)
cancel()
}
incoming <- outgoingMsg.buffer // The goroutine reading from the stream can reuse this buffer now
}
}()
}
injectBuffer() // Create our 1st buffer & outgoing goroutine
// This goroutine grabs a buffer, reads from the stream into the buffer,
// and inserts the buffer into the outgoing channel to be uploaded
for c := uint32(0); true; c++ { // Iterate once per chunk
var buffer []byte
if numBuffers < o.MaxBuffers {
select {
// We're not at max buffers, see if a previously-created buffer is available
case buffer = <-incoming:
break
default:
// No buffer available; inject a new buffer & go routine to process it
injectBuffer()
buffer = <-incoming // Grab the just-injected buffer
}
} else {
// We are at max buffers, block until we get to reuse one
buffer = <-incoming
}
n, err := io.ReadFull(reader, buffer)
if err != nil { // Less than len(buffer) bytes were read
buffer = buffer[:n] // Make slice match the # of read bytes
}
if len(buffer) > 0 {
// Buffer not empty, upload it
wg.Add(1) // We're posting a buffer to be sent
outgoing <- OutgoingMsg{chunkNum: c, buffer: buffer}
}
if err != nil { // The reader is done, no more outgoing buffers
if err == io.EOF || err == io.ErrUnexpectedEOF {
err = nil // This function does NOT return an error if io.ReadFull returns io.EOF or io.ErrUnexpectedEOF
} else {
firstErr.set(err)
}
break
}
}
// NOTE: Don't close the incoming channel because the outgoing goroutines post buffers into it when they are done
close(outgoing) // Make all the outgoing goroutines terminate when this channel is empty
wg.Wait() // Wait for all pending outgoing messages to complete
err := firstErr.get()
if err == nil {
// If no error, after all blocks uploaded, commit them to the blob & return the result
return t.end(ctx)
}
return nil, err
} }

View file

@ -8,6 +8,7 @@ import (
const ( const (
snapshot = "snapshot" snapshot = "snapshot"
versionId = "versionid"
SnapshotTimeFormat = "2006-01-02T15:04:05.0000000Z07:00" SnapshotTimeFormat = "2006-01-02T15:04:05.0000000Z07:00"
) )
@ -23,6 +24,7 @@ type BlobURLParts struct {
Snapshot string // "" if not a snapshot Snapshot string // "" if not a snapshot
SAS SASQueryParameters SAS SASQueryParameters
UnparsedParams string UnparsedParams string
VersionID string // "" if not versioning enabled
} }
// IPEndpointStyleInfo is used for IP endpoint style URL when working with Azure storage emulator. // IPEndpointStyleInfo is used for IP endpoint style URL when working with Azure storage emulator.
@ -85,12 +87,20 @@ func NewBlobURLParts(u url.URL) BlobURLParts {
// Convert the query parameters to a case-sensitive map & trim whitespace // Convert the query parameters to a case-sensitive map & trim whitespace
paramsMap := u.Query() paramsMap := u.Query()
up.Snapshot = "" // Assume no snapshot up.Snapshot = "" // Assume no snapshot
up.VersionID = "" // Assume no versionID
if snapshotStr, ok := caseInsensitiveValues(paramsMap).Get(snapshot); ok { if snapshotStr, ok := caseInsensitiveValues(paramsMap).Get(snapshot); ok {
up.Snapshot = snapshotStr[0] up.Snapshot = snapshotStr[0]
// If we recognized the query parameter, remove it from the map // If we recognized the query parameter, remove it from the map
delete(paramsMap, snapshot) delete(paramsMap, snapshot)
} }
if versionIDs, ok := caseInsensitiveValues(paramsMap).Get(versionId); ok {
up.VersionID = versionIDs[0]
// If we recognized the query parameter, remove it from the map
delete(paramsMap, versionId) // delete "versionid" from paramsMap
delete(paramsMap, "versionId") // delete "versionId" from paramsMap
}
up.SAS = newSASQueryParameters(paramsMap, true) up.SAS = newSASQueryParameters(paramsMap, true)
up.UnparsedParams = paramsMap.Encode() up.UnparsedParams = paramsMap.Encode()
return up return up
@ -136,6 +146,15 @@ func (up BlobURLParts) URL() url.URL {
} }
rawQuery += snapshot + "=" + up.Snapshot rawQuery += snapshot + "=" + up.Snapshot
} }
// Concatenate blob version id query parameter (if it exists)
if up.VersionID != "" {
if len(rawQuery) > 0 {
rawQuery += "&"
}
rawQuery += versionId + "=" + up.VersionID
}
sas := up.SAS.Encode() sas := up.SAS.Encode()
if sas != "" { if sas != "" {
if len(rawQuery) > 0 { if len(rawQuery) > 0 {

View file

@ -0,0 +1,33 @@
package azblob
// ClientProvidedKeyOptions contains headers which may be be specified from service version 2019-02-02
// or higher to encrypts the data on the service-side with the given key. Use of customer-provided keys
// must be done over HTTPS. As the encryption key itself is provided in the request, a secure connection
// must be established to transfer the key.
// Note: Azure Storage does not store or manage customer provided encryption keys. Keys are securely discarded
// as soon as possible after theyve been used to encrypt or decrypt the blob data.
// https://docs.microsoft.com/en-us/azure/storage/common/storage-service-encryption
// https://docs.microsoft.com/en-us/azure/storage/common/customer-managed-keys-overview
type ClientProvidedKeyOptions struct {
// A Base64-encoded AES-256 encryption key value.
EncryptionKey *string
// The Base64-encoded SHA256 of the encryption key.
EncryptionKeySha256 *string
// Specifies the algorithm to use when encrypting data using the given key. Must be AES256.
EncryptionAlgorithm EncryptionAlgorithmType
// Specifies the name of the encryption scope to use to encrypt the data provided in the request
// https://docs.microsoft.com/en-us/azure/storage/blobs/encryption-scope-overview
// https://docs.microsoft.com/en-us/azure/key-vault/general/overview
EncryptionScope *string
}
// NewClientProvidedKeyOptions function.
// By default the value of encryption algorithm params is "AES256" for service version 2019-02-02 or higher.
func NewClientProvidedKeyOptions(ek *string, eksha256 *string, es *string) (cpk ClientProvidedKeyOptions) {
cpk = ClientProvidedKeyOptions{}
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, cpk.EncryptionScope = ek, eksha256, EncryptionAlgorithmAES256, es
return cpk
}

View file

@ -44,6 +44,14 @@ func (v BlobSASSignatureValues) NewSASQueryParameters(credential StorageAccountC
return SASQueryParameters{}, err return SASQueryParameters{}, err
} }
v.Permissions = perms.String() v.Permissions = perms.String()
} else if v.Version != "" {
resource = "bv"
//Make sure the permission characters are in the correct order
perms := &BlobSASPermissions{}
if err := perms.Parse(v.Permissions); err != nil {
return SASQueryParameters{}, err
}
v.Permissions = perms.String()
} else if v.BlobName == "" { } else if v.BlobName == "" {
// Make sure the permission characters are in the correct order // Make sure the permission characters are in the correct order
perms := &ContainerSASPermissions{} perms := &ContainerSASPermissions{}
@ -155,7 +163,7 @@ func getCanonicalName(account string, containerName string, blobName string) str
// The ContainerSASPermissions type simplifies creating the permissions string for an Azure Storage container SAS. // The ContainerSASPermissions type simplifies creating the permissions string for an Azure Storage container SAS.
// Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field. // Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field.
type ContainerSASPermissions struct { type ContainerSASPermissions struct {
Read, Add, Create, Write, Delete, List bool Read, Add, Create, Write, Delete, DeletePreviousVersion, List, Tag bool
} }
// String produces the SAS permissions string for an Azure Storage container. // String produces the SAS permissions string for an Azure Storage container.
@ -177,9 +185,15 @@ func (p ContainerSASPermissions) String() string {
if p.Delete { if p.Delete {
b.WriteRune('d') b.WriteRune('d')
} }
if p.DeletePreviousVersion {
b.WriteRune('x')
}
if p.List { if p.List {
b.WriteRune('l') b.WriteRune('l')
} }
if p.Tag {
b.WriteRune('t')
}
return b.String() return b.String()
} }
@ -198,10 +212,14 @@ func (p *ContainerSASPermissions) Parse(s string) error {
p.Write = true p.Write = true
case 'd': case 'd':
p.Delete = true p.Delete = true
case 'x':
p.DeletePreviousVersion = true
case 'l': case 'l':
p.List = true p.List = true
case 't':
p.Tag = true
default: default:
return fmt.Errorf("Invalid permission: '%v'", r) return fmt.Errorf("invalid permission: '%v'", r)
} }
} }
return nil return nil
@ -209,7 +227,7 @@ func (p *ContainerSASPermissions) Parse(s string) error {
// The BlobSASPermissions type simplifies creating the permissions string for an Azure Storage blob SAS. // The BlobSASPermissions type simplifies creating the permissions string for an Azure Storage blob SAS.
// Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field. // Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field.
type BlobSASPermissions struct{ Read, Add, Create, Write, Delete bool } type BlobSASPermissions struct{ Read, Add, Create, Write, Delete, DeletePreviousVersion, Tag bool }
// String produces the SAS permissions string for an Azure Storage blob. // String produces the SAS permissions string for an Azure Storage blob.
// Call this method to set BlobSASSignatureValues's Permissions field. // Call this method to set BlobSASSignatureValues's Permissions field.
@ -230,6 +248,12 @@ func (p BlobSASPermissions) String() string {
if p.Delete { if p.Delete {
b.WriteRune('d') b.WriteRune('d')
} }
if p.DeletePreviousVersion {
b.WriteRune('x')
}
if p.Tag {
b.WriteRune('t')
}
return b.String() return b.String()
} }
@ -248,8 +272,12 @@ func (p *BlobSASPermissions) Parse(s string) error {
p.Write = true p.Write = true
case 'd': case 'd':
p.Delete = true p.Delete = true
case 'x':
p.DeletePreviousVersion = true
case 't':
p.Tag = true
default: default:
return fmt.Errorf("Invalid permission: '%v'", r) return fmt.Errorf("invalid permission: '%v'", r)
} }
} }
return nil return nil

View file

@ -0,0 +1,47 @@
package azblob
import (
"errors"
"io"
)
type sectionWriter struct {
count int64
offset int64
position int64
writerAt io.WriterAt
}
func newSectionWriter(c io.WriterAt, off int64, count int64) *sectionWriter {
return &sectionWriter{
count: count,
offset: off,
writerAt: c,
}
}
func (c *sectionWriter) Write(p []byte) (int, error) {
remaining := c.count - c.position
if remaining <= 0 {
return 0, errors.New("End of section reached")
}
slice := p
if int64(len(slice)) > remaining {
slice = slice[:remaining]
}
n, err := c.writerAt.WriteAt(slice, c.offset+c.position)
c.position += int64(n)
if err != nil {
return n, err
}
if len(p) > n {
return n, errors.New("Not enough space for all bytes")
}
return n, nil
}

View file

@ -61,8 +61,11 @@ const (
// ServiceCodeIncrementalCopyBlobMismatch means the specified source blob is different than the copy source of the existing incremental copy blob. // ServiceCodeIncrementalCopyBlobMismatch means the specified source blob is different than the copy source of the existing incremental copy blob.
ServiceCodeIncrementalCopyBlobMismatch ServiceCodeType = "IncrementalCopyBlobMismatch" ServiceCodeIncrementalCopyBlobMismatch ServiceCodeType = "IncrementalCopyBlobMismatch"
// ServiceCodeIncrementalCopyOfEralierVersionSnapshotNotAllowed means the specified snapshot is earlier than the last snapshot copied into the incremental copy blob. // ServiceCodeFeatureEncryptionMismatch means the given customer specified encryption does not match the encryption used to encrypt the blob.
ServiceCodeIncrementalCopyOfEralierVersionSnapshotNotAllowed ServiceCodeType = "IncrementalCopyOfEralierVersionSnapshotNotAllowed" ServiceCodeFeatureEncryptionMismatch ServiceCodeType = "BlobCustomerSpecifiedEncryptionMismatch"
// ServiceCodeIncrementalCopyOfEarlierVersionSnapshotNotAllowed means the specified snapshot is earlier than the last snapshot copied into the incremental copy blob.
ServiceCodeIncrementalCopyOfEarlierVersionSnapshotNotAllowed ServiceCodeType = "IncrementalCopyOfEarlierVersionSnapshotNotAllowed"
// ServiceCodeIncrementalCopySourceMustBeSnapshot means the source for incremental copy request must be a snapshot. // ServiceCodeIncrementalCopySourceMustBeSnapshot means the source for incremental copy request must be a snapshot.
ServiceCodeIncrementalCopySourceMustBeSnapshot ServiceCodeType = "IncrementalCopySourceMustBeSnapshot" ServiceCodeIncrementalCopySourceMustBeSnapshot ServiceCodeType = "IncrementalCopySourceMustBeSnapshot"

View file

@ -42,21 +42,40 @@ func (ab AppendBlobURL) WithSnapshot(snapshot string) AppendBlobURL {
return NewAppendBlobURL(p.URL(), ab.blobClient.Pipeline()) return NewAppendBlobURL(p.URL(), ab.blobClient.Pipeline())
} }
// WithVersionID creates a new AppendBlobURL object identical to the source but with the specified version id.
// Pass "" to remove the snapshot returning a URL to the base blob.
func (ab AppendBlobURL) WithVersionID(versionId string) AppendBlobURL {
p := NewBlobURLParts(ab.URL())
p.VersionID = versionId
return NewAppendBlobURL(p.URL(), ab.blobClient.Pipeline())
}
func (ab AppendBlobURL) GetAccountInfo(ctx context.Context) (*BlobGetAccountInfoResponse, error) {
return ab.blobClient.GetAccountInfo(ctx)
}
// Create creates a 0-length append blob. Call AppendBlock to append data to an append blob. // Create creates a 0-length append blob. Call AppendBlock to append data to an append blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
func (ab AppendBlobURL) Create(ctx context.Context, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*AppendBlobCreateResponse, error) { func (ab AppendBlobURL) Create(ctx context.Context, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions, blobTagsMap BlobTagsMap, cpk ClientProvidedKeyOptions) (*AppendBlobCreateResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch := ac.ModifiedAccessConditions.pointers()
blobTagsString := SerializeBlobTagsHeader(blobTagsMap)
return ab.abClient.Create(ctx, 0, nil, return ab.abClient.Create(ctx, 0, nil,
&h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5,
&h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition, &h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition,
ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, nil) cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK-V
cpk.EncryptionScope, // CPK-N
ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch,
nil, // Blob ifTags
nil,
blobTagsString, // Blob tags
)
} }
// AppendBlock writes a stream to a new block of data to the end of the existing append blob. // AppendBlock writes a stream to a new block of data to the end of the existing append blob.
// This method panics if the stream is not at position 0. // This method panics if the stream is not at position 0.
// Note that the http client closes the body stream after the request is sent to the service. // Note that the http client closes the body stream after the request is sent to the service.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/append-block. // For more information, see https://docs.microsoft.com/rest/api/storageservices/append-block.
func (ab AppendBlobURL) AppendBlock(ctx context.Context, body io.ReadSeeker, ac AppendBlobAccessConditions, transactionalMD5 []byte) (*AppendBlobAppendBlockResponse, error) { func (ab AppendBlobURL) AppendBlock(ctx context.Context, body io.ReadSeeker, ac AppendBlobAccessConditions, transactionalMD5 []byte, cpk ClientProvidedKeyOptions) (*AppendBlobAppendBlockResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
ifAppendPositionEqual, ifMaxSizeLessThanOrEqual := ac.AppendPositionAccessConditions.pointers() ifAppendPositionEqual, ifMaxSizeLessThanOrEqual := ac.AppendPositionAccessConditions.pointers()
count, err := validateSeekableStreamAt0AndGetCount(body) count, err := validateSeekableStreamAt0AndGetCount(body)
@ -64,21 +83,32 @@ func (ab AppendBlobURL) AppendBlock(ctx context.Context, body io.ReadSeeker, ac
return nil, err return nil, err
} }
return ab.abClient.AppendBlock(ctx, body, count, nil, return ab.abClient.AppendBlock(ctx, body, count, nil,
transactionalMD5, ac.LeaseAccessConditions.pointers(), transactionalMD5,
nil, // CRC
ac.LeaseAccessConditions.pointers(),
ifMaxSizeLessThanOrEqual, ifAppendPositionEqual, ifMaxSizeLessThanOrEqual, ifAppendPositionEqual,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK
cpk.EncryptionScope, // CPK-N
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
} }
// AppendBlockFromURL copies a new block of data from source URL to the end of the existing append blob. // AppendBlockFromURL copies a new block of data from source URL to the end of the existing append blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/append-block-from-url. // For more information, see https://docs.microsoft.com/rest/api/storageservices/append-block-from-url.
func (ab AppendBlobURL) AppendBlockFromURL(ctx context.Context, sourceURL url.URL, offset int64, count int64, destinationAccessConditions AppendBlobAccessConditions, sourceAccessConditions ModifiedAccessConditions, transactionalMD5 []byte) (*AppendBlobAppendBlockFromURLResponse, error) { func (ab AppendBlobURL) AppendBlockFromURL(ctx context.Context, sourceURL url.URL, offset int64, count int64, destinationAccessConditions AppendBlobAccessConditions, sourceAccessConditions ModifiedAccessConditions, transactionalMD5 []byte, cpk ClientProvidedKeyOptions) (*AppendBlobAppendBlockFromURLResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := destinationAccessConditions.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := destinationAccessConditions.ModifiedAccessConditions.pointers()
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers() sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers()
ifAppendPositionEqual, ifMaxSizeLessThanOrEqual := destinationAccessConditions.AppendPositionAccessConditions.pointers() ifAppendPositionEqual, ifMaxSizeLessThanOrEqual := destinationAccessConditions.AppendPositionAccessConditions.pointers()
return ab.abClient.AppendBlockFromURL(ctx, sourceURL.String(), 0, httpRange{offset: offset, count: count}.pointers(), return ab.abClient.AppendBlockFromURL(ctx, sourceURL.String(), 0, httpRange{offset: offset, count: count}.pointers(),
transactionalMD5, nil, destinationAccessConditions.LeaseAccessConditions.pointers(), transactionalMD5, nil, nil, nil,
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK
cpk.EncryptionScope, // CPK-N
destinationAccessConditions.LeaseAccessConditions.pointers(),
ifMaxSizeLessThanOrEqual, ifAppendPositionEqual, ifMaxSizeLessThanOrEqual, ifAppendPositionEqual,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil)
} }
type AppendBlobAccessConditions struct { type AppendBlobAccessConditions struct {

View file

@ -2,9 +2,9 @@ package azblob
import ( import (
"context" "context"
"net/url"
"github.com/Azure/azure-pipeline-go/pipeline" "github.com/Azure/azure-pipeline-go/pipeline"
"net/url"
"strings"
) )
// A BlobURL represents a URL to an Azure Storage blob; the blob may be a block blob, append blob, or page blob. // A BlobURL represents a URL to an Azure Storage blob; the blob may be a block blob, append blob, or page blob.
@ -12,6 +12,11 @@ type BlobURL struct {
blobClient blobClient blobClient blobClient
} }
type BlobTagsMap map[string]string
var DefaultAccessTier AccessTierType = AccessTierNone
var DefaultPremiumBlobAccessTier PremiumPageBlobAccessTierType = PremiumPageBlobAccessTierNone
// NewBlobURL creates a BlobURL object using the specified URL and request policy pipeline. // NewBlobURL creates a BlobURL object using the specified URL and request policy pipeline.
func NewBlobURL(url url.URL, p pipeline.Pipeline) BlobURL { func NewBlobURL(url url.URL, p pipeline.Pipeline) BlobURL {
blobClient := newBlobClient(url, p) blobClient := newBlobClient(url, p)
@ -29,6 +34,10 @@ func (b BlobURL) String() string {
return u.String() return u.String()
} }
func (b BlobURL) GetAccountInfo(ctx context.Context) (*BlobGetAccountInfoResponse, error) {
return b.blobClient.GetAccountInfo(ctx)
}
// WithPipeline creates a new BlobURL object identical to the source but with the specified request policy pipeline. // WithPipeline creates a new BlobURL object identical to the source but with the specified request policy pipeline.
func (b BlobURL) WithPipeline(p pipeline.Pipeline) BlobURL { func (b BlobURL) WithPipeline(p pipeline.Pipeline) BlobURL {
return NewBlobURL(b.blobClient.URL(), p) return NewBlobURL(b.blobClient.URL(), p)
@ -42,6 +51,14 @@ func (b BlobURL) WithSnapshot(snapshot string) BlobURL {
return NewBlobURL(p.URL(), b.blobClient.Pipeline()) return NewBlobURL(p.URL(), b.blobClient.Pipeline())
} }
// WithVersionID creates a new BlobURL object identical to the source but with the specified version id.
// Pass "" to remove the snapshot returning a URL to the base blob.
func (b BlobURL) WithVersionID(versionID string) BlobURL {
p := NewBlobURLParts(b.URL())
p.VersionID = versionID
return NewBlobURL(p.URL(), b.blobClient.Pipeline())
}
// ToAppendBlobURL creates an AppendBlobURL using the source's URL and pipeline. // ToAppendBlobURL creates an AppendBlobURL using the source's URL and pipeline.
func (b BlobURL) ToAppendBlobURL() AppendBlobURL { func (b BlobURL) ToAppendBlobURL() AppendBlobURL {
return NewAppendBlobURL(b.URL(), b.blobClient.Pipeline()) return NewAppendBlobURL(b.URL(), b.blobClient.Pipeline())
@ -57,19 +74,49 @@ func (b BlobURL) ToPageBlobURL() PageBlobURL {
return NewPageBlobURL(b.URL(), b.blobClient.Pipeline()) return NewPageBlobURL(b.URL(), b.blobClient.Pipeline())
} }
// DownloadBlob reads a range of bytes from a blob. The response also includes the blob's properties and metadata. func SerializeBlobTagsHeader(blobTagsMap BlobTagsMap) *string {
if blobTagsMap == nil {
return nil
}
tags := make([]string, 0)
for key, val := range blobTagsMap {
tags = append(tags, url.QueryEscape(key)+"="+url.QueryEscape(val))
}
//tags = tags[:len(tags)-1]
blobTagsString := strings.Join(tags, "&")
return &blobTagsString
}
func SerializeBlobTags(blobTagsMap BlobTagsMap) BlobTags {
if blobTagsMap == nil {
return BlobTags{}
}
blobTagSet := make([]BlobTag, 0, len(blobTagsMap))
for key, val := range blobTagsMap {
blobTagSet = append(blobTagSet, BlobTag{Key: key, Value: val})
}
return BlobTags{BlobTagSet: blobTagSet}
}
// Download reads a range of bytes from a blob. The response also includes the blob's properties and metadata.
// Passing azblob.CountToEnd (0) for count will download the blob from the offset to the end. // Passing azblob.CountToEnd (0) for count will download the blob from the offset to the end.
// Note: Snapshot/VersionId are optional parameters which are part of request URL query params.
// These parameters can be explicitly set by calling WithSnapshot(snapshot string)/WithVersionID(versionID string)
// Therefore it not required to pass these here.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob.
func (b BlobURL) Download(ctx context.Context, offset int64, count int64, ac BlobAccessConditions, rangeGetContentMD5 bool) (*DownloadResponse, error) { func (b BlobURL) Download(ctx context.Context, offset int64, count int64, ac BlobAccessConditions, rangeGetContentMD5 bool, cpk ClientProvidedKeyOptions) (*DownloadResponse, error) {
var xRangeGetContentMD5 *bool var xRangeGetContentMD5 *bool
if rangeGetContentMD5 { if rangeGetContentMD5 {
xRangeGetContentMD5 = &rangeGetContentMD5 xRangeGetContentMD5 = &rangeGetContentMD5
} }
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
dr, err := b.blobClient.Download(ctx, nil, nil, dr, err := b.blobClient.Download(ctx, nil, nil, nil,
httpRange{offset: offset, count: count}.pointers(), httpRange{offset: offset, count: count}.pointers(),
ac.LeaseAccessConditions.pointers(), xRangeGetContentMD5, ac.LeaseAccessConditions.pointers(), xRangeGetContentMD5, nil,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -81,13 +128,33 @@ func (b BlobURL) Download(ctx context.Context, offset int64, count int64, ac Blo
}, err }, err
} }
// DeleteBlob marks the specified blob or snapshot for deletion. The blob is later deleted during garbage collection. // Delete marks the specified blob or snapshot for deletion. The blob is later deleted during garbage collection.
// Note that deleting a blob also deletes all its snapshots. // Note 1: that deleting a blob also deletes all its snapshots.
// Note 2: Snapshot/VersionId are optional parameters which are part of request URL query params.
// These parameters can be explicitly set by calling WithSnapshot(snapshot string)/WithVersionID(versionID string)
// Therefore it not required to pass these here.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-blob.
func (b BlobURL) Delete(ctx context.Context, deleteOptions DeleteSnapshotsOptionType, ac BlobAccessConditions) (*BlobDeleteResponse, error) { func (b BlobURL) Delete(ctx context.Context, deleteOptions DeleteSnapshotsOptionType, ac BlobAccessConditions) (*BlobDeleteResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return b.blobClient.Delete(ctx, nil, nil, ac.LeaseAccessConditions.pointers(), deleteOptions, return b.blobClient.Delete(ctx, nil, nil, nil, ac.LeaseAccessConditions.pointers(), deleteOptions,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
}
// SetTags operation enables users to set tags on a blob or specific blob version, but not snapshot.
// Each call to this operation replaces all existing tags attached to the blob.
// To remove all tags from the blob, call this operation with no tags set.
// https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tags
func (b BlobURL) SetTags(ctx context.Context, timeout *int32, versionID *string, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, requestID *string, ifTags *string, blobTagsMap BlobTagsMap) (*BlobSetTagsResponse, error) {
tags := SerializeBlobTags(blobTagsMap)
return b.blobClient.SetTags(ctx, timeout, versionID, transactionalContentMD5, transactionalContentCrc64, requestID, ifTags, &tags)
}
// GetTags operation enables users to get tags on a blob or specific blob version, or snapshot.
// https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-tags
func (b BlobURL) GetTags(ctx context.Context, timeout *int32, requestID *string, snapshot *string, versionID *string, ifTags *string) (*BlobTags, error) {
return b.blobClient.GetTags(ctx, timeout, requestID, snapshot, versionID, ifTags)
} }
// Undelete restores the contents and metadata of a soft-deleted blob and any associated soft-deleted snapshots. // Undelete restores the contents and metadata of a soft-deleted blob and any associated soft-deleted snapshots.
@ -96,50 +163,71 @@ func (b BlobURL) Undelete(ctx context.Context) (*BlobUndeleteResponse, error) {
return b.blobClient.Undelete(ctx, nil, nil) return b.blobClient.Undelete(ctx, nil, nil)
} }
// SetTier operation sets the tier on a blob. The operation is allowed on a page // SetTier operation sets the tier on a blob. The operation is allowed on a page blob in a premium storage account
// blob in a premium storage account and on a block blob in a blob storage account (locally // and on a block blob in a blob storage account (locally redundant storage only).
// redundant storage only). A premium page blob's tier determines the allowed size, IOPS, and // A premium page blob's tier determines the allowed size, IOPS, and bandwidth of the blob.
// bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive storage type. This operation // A block blob's tier determines Hot/Cool/Archive storage type. This operation does not update the blob's ETag.
// does not update the blob's ETag. // Note: VersionId is an optional parameter which is part of request URL query params.
// It can be explicitly set by calling WithVersionID(versionID string) function and hence it not required to pass it here.
// For detailed information about block blob level tiering see https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers. // For detailed information about block blob level tiering see https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers.
func (b BlobURL) SetTier(ctx context.Context, tier AccessTierType, lac LeaseAccessConditions) (*BlobSetTierResponse, error) { func (b BlobURL) SetTier(ctx context.Context, tier AccessTierType, lac LeaseAccessConditions) (*BlobSetTierResponse, error) {
return b.blobClient.SetTier(ctx, tier, nil, nil, lac.pointers()) return b.blobClient.SetTier(ctx, tier, nil,
nil, // Blob versioning
nil, RehydratePriorityNone, nil, lac.pointers())
} }
// GetBlobProperties returns the blob's properties. // GetProperties returns the blob's properties.
// Note: Snapshot/VersionId are optional parameters which are part of request URL query params.
// These parameters can be explicitly set by calling WithSnapshot(snapshot string)/WithVersionID(versionID string)
// Therefore it not required to pass these here.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob-properties. // For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob-properties.
func (b BlobURL) GetProperties(ctx context.Context, ac BlobAccessConditions) (*BlobGetPropertiesResponse, error) { func (b BlobURL) GetProperties(ctx context.Context, ac BlobAccessConditions, cpk ClientProvidedKeyOptions) (*BlobGetPropertiesResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return b.blobClient.GetProperties(ctx, nil, nil, ac.LeaseAccessConditions.pointers(), return b.blobClient.GetProperties(ctx, nil,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) nil, // Blob versioning
nil, ac.LeaseAccessConditions.pointers(),
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
} }
// SetBlobHTTPHeaders changes a blob's HTTP headers. // SetHTTPHeaders changes a blob's HTTP headers.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties. // For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties.
func (b BlobURL) SetHTTPHeaders(ctx context.Context, h BlobHTTPHeaders, ac BlobAccessConditions) (*BlobSetHTTPHeadersResponse, error) { func (b BlobURL) SetHTTPHeaders(ctx context.Context, h BlobHTTPHeaders, ac BlobAccessConditions) (*BlobSetHTTPHeadersResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return b.blobClient.SetHTTPHeaders(ctx, nil, return b.blobClient.SetHTTPHeaders(ctx, nil,
&h.CacheControl, &h.ContentType, h.ContentMD5, &h.ContentEncoding, &h.ContentLanguage, &h.CacheControl, &h.ContentType, h.ContentMD5, &h.ContentEncoding, &h.ContentLanguage,
ac.LeaseAccessConditions.pointers(), ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, ac.LeaseAccessConditions.pointers(), ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
&h.ContentDisposition, nil) &h.ContentDisposition, nil)
} }
// SetBlobMetadata changes a blob's metadata. // SetMetadata changes a blob's metadata.
// https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata. // https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata.
func (b BlobURL) SetMetadata(ctx context.Context, metadata Metadata, ac BlobAccessConditions) (*BlobSetMetadataResponse, error) { func (b BlobURL) SetMetadata(ctx context.Context, metadata Metadata, ac BlobAccessConditions, cpk ClientProvidedKeyOptions) (*BlobSetMetadataResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return b.blobClient.SetMetadata(ctx, nil, metadata, ac.LeaseAccessConditions.pointers(), return b.blobClient.SetMetadata(ctx, nil, metadata, ac.LeaseAccessConditions.pointers(),
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK-V
cpk.EncryptionScope, // CPK-N
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
} }
// CreateSnapshot creates a read-only snapshot of a blob. // CreateSnapshot creates a read-only snapshot of a blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/snapshot-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/snapshot-blob.
func (b BlobURL) CreateSnapshot(ctx context.Context, metadata Metadata, ac BlobAccessConditions) (*BlobCreateSnapshotResponse, error) { func (b BlobURL) CreateSnapshot(ctx context.Context, metadata Metadata, ac BlobAccessConditions, cpk ClientProvidedKeyOptions) (*BlobCreateSnapshotResponse, error) {
// CreateSnapshot does NOT panic if the user tries to create a snapshot using a URL that already has a snapshot query parameter // CreateSnapshot does NOT panic if the user tries to create a snapshot using a URL that already has a snapshot query parameter
// because checking this would be a performance hit for a VERY unusual path and I don't think the common case should suffer this // because checking this would be a performance hit for a VERY unusual path and I don't think the common case should suffer this
// performance hit. // performance hit.
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return b.blobClient.CreateSnapshot(ctx, nil, metadata, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, ac.LeaseAccessConditions.pointers(), nil) return b.blobClient.CreateSnapshot(ctx, nil, metadata,
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK-V
cpk.EncryptionScope, // CPK-N
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
ac.LeaseAccessConditions.pointers(), nil)
} }
// AcquireLease acquires a lease on the blob for write and delete operations. The lease duration must be between // AcquireLease acquires a lease on the blob for write and delete operations. The lease duration must be between
@ -148,7 +236,9 @@ func (b BlobURL) CreateSnapshot(ctx context.Context, metadata Metadata, ac BlobA
func (b BlobURL) AcquireLease(ctx context.Context, proposedID string, duration int32, ac ModifiedAccessConditions) (*BlobAcquireLeaseResponse, error) { func (b BlobURL) AcquireLease(ctx context.Context, proposedID string, duration int32, ac ModifiedAccessConditions) (*BlobAcquireLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
return b.blobClient.AcquireLease(ctx, nil, &duration, &proposedID, return b.blobClient.AcquireLease(ctx, nil, &duration, &proposedID,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
} }
// RenewLease renews the blob's previously-acquired lease. // RenewLease renews the blob's previously-acquired lease.
@ -156,7 +246,9 @@ func (b BlobURL) AcquireLease(ctx context.Context, proposedID string, duration i
func (b BlobURL) RenewLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*BlobRenewLeaseResponse, error) { func (b BlobURL) RenewLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*BlobRenewLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
return b.blobClient.RenewLease(ctx, leaseID, nil, return b.blobClient.RenewLease(ctx, leaseID, nil,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
} }
// ReleaseLease releases the blob's previously-acquired lease. // ReleaseLease releases the blob's previously-acquired lease.
@ -164,7 +256,9 @@ func (b BlobURL) RenewLease(ctx context.Context, leaseID string, ac ModifiedAcce
func (b BlobURL) ReleaseLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*BlobReleaseLeaseResponse, error) { func (b BlobURL) ReleaseLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*BlobReleaseLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
return b.blobClient.ReleaseLease(ctx, leaseID, nil, return b.blobClient.ReleaseLease(ctx, leaseID, nil,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
} }
// BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) // BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1)
@ -173,7 +267,9 @@ func (b BlobURL) ReleaseLease(ctx context.Context, leaseID string, ac ModifiedAc
func (b BlobURL) BreakLease(ctx context.Context, breakPeriodInSeconds int32, ac ModifiedAccessConditions) (*BlobBreakLeaseResponse, error) { func (b BlobURL) BreakLease(ctx context.Context, breakPeriodInSeconds int32, ac ModifiedAccessConditions) (*BlobBreakLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
return b.blobClient.BreakLease(ctx, nil, leasePeriodPointer(breakPeriodInSeconds), return b.blobClient.BreakLease(ctx, nil, leasePeriodPointer(breakPeriodInSeconds),
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
} }
// ChangeLease changes the blob's lease ID. // ChangeLease changes the blob's lease ID.
@ -181,7 +277,9 @@ func (b BlobURL) BreakLease(ctx context.Context, breakPeriodInSeconds int32, ac
func (b BlobURL) ChangeLease(ctx context.Context, leaseID string, proposedID string, ac ModifiedAccessConditions) (*BlobChangeLeaseResponse, error) { func (b BlobURL) ChangeLease(ctx context.Context, leaseID string, proposedID string, ac ModifiedAccessConditions) (*BlobChangeLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
return b.blobClient.ChangeLease(ctx, leaseID, proposedID, return b.blobClient.ChangeLease(ctx, leaseID, proposedID,
nil, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) nil, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
} }
// LeaseBreakNaturally tells ContainerURL's or BlobURL's BreakLease method to break the lease using service semantics. // LeaseBreakNaturally tells ContainerURL's or BlobURL's BreakLease method to break the lease using service semantics.
@ -196,17 +294,22 @@ func leasePeriodPointer(period int32) (p *int32) {
// StartCopyFromURL copies the data at the source URL to a blob. // StartCopyFromURL copies the data at the source URL to a blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/copy-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/copy-blob.
func (b BlobURL) StartCopyFromURL(ctx context.Context, source url.URL, metadata Metadata, srcac ModifiedAccessConditions, dstac BlobAccessConditions) (*BlobStartCopyFromURLResponse, error) { func (b BlobURL) StartCopyFromURL(ctx context.Context, source url.URL, metadata Metadata, srcac ModifiedAccessConditions, dstac BlobAccessConditions, tier AccessTierType, blobTagsMap BlobTagsMap) (*BlobStartCopyFromURLResponse, error) {
srcIfModifiedSince, srcIfUnmodifiedSince, srcIfMatchETag, srcIfNoneMatchETag := srcac.pointers() srcIfModifiedSince, srcIfUnmodifiedSince, srcIfMatchETag, srcIfNoneMatchETag := srcac.pointers()
dstIfModifiedSince, dstIfUnmodifiedSince, dstIfMatchETag, dstIfNoneMatchETag := dstac.ModifiedAccessConditions.pointers() dstIfModifiedSince, dstIfUnmodifiedSince, dstIfMatchETag, dstIfNoneMatchETag := dstac.ModifiedAccessConditions.pointers()
dstLeaseID := dstac.LeaseAccessConditions.pointers() dstLeaseID := dstac.LeaseAccessConditions.pointers()
blobTagsString := SerializeBlobTagsHeader(blobTagsMap)
return b.blobClient.StartCopyFromURL(ctx, source.String(), nil, metadata, return b.blobClient.StartCopyFromURL(ctx, source.String(), nil, metadata,
srcIfModifiedSince, srcIfUnmodifiedSince, tier, RehydratePriorityNone, srcIfModifiedSince, srcIfUnmodifiedSince,
srcIfMatchETag, srcIfNoneMatchETag, srcIfMatchETag, srcIfNoneMatchETag,
nil, // source ifTags
dstIfModifiedSince, dstIfUnmodifiedSince, dstIfModifiedSince, dstIfUnmodifiedSince,
dstIfMatchETag, dstIfNoneMatchETag, dstIfMatchETag, dstIfNoneMatchETag,
dstLeaseID, nil) nil, // Blob ifTags
dstLeaseID,
nil,
blobTagsString, // Blob tags
nil)
} }
// AbortCopyFromURL stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. // AbortCopyFromURL stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata.

View file

@ -5,9 +5,6 @@ import (
"io" "io"
"net/url" "net/url"
"encoding/base64"
"encoding/binary"
"github.com/Azure/azure-pipeline-go/pipeline" "github.com/Azure/azure-pipeline-go/pipeline"
) )
@ -16,7 +13,7 @@ const (
BlockBlobMaxUploadBlobBytes = 256 * 1024 * 1024 // 256MB BlockBlobMaxUploadBlobBytes = 256 * 1024 * 1024 // 256MB
// BlockBlobMaxStageBlockBytes indicates the maximum number of bytes that can be sent in a call to StageBlock. // BlockBlobMaxStageBlockBytes indicates the maximum number of bytes that can be sent in a call to StageBlock.
BlockBlobMaxStageBlockBytes = 100 * 1024 * 1024 // 100MB BlockBlobMaxStageBlockBytes = 4000 * 1024 * 1024 // 4000MiB
// BlockBlobMaxBlocks indicates the maximum number of blocks allowed in a block blob. // BlockBlobMaxBlocks indicates the maximum number of blocks allowed in a block blob.
BlockBlobMaxBlocks = 50000 BlockBlobMaxBlocks = 50000
@ -48,6 +45,18 @@ func (bb BlockBlobURL) WithSnapshot(snapshot string) BlockBlobURL {
return NewBlockBlobURL(p.URL(), bb.blobClient.Pipeline()) return NewBlockBlobURL(p.URL(), bb.blobClient.Pipeline())
} }
// WithVersionID creates a new BlockBlobURRL object identical to the source but with the specified version id.
// Pass "" to remove the snapshot returning a URL to the base blob.
func (bb BlockBlobURL) WithVersionID(versionId string) BlockBlobURL {
p := NewBlobURLParts(bb.URL())
p.VersionID = versionId
return NewBlockBlobURL(p.URL(), bb.blobClient.Pipeline())
}
func (bb BlockBlobURL) GetAccountInfo(ctx context.Context) (*BlobGetAccountInfoResponse, error) {
return bb.blobClient.GetAccountInfo(ctx)
}
// Upload creates a new block blob or overwrites an existing block blob. // Upload creates a new block blob or overwrites an existing block blob.
// Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not // Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not
// supported with Upload; the content of the existing blob is overwritten with the new content. To // supported with Upload; the content of the existing blob is overwritten with the new content. To
@ -55,36 +64,48 @@ func (bb BlockBlobURL) WithSnapshot(snapshot string) BlockBlobURL {
// This method panics if the stream is not at position 0. // This method panics if the stream is not at position 0.
// Note that the http client closes the body stream after the request is sent to the service. // Note that the http client closes the body stream after the request is sent to the service.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
func (bb BlockBlobURL) Upload(ctx context.Context, body io.ReadSeeker, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*BlockBlobUploadResponse, error) { func (bb BlockBlobURL) Upload(ctx context.Context, body io.ReadSeeker, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions, tier AccessTierType, blobTagsMap BlobTagsMap, cpk ClientProvidedKeyOptions) (*BlockBlobUploadResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
count, err := validateSeekableStreamAt0AndGetCount(body) count, err := validateSeekableStreamAt0AndGetCount(body)
blobTagsString := SerializeBlobTagsHeader(blobTagsMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return bb.bbClient.Upload(ctx, body, count, nil, return bb.bbClient.Upload(ctx, body, count, nil, nil,
&h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5,
&h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), &h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition,
&h.ContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK-V
nil) cpk.EncryptionScope, // CPK-N
tier, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil,
blobTagsString, // Blob tags
)
} }
// StageBlock uploads the specified block to the block blob's "staging area" to be later committed by a call to CommitBlockList. // StageBlock uploads the specified block to the block blob's "staging area" to be later committed by a call to CommitBlockList.
// Note that the http client closes the body stream after the request is sent to the service. // Note that the http client closes the body stream after the request is sent to the service.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block.
func (bb BlockBlobURL) StageBlock(ctx context.Context, base64BlockID string, body io.ReadSeeker, ac LeaseAccessConditions, transactionalMD5 []byte) (*BlockBlobStageBlockResponse, error) { func (bb BlockBlobURL) StageBlock(ctx context.Context, base64BlockID string, body io.ReadSeeker, ac LeaseAccessConditions, transactionalMD5 []byte, cpk ClientProvidedKeyOptions) (*BlockBlobStageBlockResponse, error) {
count, err := validateSeekableStreamAt0AndGetCount(body) count, err := validateSeekableStreamAt0AndGetCount(body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return bb.bbClient.StageBlock(ctx, base64BlockID, count, body, transactionalMD5, nil, ac.pointers(), nil) return bb.bbClient.StageBlock(ctx, base64BlockID, count, body, transactionalMD5, nil, nil, ac.pointers(),
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK-V
cpk.EncryptionScope, // CPK-N
nil)
} }
// StageBlockFromURL copies the specified block from a source URL to the block blob's "staging area" to be later committed by a call to CommitBlockList. // StageBlockFromURL copies the specified block from a source URL to the block blob's "staging area" to be later committed by a call to CommitBlockList.
// If count is CountToEnd (0), then data is read from specified offset to the end. // If count is CountToEnd (0), then data is read from specified offset to the end.
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/put-block-from-url. // For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/put-block-from-url.
func (bb BlockBlobURL) StageBlockFromURL(ctx context.Context, base64BlockID string, sourceURL url.URL, offset int64, count int64, destinationAccessConditions LeaseAccessConditions, sourceAccessConditions ModifiedAccessConditions) (*BlockBlobStageBlockFromURLResponse, error) { func (bb BlockBlobURL) StageBlockFromURL(ctx context.Context, base64BlockID string, sourceURL url.URL, offset int64, count int64, destinationAccessConditions LeaseAccessConditions, sourceAccessConditions ModifiedAccessConditions, cpk ClientProvidedKeyOptions) (*BlockBlobStageBlockFromURLResponse, error) {
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers() sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers()
return bb.bbClient.StageBlockFromURL(ctx, base64BlockID, 0, sourceURL.String(), httpRange{offset: offset, count: count}.pointers(), nil, nil, destinationAccessConditions.pointers(), sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil) return bb.bbClient.StageBlockFromURL(ctx, base64BlockID, 0, sourceURL.String(), httpRange{offset: offset, count: count}.pointers(), nil, nil, nil,
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK
cpk.EncryptionScope, // CPK-N
destinationAccessConditions.pointers(), sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil)
} }
// CommitBlockList writes a blob by specifying the list of block IDs that make up the blob. // CommitBlockList writes a blob by specifying the list of block IDs that make up the blob.
@ -93,70 +114,46 @@ func (bb BlockBlobURL) StageBlockFromURL(ctx context.Context, base64BlockID stri
// by uploading only those blocks that have changed, then committing the new and existing // by uploading only those blocks that have changed, then committing the new and existing
// blocks together. Any blocks not specified in the block list and permanently deleted. // blocks together. Any blocks not specified in the block list and permanently deleted.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block-list. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block-list.
func (bb BlockBlobURL) CommitBlockList(ctx context.Context, base64BlockIDs []string, h BlobHTTPHeaders, func (bb BlockBlobURL) CommitBlockList(ctx context.Context, base64BlockIDs []string, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions, tier AccessTierType, blobTagsMap BlobTagsMap, cpk ClientProvidedKeyOptions) (*BlockBlobCommitBlockListResponse, error) {
metadata Metadata, ac BlobAccessConditions) (*BlockBlobCommitBlockListResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
blobTagsString := SerializeBlobTagsHeader(blobTagsMap)
return bb.bbClient.CommitBlockList(ctx, BlockLookupList{Latest: base64BlockIDs}, nil, return bb.bbClient.CommitBlockList(ctx, BlockLookupList{Latest: base64BlockIDs}, nil,
&h.CacheControl, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.CacheControl, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, nil, nil,
metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition, metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK
cpk.EncryptionScope, // CPK-N
tier,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil,
blobTagsString, // Blob tags
)
} }
// GetBlockList returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter. // GetBlockList returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-block-list. // For more information, see https://docs.microsoft.com/rest/api/storageservices/get-block-list.
func (bb BlockBlobURL) GetBlockList(ctx context.Context, listType BlockListType, ac LeaseAccessConditions) (*BlockList, error) { func (bb BlockBlobURL) GetBlockList(ctx context.Context, listType BlockListType, ac LeaseAccessConditions) (*BlockList, error) {
return bb.bbClient.GetBlockList(ctx, listType, nil, nil, ac.pointers(), nil) return bb.bbClient.GetBlockList(ctx, listType, nil, nil, ac.pointers(),
nil, // Blob ifTags
nil)
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CopyFromURL synchronously copies the data at the source URL to a block blob, with sizes up to 256 MB.
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url.
func (bb BlockBlobURL) CopyFromURL(ctx context.Context, source url.URL, metadata Metadata, srcac ModifiedAccessConditions, dstac BlobAccessConditions, srcContentMD5 []byte, tier AccessTierType, blobTagsMap BlobTagsMap) (*BlobCopyFromURLResponse, error) {
type BlockID [64]byte srcIfModifiedSince, srcIfUnmodifiedSince, srcIfMatchETag, srcIfNoneMatchETag := srcac.pointers()
dstIfModifiedSince, dstIfUnmodifiedSince, dstIfMatchETag, dstIfNoneMatchETag := dstac.ModifiedAccessConditions.pointers()
func (blockID BlockID) ToBase64() string { dstLeaseID := dstac.LeaseAccessConditions.pointers()
return base64.StdEncoding.EncodeToString(blockID[:]) blobTagsString := SerializeBlobTagsHeader(blobTagsMap)
} return bb.blobClient.CopyFromURL(ctx, source.String(), nil, metadata, tier,
srcIfModifiedSince, srcIfUnmodifiedSince,
func (blockID *BlockID) FromBase64(s string) error { srcIfMatchETag, srcIfNoneMatchETag,
*blockID = BlockID{} // Zero out the block ID dstIfModifiedSince, dstIfUnmodifiedSince,
_, err := base64.StdEncoding.Decode(blockID[:], ([]byte)(s)) dstIfMatchETag, dstIfNoneMatchETag,
return err nil, // Blob ifTags
} dstLeaseID, nil, srcContentMD5,
blobTagsString, // Blob tags
////////////////////////////////////////////////////////////////////////////////////////////////////////////// nil, // seal Blob
)
type uuidBlockID BlockID
func (ubi uuidBlockID) UUID() uuid {
u := uuid{}
copy(u[:], ubi[:len(u)])
return u
}
func (ubi uuidBlockID) Number() uint32 {
return binary.BigEndian.Uint32(ubi[len(uuid{}):])
}
func newUuidBlockID(u uuid) uuidBlockID {
ubi := uuidBlockID{} // Create a new uuidBlockID
copy(ubi[:len(u)], u[:]) // Copy the specified UUID into it
// Block number defaults to 0
return ubi
}
func (ubi *uuidBlockID) SetUUID(u uuid) *uuidBlockID {
copy(ubi[:len(u)], u[:])
return ubi
}
func (ubi uuidBlockID) WithBlockNumber(blockNumber uint32) uuidBlockID {
binary.BigEndian.PutUint32(ubi[len(uuid{}):], blockNumber) // Put block number after UUID
return ubi // Return the passed-in copy
}
func (ubi uuidBlockID) ToBase64() string {
return BlockID(ubi).ToBase64()
}
func (ubi *uuidBlockID) FromBase64(s string) error {
return (*BlockID)(ubi).FromBase64(s)
} }

View file

@ -32,6 +32,10 @@ func (c ContainerURL) String() string {
return u.String() return u.String()
} }
func (c ContainerURL) GetAccountInfo(ctx context.Context) (*ContainerGetAccountInfoResponse, error) {
return c.client.GetAccountInfo(ctx)
}
// WithPipeline creates a new ContainerURL object identical to the source but with the specified request policy pipeline. // WithPipeline creates a new ContainerURL object identical to the source but with the specified request policy pipeline.
func (c ContainerURL) WithPipeline(p pipeline.Pipeline) ContainerURL { func (c ContainerURL) WithPipeline(p pipeline.Pipeline) ContainerURL {
return NewContainerURL(c.URL(), p) return NewContainerURL(c.URL(), p)
@ -80,7 +84,9 @@ func (c ContainerURL) NewPageBlobURL(blobName string) PageBlobURL {
// Create creates a new container within a storage account. If a container with the same name already exists, the operation fails. // Create creates a new container within a storage account. If a container with the same name already exists, the operation fails.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/create-container. // For more information, see https://docs.microsoft.com/rest/api/storageservices/create-container.
func (c ContainerURL) Create(ctx context.Context, metadata Metadata, publicAccessType PublicAccessType) (*ContainerCreateResponse, error) { func (c ContainerURL) Create(ctx context.Context, metadata Metadata, publicAccessType PublicAccessType) (*ContainerCreateResponse, error) {
return c.client.Create(ctx, nil, metadata, publicAccessType, nil) return c.client.Create(ctx, nil, metadata, publicAccessType, nil,
nil, nil, // container encryption
)
} }
// Delete marks the specified container for deletion. The container and any blobs contained within it are later deleted during garbage collection. // Delete marks the specified container for deletion. The container and any blobs contained within it are later deleted during garbage collection.
@ -269,7 +275,7 @@ func (o *ListBlobsSegmentOptions) pointers() (prefix *string, include []ListBlob
// BlobListingDetails indicates what additional information the service should return with each blob. // BlobListingDetails indicates what additional information the service should return with each blob.
type BlobListingDetails struct { type BlobListingDetails struct {
Copy, Metadata, Snapshots, UncommittedBlobs, Deleted bool Copy, Metadata, Snapshots, UncommittedBlobs, Deleted, Tags, Versions bool
} }
// string produces the Include query parameter's value. // string produces the Include query parameter's value.
@ -291,5 +297,11 @@ func (d *BlobListingDetails) slice() []ListBlobsIncludeItemType {
if d.UncommittedBlobs { if d.UncommittedBlobs {
items = append(items, ListBlobsIncludeItemUncommittedblobs) items = append(items, ListBlobsIncludeItemUncommittedblobs)
} }
if d.Tags {
items = append(items, ListBlobsIncludeItemTags)
}
if d.Versions {
items = append(items, ListBlobsIncludeItemVersions)
}
return items return items
} }

View file

@ -14,7 +14,7 @@ const (
// PageBlobPageBytes indicates the number of bytes in a page (512). // PageBlobPageBytes indicates the number of bytes in a page (512).
PageBlobPageBytes = 512 PageBlobPageBytes = 512
// PageBlobMaxPutPagesBytes indicates the maximum number of bytes that can be sent in a call to PutPage. // PageBlobMaxUploadPagesBytes indicates the maximum number of bytes that can be sent in a call to PutPage.
PageBlobMaxUploadPagesBytes = 4 * 1024 * 1024 // 4MB PageBlobMaxUploadPagesBytes = 4 * 1024 * 1024 // 4MB
) )
@ -44,32 +44,55 @@ func (pb PageBlobURL) WithSnapshot(snapshot string) PageBlobURL {
return NewPageBlobURL(p.URL(), pb.blobClient.Pipeline()) return NewPageBlobURL(p.URL(), pb.blobClient.Pipeline())
} }
// Create creates a page blob of the specified length. Call PutPage to upload data data to a page blob. // WithVersionID creates a new PageBlobURL object identical to the source but with the specified snapshot timestamp.
// Pass "" to remove the snapshot returning a URL to the base blob.
func (pb PageBlobURL) WithVersionID(versionId string) PageBlobURL {
p := NewBlobURLParts(pb.URL())
p.VersionID = versionId
return NewPageBlobURL(p.URL(), pb.blobClient.Pipeline())
}
func (pb PageBlobURL) GetAccountInfo(ctx context.Context) (*BlobGetAccountInfoResponse, error) {
return pb.blobClient.GetAccountInfo(ctx)
}
// Create creates a page blob of the specified length. Call PutPage to upload data to a page blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
func (pb PageBlobURL) Create(ctx context.Context, size int64, sequenceNumber int64, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*PageBlobCreateResponse, error) { func (pb PageBlobURL) Create(ctx context.Context, size int64, sequenceNumber int64, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions, tier PremiumPageBlobAccessTierType, blobTagsMap BlobTagsMap, cpk ClientProvidedKeyOptions) (*PageBlobCreateResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return pb.pbClient.Create(ctx, 0, size, nil, blobTagsString := SerializeBlobTagsHeader(blobTagsMap)
return pb.pbClient.Create(ctx, 0, size, nil, tier,
&h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.CacheControl, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.CacheControl,
metadata, ac.LeaseAccessConditions.pointers(), metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition,
&h.ContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, &sequenceNumber, nil) cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK-V
cpk.EncryptionScope, // CPK-N
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob tags
&sequenceNumber, nil,
blobTagsString, // Blob tags
)
} }
// UploadPages writes 1 or more pages to the page blob. The start offset and the stream size must be a multiple of 512 bytes. // UploadPages writes 1 or more pages to the page blob. The start offset and the stream size must be a multiple of 512 bytes.
// This method panics if the stream is not at position 0. // This method panics if the stream is not at position 0.
// Note that the http client closes the body stream after the request is sent to the service. // Note that the http client closes the body stream after the request is sent to the service.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page.
func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.ReadSeeker, ac PageBlobAccessConditions, transactionalMD5 []byte) (*PageBlobUploadPagesResponse, error) { func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.ReadSeeker, ac PageBlobAccessConditions, transactionalMD5 []byte, cpk ClientProvidedKeyOptions) (*PageBlobUploadPagesResponse, error) {
count, err := validateSeekableStreamAt0AndGetCount(body) count, err := validateSeekableStreamAt0AndGetCount(body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.SequenceNumberAccessConditions.pointers() ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.SequenceNumberAccessConditions.pointers()
return pb.pbClient.UploadPages(ctx, body, count, transactionalMD5, nil, return pb.pbClient.UploadPages(ctx, body, count, transactionalMD5, nil, nil,
PageRange{Start: offset, End: offset + count - 1}.pointers(), PageRange{Start: offset, End: offset + count - 1}.pointers(),
ac.LeaseAccessConditions.pointers(), ac.LeaseAccessConditions.pointers(),
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK
cpk.EncryptionScope, // CPK-N
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual, ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
} }
// UploadPagesFromURL copies 1 or more pages from a source URL to the page blob. // UploadPagesFromURL copies 1 or more pages from a source URL to the page blob.
@ -77,24 +100,31 @@ func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.Rea
// The destOffset specifies the start offset of data in page blob will be written to. // The destOffset specifies the start offset of data in page blob will be written to.
// The count must be a multiple of 512 bytes. // The count must be a multiple of 512 bytes.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page-from-url. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page-from-url.
func (pb PageBlobURL) UploadPagesFromURL(ctx context.Context, sourceURL url.URL, sourceOffset int64, destOffset int64, count int64, transactionalMD5 []byte, destinationAccessConditions PageBlobAccessConditions, sourceAccessConditions ModifiedAccessConditions) (*PageBlobUploadPagesFromURLResponse, error) { func (pb PageBlobURL) UploadPagesFromURL(ctx context.Context, sourceURL url.URL, sourceOffset int64, destOffset int64, count int64, transactionalMD5 []byte, destinationAccessConditions PageBlobAccessConditions, sourceAccessConditions ModifiedAccessConditions, cpk ClientProvidedKeyOptions) (*PageBlobUploadPagesFromURLResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := destinationAccessConditions.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := destinationAccessConditions.ModifiedAccessConditions.pointers()
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers() sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers()
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := destinationAccessConditions.SequenceNumberAccessConditions.pointers() ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := destinationAccessConditions.SequenceNumberAccessConditions.pointers()
return pb.pbClient.UploadPagesFromURL(ctx, sourceURL.String(), *PageRange{Start: sourceOffset, End: sourceOffset + count - 1}.pointers(), 0, return pb.pbClient.UploadPagesFromURL(ctx, sourceURL.String(), *PageRange{Start: sourceOffset, End: sourceOffset + count - 1}.pointers(), 0,
*PageRange{Start: destOffset, End: destOffset + count - 1}.pointers(), transactionalMD5, nil, destinationAccessConditions.LeaseAccessConditions.pointers(), *PageRange{Start: destOffset, End: destOffset + count - 1}.pointers(), transactionalMD5, nil, nil,
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK-V
cpk.EncryptionScope, // CPK-N
destinationAccessConditions.LeaseAccessConditions.pointers(),
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual, ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil)
} }
// ClearPages frees the specified pages from the page blob. // ClearPages frees the specified pages from the page blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page.
func (pb PageBlobURL) ClearPages(ctx context.Context, offset int64, count int64, ac PageBlobAccessConditions) (*PageBlobClearPagesResponse, error) { func (pb PageBlobURL) ClearPages(ctx context.Context, offset int64, count int64, ac PageBlobAccessConditions, cpk ClientProvidedKeyOptions) (*PageBlobClearPagesResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.SequenceNumberAccessConditions.pointers() ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.SequenceNumberAccessConditions.pointers()
return pb.pbClient.ClearPages(ctx, 0, nil, return pb.pbClient.ClearPages(ctx, 0, nil,
PageRange{Start: offset, End: offset + count - 1}.pointers(), PageRange{Start: offset, End: offset + count - 1}.pointers(),
ac.LeaseAccessConditions.pointers(), ac.LeaseAccessConditions.pointers(),
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK
cpk.EncryptionScope, // CPK-N
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan,
ifSequenceNumberEqual, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifSequenceNumberEqual, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
} }
@ -106,7 +136,23 @@ func (pb PageBlobURL) GetPageRanges(ctx context.Context, offset int64, count int
return pb.pbClient.GetPageRanges(ctx, nil, nil, return pb.pbClient.GetPageRanges(ctx, nil, nil,
httpRange{offset: offset, count: count}.pointers(), httpRange{offset: offset, count: count}.pointers(),
ac.LeaseAccessConditions.pointers(), ac.LeaseAccessConditions.pointers(),
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
}
// GetManagedDiskPageRangesDiff gets the collection of page ranges that differ between a specified snapshot and this page blob representing managed disk.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges.
func (pb PageBlobURL) GetManagedDiskPageRangesDiff(ctx context.Context, offset int64, count int64, prevSnapshot *string, prevSnapshotURL *string, ac BlobAccessConditions) (*PageList, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return pb.pbClient.GetPageRangesDiff(ctx, nil, nil, prevSnapshot,
prevSnapshotURL, // Get managed disk diff
httpRange{offset: offset, count: count}.pointers(),
ac.LeaseAccessConditions.pointers(),
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil)
} }
// GetPageRangesDiff gets the collection of page ranges that differ between a specified snapshot and this page blob. // GetPageRangesDiff gets the collection of page ranges that differ between a specified snapshot and this page blob.
@ -114,21 +160,25 @@ func (pb PageBlobURL) GetPageRanges(ctx context.Context, offset int64, count int
func (pb PageBlobURL) GetPageRangesDiff(ctx context.Context, offset int64, count int64, prevSnapshot string, ac BlobAccessConditions) (*PageList, error) { func (pb PageBlobURL) GetPageRangesDiff(ctx context.Context, offset int64, count int64, prevSnapshot string, ac BlobAccessConditions) (*PageList, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return pb.pbClient.GetPageRangesDiff(ctx, nil, nil, &prevSnapshot, return pb.pbClient.GetPageRangesDiff(ctx, nil, nil, &prevSnapshot,
nil, // Get managed disk diff
httpRange{offset: offset, count: count}.pointers(), httpRange{offset: offset, count: count}.pointers(),
ac.LeaseAccessConditions.pointers(), ac.LeaseAccessConditions.pointers(),
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
nil, // Blob ifTags
nil) nil)
} }
// Resize resizes the page blob to the specified size (which must be a multiple of 512). // Resize resizes the page blob to the specified size (which must be a multiple of 512).
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties. // For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties.
func (pb PageBlobURL) Resize(ctx context.Context, size int64, ac BlobAccessConditions) (*PageBlobResizeResponse, error) { func (pb PageBlobURL) Resize(ctx context.Context, size int64, ac BlobAccessConditions, cpk ClientProvidedKeyOptions) (*PageBlobResizeResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return pb.pbClient.Resize(ctx, size, nil, ac.LeaseAccessConditions.pointers(), return pb.pbClient.Resize(ctx, size, nil, ac.LeaseAccessConditions.pointers(),
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK
cpk.EncryptionScope, // CPK-N
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
} }
// SetSequenceNumber sets the page blob's sequence number. // UpdateSequenceNumber sets the page blob's sequence number.
func (pb PageBlobURL) UpdateSequenceNumber(ctx context.Context, action SequenceNumberActionType, sequenceNumber int64, func (pb PageBlobURL) UpdateSequenceNumber(ctx context.Context, action SequenceNumberActionType, sequenceNumber int64,
ac BlobAccessConditions) (*PageBlobUpdateSequenceNumberResponse, error) { ac BlobAccessConditions) (*PageBlobUpdateSequenceNumberResponse, error) {
sn := &sequenceNumber sn := &sequenceNumber
@ -141,7 +191,7 @@ func (pb PageBlobURL) UpdateSequenceNumber(ctx context.Context, action SequenceN
sn, nil) sn, nil)
} }
// StartIncrementalCopy begins an operation to start an incremental copy from one page blob's snapshot to this page blob. // StartCopyIncremental begins an operation to start an incremental copy from one page blob's snapshot to this page blob.
// The snapshot is copied such that only the differential changes between the previously copied snapshot are transferred to the destination. // The snapshot is copied such that only the differential changes between the previously copied snapshot are transferred to the destination.
// The copied snapshots are complete copies of the original snapshot and can be read or copied from as usual. // The copied snapshots are complete copies of the original snapshot and can be read or copied from as usual.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/incremental-copy-blob and // For more information, see https://docs.microsoft.com/rest/api/storageservices/incremental-copy-blob and

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"net/url" "net/url"
"strings" "strings"
"time"
"github.com/Azure/azure-pipeline-go/pipeline" "github.com/Azure/azure-pipeline-go/pipeline"
) )
@ -38,6 +39,19 @@ func (s ServiceURL) GetUserDelegationCredential(ctx context.Context, info KeyInf
return NewUserDelegationCredential(strings.Split(s.client.url.Host, ".")[0], *udk), nil return NewUserDelegationCredential(strings.Split(s.client.url.Host, ".")[0], *udk), nil
} }
//TODO this was supposed to be generated
//NewKeyInfo creates a new KeyInfo struct with the correct time formatting & conversion
func NewKeyInfo(Start, Expiry time.Time) KeyInfo {
return KeyInfo{
Start: Start.UTC().Format(SASTimeFormat),
Expiry: Expiry.UTC().Format(SASTimeFormat),
}
}
func (s ServiceURL) GetAccountInfo(ctx context.Context) (*ServiceGetAccountInfoResponse, error) {
return s.client.GetAccountInfo(ctx)
}
// URL returns the URL endpoint used by the ServiceURL object. // URL returns the URL endpoint used by the ServiceURL object.
func (s ServiceURL) URL() url.URL { func (s ServiceURL) URL() url.URL {
return s.client.URL() return s.client.URL()
@ -102,14 +116,14 @@ type ListContainersSegmentOptions struct {
// TODO: update swagger to generate this type? // TODO: update swagger to generate this type?
} }
func (o *ListContainersSegmentOptions) pointers() (prefix *string, include ListContainersIncludeType, maxResults *int32) { func (o *ListContainersSegmentOptions) pointers() (prefix *string, include []ListContainersIncludeType, maxResults *int32) {
if o.Prefix != "" { if o.Prefix != "" {
prefix = &o.Prefix prefix = &o.Prefix
} }
if o.MaxResults != 0 { if o.MaxResults != 0 {
maxResults = &o.MaxResults maxResults = &o.MaxResults
} }
include = ListContainersIncludeType(o.Detail.string()) include = []ListContainersIncludeType{ListContainersIncludeType(o.Detail.string())}
return return
} }
@ -117,15 +131,21 @@ func (o *ListContainersSegmentOptions) pointers() (prefix *string, include ListC
type ListContainersDetail struct { type ListContainersDetail struct {
// Tells the service whether to return metadata for each container. // Tells the service whether to return metadata for each container.
Metadata bool Metadata bool
// Show containers that have been deleted when the soft-delete feature is enabled.
// Deleted bool
} }
// string produces the Include query parameter's value. // string produces the Include query parameter's value.
func (d *ListContainersDetail) string() string { func (d *ListContainersDetail) string() string {
items := make([]string, 0, 1) items := make([]string, 0, 2)
// NOTE: Multiple strings MUST be appended in alphabetic order or signing the string for authentication fails! // NOTE: Multiple strings MUST be appended in alphabetic order or signing the string for authentication fails!
if d.Metadata { if d.Metadata {
items = append(items, string(ListContainersIncludeMetadata)) items = append(items, string(ListContainersIncludeMetadata))
} }
// if d.Deleted {
// items = append(items, string(ListContainersIncludeDeleted))
// }
if len(items) > 0 { if len(items) > 0 {
return strings.Join(items, ",") return strings.Join(items, ",")
} }
@ -143,3 +163,12 @@ func (bsu ServiceURL) SetProperties(ctx context.Context, properties StorageServi
func (bsu ServiceURL) GetStatistics(ctx context.Context) (*StorageServiceStats, error) { func (bsu ServiceURL) GetStatistics(ctx context.Context) (*StorageServiceStats, error) {
return bsu.client.GetStatistics(ctx, nil, nil) return bsu.client.GetStatistics(ctx, nil, nil)
} }
// FindBlobsByTags operation finds all blobs in the storage account whose tags match a given search expression.
// Filter blobs searches across all containers within a storage account but can be scoped within the expression to a single container.
// https://docs.microsoft.com/en-us/rest/api/storageservices/find-blobs-by-tags
// eg. "dog='germanshepherd' and penguin='emperorpenguin'"
// To specify a container, eg. "@container=containerName and Name = C"
func (bsu ServiceURL) FindBlobsByTags(ctx context.Context, timeout *int32, requestID *string, where *string, marker Marker, maxResults *int32) (*FilterBlobSegment, error) {
return bsu.client.FilterBlobs(ctx, timeout, requestID, where, marker.Val, maxResults)
}

View file

@ -1,3 +1,3 @@
package azblob package azblob
const serviceLibVersion = "0.7" const serviceLibVersion = "0.12"

View file

@ -1,27 +0,0 @@
// +build linux darwin freebsd openbsd netbsd dragonfly
package azblob
import (
"os"
"syscall"
)
type mmf []byte
func newMMF(file *os.File, writable bool, offset int64, length int) (mmf, error) {
prot, flags := syscall.PROT_READ, syscall.MAP_SHARED // Assume read-only
if writable {
prot, flags = syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED
}
addr, err := syscall.Mmap(int(file.Fd()), offset, length, prot, flags)
return mmf(addr), err
}
func (m *mmf) unmap() {
err := syscall.Munmap(*m)
*m = nil
if err != nil {
panic("if we are unable to unmap the memory-mapped file, there is serious concern for memory corruption")
}
}

View file

@ -1,38 +0,0 @@
package azblob
import (
"os"
"reflect"
"syscall"
"unsafe"
)
type mmf []byte
func newMMF(file *os.File, writable bool, offset int64, length int) (mmf, error) {
prot, access := uint32(syscall.PAGE_READONLY), uint32(syscall.FILE_MAP_READ) // Assume read-only
if writable {
prot, access = uint32(syscall.PAGE_READWRITE), uint32(syscall.FILE_MAP_WRITE)
}
hMMF, errno := syscall.CreateFileMapping(syscall.Handle(file.Fd()), nil, prot, uint32(int64(length)>>32), uint32(int64(length)&0xffffffff), nil)
if hMMF == 0 {
return nil, os.NewSyscallError("CreateFileMapping", errno)
}
defer syscall.CloseHandle(hMMF)
addr, errno := syscall.MapViewOfFile(hMMF, access, uint32(offset>>32), uint32(offset&0xffffffff), uintptr(length))
m := mmf{}
h := (*reflect.SliceHeader)(unsafe.Pointer(&m))
h.Data = addr
h.Len = length
h.Cap = h.Len
return m, nil
}
func (m *mmf) unmap() {
addr := uintptr(unsafe.Pointer(&(([]byte)(*m)[0])))
*m = mmf{}
err := syscall.UnmapViewOfFile(addr)
if err != nil {
panic("if we are unable to unmap the memory-mapped file, there is serious concern for memory corruption")
}
}

View file

@ -62,15 +62,21 @@ func NewRequestLogPolicyFactory(o RequestLogOptions) pipeline.Factory {
logLevel, forceLog = pipeline.LogWarning, true logLevel, forceLog = pipeline.LogWarning, true
} }
if err == nil { // We got a response from the service var sc int
sc := response.Response().StatusCode if err == nil { // We got a valid response from the service
if ((sc >= 400 && sc <= 499) && sc != http.StatusNotFound && sc != http.StatusConflict && sc != http.StatusPreconditionFailed && sc != http.StatusRequestedRangeNotSatisfiable) || (sc >= 500 && sc <= 599) { sc = response.Response().StatusCode
logLevel, forceLog = pipeline.LogError, true // Promote to Error any 4xx (except those listed is an error) or any 5xx } else { // We got an error, so we should inspect if we got a response
} else { if se, ok := err.(StorageError); ok {
// For other status codes, we leave the level as is. if r := se.Response(); r != nil {
sc = r.StatusCode
}
} }
} else { // This error did not get an HTTP response from the service; upgrade the severity to Error }
logLevel, forceLog = pipeline.LogError, true
if sc == 0 || ((sc >= 400 && sc <= 499) && sc != http.StatusNotFound && sc != http.StatusConflict && sc != http.StatusPreconditionFailed && sc != http.StatusRequestedRangeNotSatisfiable) || (sc >= 500 && sc <= 599) {
logLevel, forceLog = pipeline.LogError, true // Promote to Error any 4xx (except those listed is an error) or any 5xx
} else {
// For other status codes, we leave the level as is.
} }
if shouldLog := po.ShouldLog(logLevel); forceLog || shouldLog { if shouldLog := po.ShouldLog(logLevel); forceLog || shouldLog {

View file

@ -240,6 +240,8 @@ func NewRetryPolicyFactory(o RetryOptions) pipeline.Factory {
} else { } else {
action = "NoRetry: net.Error and in the non-retriable list" action = "NoRetry: net.Error and in the non-retriable list"
} }
} else if err == io.ErrUnexpectedEOF {
action = "Retry: unexpected EOF"
} else { } else {
action = "NoRetry: unrecognized error" action = "NoRetry: unrecognized error"
} }

View file

@ -41,6 +41,7 @@ type RetryReaderOptions struct {
MaxRetryRequests int MaxRetryRequests int
doInjectError bool doInjectError bool
doInjectErrorRound int doInjectErrorRound int
injectedError error
// NotifyFailedRead is called, if non-nil, after any failure to read. Expected usage is diagnostic logging. // NotifyFailedRead is called, if non-nil, after any failure to read. Expected usage is diagnostic logging.
NotifyFailedRead FailedReadNotifier NotifyFailedRead FailedReadNotifier
@ -55,6 +56,8 @@ type RetryReaderOptions struct {
// from the same "thread" (goroutine) as Read. Concurrent Close calls from other goroutines may instead produce network errors // from the same "thread" (goroutine) as Read. Concurrent Close calls from other goroutines may instead produce network errors
// which will be retried. // which will be retried.
TreatEarlyCloseAsError bool TreatEarlyCloseAsError bool
ClientProvidedKeyOptions ClientProvidedKeyOptions
} }
// retryReader implements io.ReaderCloser methods. // retryReader implements io.ReaderCloser methods.
@ -117,7 +120,11 @@ func (s *retryReader) Read(p []byte) (n int, err error) {
// Injection mechanism for testing. // Injection mechanism for testing.
if s.o.doInjectError && try == s.o.doInjectErrorRound { if s.o.doInjectError && try == s.o.doInjectErrorRound {
err = &net.DNSError{IsTemporary: true} if s.o.injectedError != nil {
err = s.o.injectedError
} else {
err = &net.DNSError{IsTemporary: true}
}
} }
// We successfully read data or end EOF. // We successfully read data or end EOF.
@ -134,7 +141,8 @@ func (s *retryReader) Read(p []byte) (n int, err error) {
// Check the retry count and error code, and decide whether to retry. // Check the retry count and error code, and decide whether to retry.
retriesExhausted := try >= s.o.MaxRetryRequests retriesExhausted := try >= s.o.MaxRetryRequests
_, isNetError := err.(net.Error) _, isNetError := err.(net.Error)
willRetry := (isNetError || s.wasRetryableEarlyClose(err)) && !retriesExhausted isUnexpectedEOF := err == io.ErrUnexpectedEOF
willRetry := (isNetError || isUnexpectedEOF || s.wasRetryableEarlyClose(err)) && !retriesExhausted
// Notify, for logging purposes, of any failures // Notify, for logging purposes, of any failures
if s.o.NotifyFailedRead != nil { if s.o.NotifyFailedRead != nil {

View file

@ -76,7 +76,7 @@ func (v AccountSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *Sh
// The AccountSASPermissions type simplifies creating the permissions string for an Azure Storage Account SAS. // The AccountSASPermissions type simplifies creating the permissions string for an Azure Storage Account SAS.
// Initialize an instance of this type and then call its String method to set AccountSASSignatureValues's Permissions field. // Initialize an instance of this type and then call its String method to set AccountSASSignatureValues's Permissions field.
type AccountSASPermissions struct { type AccountSASPermissions struct {
Read, Write, Delete, List, Add, Create, Update, Process bool Read, Write, Delete, DeletePreviousVersion, List, Add, Create, Update, Process, Tag, FilterByTags bool
} }
// String produces the SAS permissions string for an Azure Storage account. // String produces the SAS permissions string for an Azure Storage account.
@ -92,6 +92,9 @@ func (p AccountSASPermissions) String() string {
if p.Delete { if p.Delete {
buffer.WriteRune('d') buffer.WriteRune('d')
} }
if p.DeletePreviousVersion {
buffer.WriteRune('x')
}
if p.List { if p.List {
buffer.WriteRune('l') buffer.WriteRune('l')
} }
@ -107,6 +110,12 @@ func (p AccountSASPermissions) String() string {
if p.Process { if p.Process {
buffer.WriteRune('p') buffer.WriteRune('p')
} }
if p.Tag {
buffer.WriteRune('t')
}
if p.FilterByTags {
buffer.WriteRune('f')
}
return buffer.String() return buffer.String()
} }
@ -131,8 +140,14 @@ func (p *AccountSASPermissions) Parse(s string) error {
p.Update = true p.Update = true
case 'p': case 'p':
p.Process = true p.Process = true
case 'x':
p.Process = true
case 't':
p.Tag = true
case 'f':
p.FilterByTags = true
default: default:
return fmt.Errorf("Invalid permission character: '%v'", r) return fmt.Errorf("invalid permission character: '%v'", r)
} }
} }
return nil return nil

View file

@ -1,6 +1,7 @@
package azblob package azblob
import ( import (
"errors"
"net" "net"
"net/url" "net/url"
"strings" "strings"
@ -25,11 +26,11 @@ const (
func FormatTimesForSASSigning(startTime, expiryTime, snapshotTime time.Time) (string, string, string) { func FormatTimesForSASSigning(startTime, expiryTime, snapshotTime time.Time) (string, string, string) {
ss := "" ss := ""
if !startTime.IsZero() { if !startTime.IsZero() {
ss = startTime.Format(SASTimeFormat) // "yyyy-MM-ddTHH:mm:ssZ" ss = formatSASTimeWithDefaultFormat(&startTime)
} }
se := "" se := ""
if !expiryTime.IsZero() { if !expiryTime.IsZero() {
se = expiryTime.Format(SASTimeFormat) // "yyyy-MM-ddTHH:mm:ssZ" se = formatSASTimeWithDefaultFormat(&expiryTime)
} }
sh := "" sh := ""
if !snapshotTime.IsZero() { if !snapshotTime.IsZero() {
@ -40,6 +41,37 @@ func FormatTimesForSASSigning(startTime, expiryTime, snapshotTime time.Time) (st
// SASTimeFormat represents the format of a SAS start or expiry time. Use it when formatting/parsing a time.Time. // SASTimeFormat represents the format of a SAS start or expiry time. Use it when formatting/parsing a time.Time.
const SASTimeFormat = "2006-01-02T15:04:05Z" //"2017-07-27T00:00:00Z" // ISO 8601 const SASTimeFormat = "2006-01-02T15:04:05Z" //"2017-07-27T00:00:00Z" // ISO 8601
var SASTimeFormats = []string{"2006-01-02T15:04:05.0000000Z", SASTimeFormat, "2006-01-02T15:04Z", "2006-01-02"} // ISO 8601 formats, please refer to https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas for more details.
// formatSASTimeWithDefaultFormat format time with ISO 8601 in "yyyy-MM-ddTHH:mm:ssZ".
func formatSASTimeWithDefaultFormat(t *time.Time) string {
return formatSASTime(t, SASTimeFormat) // By default, "yyyy-MM-ddTHH:mm:ssZ" is used
}
// formatSASTime format time with given format, use ISO 8601 in "yyyy-MM-ddTHH:mm:ssZ" by default.
func formatSASTime(t *time.Time, format string) string {
if format != "" {
return t.Format(format)
}
return t.Format(SASTimeFormat) // By default, "yyyy-MM-ddTHH:mm:ssZ" is used
}
// parseSASTimeString try to parse sas time string.
func parseSASTimeString(val string) (t time.Time, timeFormat string, err error) {
for _, sasTimeFormat := range SASTimeFormats {
t, err = time.Parse(sasTimeFormat, val)
if err == nil {
timeFormat = sasTimeFormat
break
}
}
if err != nil {
err = errors.New("fail to parse time with IOS 8601 formats, please refer to https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas for more details")
}
return
}
// https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
@ -74,6 +106,10 @@ type SASQueryParameters struct {
signedExpiry time.Time `param:"ske"` signedExpiry time.Time `param:"ske"`
signedService string `param:"sks"` signedService string `param:"sks"`
signedVersion string `param:"skv"` signedVersion string `param:"skv"`
// private member used for startTime and expiryTime formatting.
stTimeFormat string
seTimeFormat string
} }
func (p *SASQueryParameters) SignedOid() string { func (p *SASQueryParameters) SignedOid() string {
@ -202,9 +238,9 @@ func newSASQueryParameters(values url.Values, deleteSASParametersFromValues bool
case "snapshot": case "snapshot":
p.snapshotTime, _ = time.Parse(SnapshotTimeFormat, val) p.snapshotTime, _ = time.Parse(SnapshotTimeFormat, val)
case "st": case "st":
p.startTime, _ = time.Parse(SASTimeFormat, val) p.startTime, p.stTimeFormat, _ = parseSASTimeString(val)
case "se": case "se":
p.expiryTime, _ = time.Parse(SASTimeFormat, val) p.expiryTime, p.seTimeFormat, _ = parseSASTimeString(val)
case "sip": case "sip":
dashIndex := strings.Index(val, "-") dashIndex := strings.Index(val, "-")
if dashIndex == -1 { if dashIndex == -1 {
@ -268,10 +304,10 @@ func (p *SASQueryParameters) addToValues(v url.Values) url.Values {
v.Add("spr", string(p.protocol)) v.Add("spr", string(p.protocol))
} }
if !p.startTime.IsZero() { if !p.startTime.IsZero() {
v.Add("st", p.startTime.Format(SASTimeFormat)) v.Add("st", formatSASTime(&(p.startTime), p.stTimeFormat))
} }
if !p.expiryTime.IsZero() { if !p.expiryTime.IsZero() {
v.Add("se", p.expiryTime.Format(SASTimeFormat)) v.Add("se", formatSASTime(&(p.expiryTime), p.seTimeFormat))
} }
if len(p.ipRange.Start) > 0 { if len(p.ipRange.Start) > 0 {
v.Add("sip", p.ipRange.String()) v.Add("sip", p.ipRange.String())

View file

@ -114,6 +114,9 @@ const (
// ServiceCodeResourceNotFound means the specified resource does not exist (404). // ServiceCodeResourceNotFound means the specified resource does not exist (404).
ServiceCodeResourceNotFound ServiceCodeType = "ResourceNotFound" ServiceCodeResourceNotFound ServiceCodeType = "ResourceNotFound"
// ServiceCodeNoAuthenticationInformation means the specified authentication for the resource does not exist (401).
ServiceCodeNoAuthenticationInformation ServiceCodeType = "NoAuthenticationInformation"
// ServiceCodeServerBusy means the server is currently unable to receive requests. Please retry your request or Ingress/egress is over the account limit or operations per second is over the account limit (503). // ServiceCodeServerBusy means the server is currently unable to receive requests. Please retry your request or Ingress/egress is over the account limit or operations per second is over the account limit (503).
ServiceCodeServerBusy ServiceCodeType = "ServerBusy" ServiceCodeServerBusy ServiceCodeType = "ServerBusy"

View file

@ -79,7 +79,7 @@ func (e *storageError) Error() string {
// Temporary returns true if the error occurred due to a temporary condition (including an HTTP status of 500 or 503). // Temporary returns true if the error occurred due to a temporary condition (including an HTTP status of 500 or 503).
func (e *storageError) Temporary() bool { func (e *storageError) Temporary() bool {
if e.response != nil { if e.response != nil {
if (e.response.StatusCode == http.StatusInternalServerError) || (e.response.StatusCode == http.StatusServiceUnavailable) { if (e.response.StatusCode == http.StatusInternalServerError) || (e.response.StatusCode == http.StatusServiceUnavailable) || (e.response.StatusCode == http.StatusBadGateway) {
return true return true
} }
} }

View file

@ -34,20 +34,30 @@ func newAppendBlobClient(url url.URL, p pipeline.Pipeline) appendBlobClient {
// information, see <a // information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> transactionalContentMD5 is specify the transactional md5 for the body, to // Timeouts for Blob Service Operations.</a> transactionalContentMD5 is specify the transactional md5 for the body, to
// be validated by the service. leaseID is if specified, the operation only succeeds if the resource's lease is active // be validated by the service. transactionalContentCrc64 is specify the transactional crc64 for the body, to be
// and matches this ID. maxSize is optional conditional header. The max length in bytes permitted for the append blob. // validated by the service. leaseID is if specified, the operation only succeeds if the resource's lease is active and
// If the Append Block operation would cause the blob to exceed that limit or if the blob size is already greater than // matches this ID. maxSize is optional conditional header. The max length in bytes permitted for the append blob. If
// the value specified in this header, the request will fail with MaxBlobSizeConditionNotMet error (HTTP status code // the Append Block operation would cause the blob to exceed that limit or if the blob size is already greater than the
// 412 - Precondition Failed). appendPosition is optional conditional header, used only for the Append Block operation. // value specified in this header, the request will fail with MaxBlobSizeConditionNotMet error (HTTP status code 412 -
// A number indicating the byte offset to compare. Append Block will succeed only if the append position is equal to // Precondition Failed). appendPosition is optional conditional header, used only for the Append Block operation. A
// this number. If it is not, the request will fail with the AppendPositionConditionNotMet error (HTTP status code 412 // number indicating the byte offset to compare. Append Block will succeed only if the append position is equal to this
// - Precondition Failed). ifModifiedSince is specify this header value to operate only on a blob if it has been // number. If it is not, the request will fail with the AppendPositionConditionNotMet error (HTTP status code 412 -
// modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if // Precondition Failed). encryptionKey is optional. Specifies the encryption key to use to encrypt the data provided in
// it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs // the request. If not specified, encryption is performed with the root account encryption key. For more information,
// with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. // see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the provided
// requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics // encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the algorithm
// logs when storage analytics logging is enabled. // used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the
func (client appendBlobClient) AppendBlock(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*AppendBlobAppendBlockResponse, error) { // x-ms-encryption-key header is provided. encryptionScope is optional. Version 2019-07-07 and later. Specifies the
// name of the encryption scope to use to encrypt the data provided in the request. If not specified, encryption is
// performed with the default account encryption scope. For more information, see Encryption at Rest for Azure Storage
// Services. ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the
// specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been
// modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching
// value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. ifTags is specify a
// SQL where clause on blob tags to operate only on blobs with a matching value. requestID is provides a
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
// analytics logging is enabled.
func (client appendBlobClient) AppendBlock(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, leaseID *string, maxSize *int64, appendPosition *int64, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string) (*AppendBlobAppendBlockResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: body, {targetValue: body,
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
@ -56,7 +66,7 @@ func (client appendBlobClient) AppendBlock(ctx context.Context, body io.ReadSeek
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.appendBlockPreparer(body, contentLength, timeout, transactionalContentMD5, leaseID, maxSize, appendPosition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID) req, err := client.appendBlockPreparer(body, contentLength, timeout, transactionalContentMD5, transactionalContentCrc64, leaseID, maxSize, appendPosition, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -68,7 +78,7 @@ func (client appendBlobClient) AppendBlock(ctx context.Context, body io.ReadSeek
} }
// appendBlockPreparer prepares the AppendBlock request. // appendBlockPreparer prepares the AppendBlock request.
func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, leaseID *string, maxSize *int64, appendPosition *int64, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, body) req, err := pipeline.NewRequest("PUT", client.url, body)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -83,6 +93,9 @@ func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLe
if transactionalContentMD5 != nil { if transactionalContentMD5 != nil {
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5)) req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
} }
if transactionalContentCrc64 != nil {
req.Header.Set("x-ms-content-crc64", base64.StdEncoding.EncodeToString(transactionalContentCrc64))
}
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
@ -92,6 +105,18 @@ func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLe
if appendPosition != nil { if appendPosition != nil {
req.Header.Set("x-ms-blob-condition-appendpos", strconv.FormatInt(*appendPosition, 10)) req.Header.Set("x-ms-blob-condition-appendpos", strconv.FormatInt(*appendPosition, 10))
} }
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if ifModifiedSince != nil { if ifModifiedSince != nil {
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
} }
@ -104,6 +129,9 @@ func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLe
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
req.Header.Set("x-ms-version", ServiceVersion) req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
@ -128,33 +156,44 @@ func (client appendBlobClient) appendBlockResponder(resp pipeline.Response) (pip
// //
// sourceURL is specify a URL to the copy source. contentLength is the length of the request. sourceRange is bytes of // sourceURL is specify a URL to the copy source. contentLength is the length of the request. sourceRange is bytes of
// source data in the specified range. sourceContentMD5 is specify the md5 calculated for the range of bytes that must // source data in the specified range. sourceContentMD5 is specify the md5 calculated for the range of bytes that must
// be read from the copy source. timeout is the timeout parameter is expressed in seconds. For more information, see <a // be read from the copy source. sourceContentcrc64 is specify the crc64 calculated for the range of bytes that must be
// read from the copy source. timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's // Timeouts for Blob Service Operations.</a> transactionalContentMD5 is specify the transactional md5 for the body, to
// lease is active and matches this ID. maxSize is optional conditional header. The max length in bytes permitted for // be validated by the service. encryptionKey is optional. Specifies the encryption key to use to encrypt the data
// the append blob. If the Append Block operation would cause the blob to exceed that limit or if the blob size is // provided in the request. If not specified, encryption is performed with the root account encryption key. For more
// already greater than the value specified in this header, the request will fail with MaxBlobSizeConditionNotMet error // information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the
// (HTTP status code 412 - Precondition Failed). appendPosition is optional conditional header, used only for the // provided encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the
// Append Block operation. A number indicating the byte offset to compare. Append Block will succeed only if the append // algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided
// position is equal to this number. If it is not, the request will fail with the AppendPositionConditionNotMet error // if the x-ms-encryption-key header is provided. encryptionScope is optional. Version 2019-07-07 and later. Specifies
// (HTTP status code 412 - Precondition Failed). ifModifiedSince is specify this header value to operate only on a blob // the name of the encryption scope to use to encrypt the data provided in the request. If not specified, encryption is
// if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate // performed with the default account encryption scope. For more information, see Encryption at Rest for Azure Storage
// only on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to // Services. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this
// operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a // ID. maxSize is optional conditional header. The max length in bytes permitted for the append blob. If the Append
// matching value. sourceIfModifiedSince is specify this header value to operate only on a blob if it has been modified // Block operation would cause the blob to exceed that limit or if the blob size is already greater than the value
// since the specified date/time. sourceIfUnmodifiedSince is specify this header value to operate only on a blob if it // specified in this header, the request will fail with MaxBlobSizeConditionNotMet error (HTTP status code 412 -
// has not been modified since the specified date/time. sourceIfMatch is specify an ETag value to operate only on blobs // Precondition Failed). appendPosition is optional conditional header, used only for the Append Block operation. A
// with a matching value. sourceIfNoneMatch is specify an ETag value to operate only on blobs without a matching value. // number indicating the byte offset to compare. Append Block will succeed only if the append position is equal to this
// requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics // number. If it is not, the request will fail with the AppendPositionConditionNotMet error (HTTP status code 412 -
// logs when storage analytics logging is enabled. // Precondition Failed). ifModifiedSince is specify this header value to operate only on a blob if it has been modified
func (client appendBlobClient) AppendBlockFromURL(ctx context.Context, sourceURL string, contentLength int64, sourceRange *string, sourceContentMD5 []byte, timeout *int32, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (*AppendBlobAppendBlockFromURLResponse, error) { // since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has
// not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a
// matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. ifTags is
// specify a SQL where clause on blob tags to operate only on blobs with a matching value. sourceIfModifiedSince is
// specify this header value to operate only on a blob if it has been modified since the specified date/time.
// sourceIfUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified since the
// specified date/time. sourceIfMatch is specify an ETag value to operate only on blobs with a matching value.
// sourceIfNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides
// a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
// analytics logging is enabled.
func (client appendBlobClient) AppendBlockFromURL(ctx context.Context, sourceURL string, contentLength int64, sourceRange *string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, transactionalContentMD5 []byte, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (*AppendBlobAppendBlockFromURLResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.appendBlockFromURLPreparer(sourceURL, contentLength, sourceRange, sourceContentMD5, timeout, leaseID, maxSize, appendPosition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, requestID) req, err := client.appendBlockFromURLPreparer(sourceURL, contentLength, sourceRange, sourceContentMD5, sourceContentcrc64, timeout, transactionalContentMD5, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, leaseID, maxSize, appendPosition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -166,7 +205,7 @@ func (client appendBlobClient) AppendBlockFromURL(ctx context.Context, sourceURL
} }
// appendBlockFromURLPreparer prepares the AppendBlockFromURL request. // appendBlockFromURLPreparer prepares the AppendBlockFromURL request.
func (client appendBlobClient) appendBlockFromURLPreparer(sourceURL string, contentLength int64, sourceRange *string, sourceContentMD5 []byte, timeout *int32, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client appendBlobClient) appendBlockFromURLPreparer(sourceURL string, contentLength int64, sourceRange *string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, transactionalContentMD5 []byte, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -184,7 +223,25 @@ func (client appendBlobClient) appendBlockFromURLPreparer(sourceURL string, cont
if sourceContentMD5 != nil { if sourceContentMD5 != nil {
req.Header.Set("x-ms-source-content-md5", base64.StdEncoding.EncodeToString(sourceContentMD5)) req.Header.Set("x-ms-source-content-md5", base64.StdEncoding.EncodeToString(sourceContentMD5))
} }
if sourceContentcrc64 != nil {
req.Header.Set("x-ms-source-content-crc64", base64.StdEncoding.EncodeToString(sourceContentcrc64))
}
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
if transactionalContentMD5 != nil {
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
}
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
@ -206,6 +263,9 @@ func (client appendBlobClient) appendBlockFromURLPreparer(sourceURL string, cont
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
if sourceIfModifiedSince != nil { if sourceIfModifiedSince != nil {
req.Header.Set("x-ms-source-if-modified-since", (*sourceIfModifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("x-ms-source-if-modified-since", (*sourceIfModifiedSince).In(gmt).Format(time.RFC1123))
} }
@ -255,20 +315,29 @@ func (client appendBlobClient) appendBlockFromURLResponder(resp pipeline.Respons
// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and // metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and
// Metadata for more information. leaseID is if specified, the operation only succeeds if the resource's lease is // Metadata for more information. leaseID is if specified, the operation only succeeds if the resource's lease is
// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. // active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header.
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified // encryptionKey is optional. Specifies the encryption key to use to encrypt the data provided in the request. If not
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified // specified, encryption is performed with the root account encryption key. For more information, see Encryption at
// since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value. // Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the provided encryption key. Must be
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a // provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the algorithm used to produce the
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key
// analytics logging is enabled. // header is provided. encryptionScope is optional. Version 2019-07-07 and later. Specifies the name of the encryption
func (client appendBlobClient) Create(ctx context.Context, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*AppendBlobCreateResponse, error) { // scope to use to encrypt the data provided in the request. If not specified, encryption is performed with the default
// account encryption scope. For more information, see Encryption at Rest for Azure Storage Services. ifModifiedSince
// is specify this header value to operate only on a blob if it has been modified since the specified date/time.
// ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified since the
// specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is
// specify an ETag value to operate only on blobs without a matching value. ifTags is specify a SQL where clause on
// blob tags to operate only on blobs with a matching value. requestID is provides a client-generated, opaque value
// with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled.
// blobTagsString is optional. Used to set blob tags in various blob operations.
func (client appendBlobClient) Create(ctx context.Context, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string, blobTagsString *string) (*AppendBlobCreateResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.createPreparer(contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID) req, err := client.createPreparer(contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, requestID, blobTagsString)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -280,7 +349,7 @@ func (client appendBlobClient) Create(ctx context.Context, contentLength int64,
} }
// createPreparer prepares the Create request. // createPreparer prepares the Create request.
func (client appendBlobClient) createPreparer(contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client appendBlobClient) createPreparer(contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string, blobTagsString *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -317,6 +386,18 @@ func (client appendBlobClient) createPreparer(contentLength int64, timeout *int3
if blobContentDisposition != nil { if blobContentDisposition != nil {
req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition) req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition)
} }
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if ifModifiedSince != nil { if ifModifiedSince != nil {
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
} }
@ -329,10 +410,16 @@ func (client appendBlobClient) createPreparer(contentLength int64, timeout *int3
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
req.Header.Set("x-ms-version", ServiceVersion) req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
} }
if blobTagsString != nil {
req.Header.Set("x-ms-tags", *blobTagsString)
}
req.Header.Set("x-ms-blob-type", "AppendBlob") req.Header.Set("x-ms-blob-type", "AppendBlob")
return req, nil return req, nil
} }
@ -347,3 +434,84 @@ func (client appendBlobClient) createResponder(resp pipeline.Response) (pipeline
resp.Response().Body.Close() resp.Response().Body.Close()
return &AppendBlobCreateResponse{rawResponse: resp.Response()}, err return &AppendBlobCreateResponse{rawResponse: resp.Response()}, err
} }
// Seal the Seal operation seals the Append Blob to make it read-only. Seal is supported only on version 2019-12-12
// version or later.
//
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled. leaseID is if
// specified, the operation only succeeds if the resource's lease is active and matches this ID. ifModifiedSince is
// specify this header value to operate only on a blob if it has been modified since the specified date/time.
// ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified since the
// specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is
// specify an ETag value to operate only on blobs without a matching value. appendPosition is optional conditional
// header, used only for the Append Block operation. A number indicating the byte offset to compare. Append Block will
// succeed only if the append position is equal to this number. If it is not, the request will fail with the
// AppendPositionConditionNotMet error (HTTP status code 412 - Precondition Failed).
func (client appendBlobClient) Seal(ctx context.Context, timeout *int32, requestID *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, appendPosition *int64) (*AppendBlobSealResponse, error) {
if err := validate([]validation{
{targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err
}
req, err := client.sealPreparer(timeout, requestID, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, appendPosition)
if err != nil {
return nil, err
}
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.sealResponder}, req)
if err != nil {
return nil, err
}
return resp.(*AppendBlobSealResponse), err
}
// sealPreparer prepares the Seal request.
func (client appendBlobClient) sealPreparer(timeout *int32, requestID *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, appendPosition *int64) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil {
return req, pipeline.NewError(err, "failed to create request")
}
params := req.URL.Query()
if timeout != nil {
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
}
params.Set("comp", "seal")
req.URL.RawQuery = params.Encode()
req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID)
}
if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID)
}
if ifModifiedSince != nil {
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
}
if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
}
if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatch))
}
if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch))
}
if appendPosition != nil {
req.Header.Set("x-ms-blob-condition-appendpos", strconv.FormatInt(*appendPosition, 10))
}
return req, nil
}
// sealResponder handles the response to the Seal request.
func (client appendBlobClient) sealResponder(resp pipeline.Response) (pipeline.Response, error) {
err := validateResponse(resp, http.StatusOK)
if resp == nil {
return nil, err
}
io.Copy(ioutil.Discard, resp.Response().Body)
resp.Response().Body.Close()
return &AppendBlobSealResponse{rawResponse: resp.Response()}, err
}

File diff suppressed because it is too large Load diff

View file

@ -43,27 +43,39 @@ func newBlockBlobClient(url url.URL, p pipeline.Pipeline) blockBlobClient {
// blob and returned with a read request. blobContentLanguage is optional. Set the blob's content language. If // blob and returned with a read request. blobContentLanguage is optional. Set the blob's content language. If
// specified, this property is stored with the blob and returned with a read request. blobContentMD5 is optional. An // specified, this property is stored with the blob and returned with a read request. blobContentMD5 is optional. An
// MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks were // MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks were
// validated when each was uploaded. metadata is optional. Specifies a user-defined name-value pair associated with the // validated when each was uploaded. transactionalContentMD5 is specify the transactional md5 for the body, to be
// blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the // validated by the service. transactionalContentCrc64 is specify the transactional crc64 for the body, to be validated
// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified // by the service. metadata is optional. Specifies a user-defined name-value pair associated with the blob. If no
// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, // name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination
// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and // blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata,
// Metadata for more information. leaseID is if specified, the operation only succeeds if the resource's lease is // and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names
// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. // must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified // more information. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified // this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. encryptionKey is optional.
// since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value. // Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a // performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // Services. encryptionKeySha256 is the SHA-256 hash of the provided encryption key. Must be provided if the
// analytics logging is enabled. // x-ms-encryption-key header is provided. encryptionAlgorithm is the algorithm used to produce the encryption key
func (client blockBlobClient) CommitBlockList(ctx context.Context, blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlockBlobCommitBlockListResponse, error) { // hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is
// provided. encryptionScope is optional. Version 2019-07-07 and later. Specifies the name of the encryption scope to
// use to encrypt the data provided in the request. If not specified, encryption is performed with the default account
// encryption scope. For more information, see Encryption at Rest for Azure Storage Services. tier is optional.
// Indicates the tier to be set on the blob. ifModifiedSince is specify this header value to operate only on a blob if
// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
// on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate
// only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a
// matching value. ifTags is specify a SQL where clause on blob tags to operate only on blobs with a matching value.
// requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics
// logs when storage analytics logging is enabled. blobTagsString is optional. Used to set blob tags in various blob
// operations.
func (client blockBlobClient) CommitBlockList(ctx context.Context, blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, tier AccessTierType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string, blobTagsString *string) (*BlockBlobCommitBlockListResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.commitBlockListPreparer(blocks, timeout, blobCacheControl, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID) req, err := client.commitBlockListPreparer(blocks, timeout, blobCacheControl, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, transactionalContentMD5, transactionalContentCrc64, metadata, leaseID, blobContentDisposition, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, tier, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, requestID, blobTagsString)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -75,7 +87,7 @@ func (client blockBlobClient) CommitBlockList(ctx context.Context, blocks BlockL
} }
// commitBlockListPreparer prepares the CommitBlockList request. // commitBlockListPreparer prepares the CommitBlockList request.
func (client blockBlobClient) commitBlockListPreparer(blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blockBlobClient) commitBlockListPreparer(blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, tier AccessTierType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string, blobTagsString *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -101,6 +113,12 @@ func (client blockBlobClient) commitBlockListPreparer(blocks BlockLookupList, ti
if blobContentMD5 != nil { if blobContentMD5 != nil {
req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5)) req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5))
} }
if transactionalContentMD5 != nil {
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
}
if transactionalContentCrc64 != nil {
req.Header.Set("x-ms-content-crc64", base64.StdEncoding.EncodeToString(transactionalContentCrc64))
}
if metadata != nil { if metadata != nil {
for k, v := range metadata { for k, v := range metadata {
req.Header.Set("x-ms-meta-"+k, v) req.Header.Set("x-ms-meta-"+k, v)
@ -112,6 +130,21 @@ func (client blockBlobClient) commitBlockListPreparer(blocks BlockLookupList, ti
if blobContentDisposition != nil { if blobContentDisposition != nil {
req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition) req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition)
} }
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if tier != AccessTierNone {
req.Header.Set("x-ms-access-tier", string(tier))
}
if ifModifiedSince != nil { if ifModifiedSince != nil {
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
} }
@ -124,10 +157,16 @@ func (client blockBlobClient) commitBlockListPreparer(blocks BlockLookupList, ti
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
req.Header.Set("x-ms-version", ServiceVersion) req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
} }
if blobTagsString != nil {
req.Header.Set("x-ms-tags", *blobTagsString)
}
b, err := xml.Marshal(blocks) b, err := xml.Marshal(blocks)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to marshal request body") return req, pipeline.NewError(err, "failed to marshal request body")
@ -161,16 +200,17 @@ func (client blockBlobClient) commitBlockListResponder(resp pipeline.Response) (
// a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a // a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character // lease is active and matches this ID. ifTags is specify a SQL where clause on blob tags to operate only on blobs with
// limit that is recorded in the analytics logs when storage analytics logging is enabled. // a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is
func (client blockBlobClient) GetBlockList(ctx context.Context, listType BlockListType, snapshot *string, timeout *int32, leaseID *string, requestID *string) (*BlockList, error) { // recorded in the analytics logs when storage analytics logging is enabled.
func (client blockBlobClient) GetBlockList(ctx context.Context, listType BlockListType, snapshot *string, timeout *int32, leaseID *string, ifTags *string, requestID *string) (*BlockList, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.getBlockListPreparer(listType, snapshot, timeout, leaseID, requestID) req, err := client.getBlockListPreparer(listType, snapshot, timeout, leaseID, ifTags, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -182,7 +222,7 @@ func (client blockBlobClient) GetBlockList(ctx context.Context, listType BlockLi
} }
// getBlockListPreparer prepares the GetBlockList request. // getBlockListPreparer prepares the GetBlockList request.
func (client blockBlobClient) getBlockListPreparer(listType BlockListType, snapshot *string, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) { func (client blockBlobClient) getBlockListPreparer(listType BlockListType, snapshot *string, timeout *int32, leaseID *string, ifTags *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil) req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -200,6 +240,9 @@ func (client blockBlobClient) getBlockListPreparer(listType BlockListType, snaps
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
req.Header.Set("x-ms-version", ServiceVersion) req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
@ -238,13 +281,22 @@ func (client blockBlobClient) getBlockListResponder(resp pipeline.Response) (pip
// equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the // equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the
// same size for each block. contentLength is the length of the request. body is initial data body will be closed upon // same size for each block. contentLength is the length of the request. body is initial data body will be closed upon
// successful return. Callers should ensure closure when receiving an error.transactionalContentMD5 is specify the // successful return. Callers should ensure closure when receiving an error.transactionalContentMD5 is specify the
// transactional md5 for the body, to be validated by the service. timeout is the timeout parameter is expressed in // transactional md5 for the body, to be validated by the service. transactionalContentCrc64 is specify the
// transactional crc64 for the body, to be validated by the service. timeout is the timeout parameter is expressed in
// seconds. For more information, see <a // seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character // lease is active and matches this ID. encryptionKey is optional. Specifies the encryption key to use to encrypt the
// limit that is recorded in the analytics logs when storage analytics logging is enabled. // data provided in the request. If not specified, encryption is performed with the root account encryption key. For
func (client blockBlobClient) StageBlock(ctx context.Context, blockID string, contentLength int64, body io.ReadSeeker, transactionalContentMD5 []byte, timeout *int32, leaseID *string, requestID *string) (*BlockBlobStageBlockResponse, error) { // more information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the
// provided encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the
// algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided
// if the x-ms-encryption-key header is provided. encryptionScope is optional. Version 2019-07-07 and later. Specifies
// the name of the encryption scope to use to encrypt the data provided in the request. If not specified, encryption is
// performed with the default account encryption scope. For more information, see Encryption at Rest for Azure Storage
// Services. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the
// analytics logs when storage analytics logging is enabled.
func (client blockBlobClient) StageBlock(ctx context.Context, blockID string, contentLength int64, body io.ReadSeeker, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, timeout *int32, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, requestID *string) (*BlockBlobStageBlockResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: body, {targetValue: body,
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
@ -253,7 +305,7 @@ func (client blockBlobClient) StageBlock(ctx context.Context, blockID string, co
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.stageBlockPreparer(blockID, contentLength, body, transactionalContentMD5, timeout, leaseID, requestID) req, err := client.stageBlockPreparer(blockID, contentLength, body, transactionalContentMD5, transactionalContentCrc64, timeout, leaseID, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -265,7 +317,7 @@ func (client blockBlobClient) StageBlock(ctx context.Context, blockID string, co
} }
// stageBlockPreparer prepares the StageBlock request. // stageBlockPreparer prepares the StageBlock request.
func (client blockBlobClient) stageBlockPreparer(blockID string, contentLength int64, body io.ReadSeeker, transactionalContentMD5 []byte, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) { func (client blockBlobClient) stageBlockPreparer(blockID string, contentLength int64, body io.ReadSeeker, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, timeout *int32, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, body) req, err := pipeline.NewRequest("PUT", client.url, body)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -281,9 +333,24 @@ func (client blockBlobClient) stageBlockPreparer(blockID string, contentLength i
if transactionalContentMD5 != nil { if transactionalContentMD5 != nil {
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5)) req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
} }
if transactionalContentCrc64 != nil {
req.Header.Set("x-ms-content-crc64", base64.StdEncoding.EncodeToString(transactionalContentCrc64))
}
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
req.Header.Set("x-ms-version", ServiceVersion) req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
@ -309,24 +376,33 @@ func (client blockBlobClient) stageBlockResponder(resp pipeline.Response) (pipel
// equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the // equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the
// same size for each block. contentLength is the length of the request. sourceURL is specify a URL to the copy source. // same size for each block. contentLength is the length of the request. sourceURL is specify a URL to the copy source.
// sourceRange is bytes of source data in the specified range. sourceContentMD5 is specify the md5 calculated for the // sourceRange is bytes of source data in the specified range. sourceContentMD5 is specify the md5 calculated for the
// range of bytes that must be read from the copy source. sourceContentcrc64 is specify the crc64 calculated for the
// range of bytes that must be read from the copy source. timeout is the timeout parameter is expressed in seconds. For // range of bytes that must be read from the copy source. timeout is the timeout parameter is expressed in seconds. For
// more information, see <a // more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's // Timeouts for Blob Service Operations.</a> encryptionKey is optional. Specifies the encryption key to use to encrypt
// lease is active and matches this ID. sourceIfModifiedSince is specify this header value to operate only on a blob if // the data provided in the request. If not specified, encryption is performed with the root account encryption key.
// it has been modified since the specified date/time. sourceIfUnmodifiedSince is specify this header value to operate // For more information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of
// only on a blob if it has not been modified since the specified date/time. sourceIfMatch is specify an ETag value to // the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is
// operate only on blobs with a matching value. sourceIfNoneMatch is specify an ETag value to operate only on blobs // the algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be
// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is // provided if the x-ms-encryption-key header is provided. encryptionScope is optional. Version 2019-07-07 and later.
// recorded in the analytics logs when storage analytics logging is enabled. // Specifies the name of the encryption scope to use to encrypt the data provided in the request. If not specified,
func (client blockBlobClient) StageBlockFromURL(ctx context.Context, blockID string, contentLength int64, sourceURL string, sourceRange *string, sourceContentMD5 []byte, timeout *int32, leaseID *string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (*BlockBlobStageBlockFromURLResponse, error) { // encryption is performed with the default account encryption scope. For more information, see Encryption at Rest for
// Azure Storage Services. leaseID is if specified, the operation only succeeds if the resource's lease is active and
// matches this ID. sourceIfModifiedSince is specify this header value to operate only on a blob if it has been
// modified since the specified date/time. sourceIfUnmodifiedSince is specify this header value to operate only on a
// blob if it has not been modified since the specified date/time. sourceIfMatch is specify an ETag value to operate
// only on blobs with a matching value. sourceIfNoneMatch is specify an ETag value to operate only on blobs without a
// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded
// in the analytics logs when storage analytics logging is enabled.
func (client blockBlobClient) StageBlockFromURL(ctx context.Context, blockID string, contentLength int64, sourceURL string, sourceRange *string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, leaseID *string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (*BlockBlobStageBlockFromURLResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.stageBlockFromURLPreparer(blockID, contentLength, sourceURL, sourceRange, sourceContentMD5, timeout, leaseID, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, requestID) req, err := client.stageBlockFromURLPreparer(blockID, contentLength, sourceURL, sourceRange, sourceContentMD5, sourceContentcrc64, timeout, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, leaseID, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -338,7 +414,7 @@ func (client blockBlobClient) StageBlockFromURL(ctx context.Context, blockID str
} }
// stageBlockFromURLPreparer prepares the StageBlockFromURL request. // stageBlockFromURLPreparer prepares the StageBlockFromURL request.
func (client blockBlobClient) stageBlockFromURLPreparer(blockID string, contentLength int64, sourceURL string, sourceRange *string, sourceContentMD5 []byte, timeout *int32, leaseID *string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blockBlobClient) stageBlockFromURLPreparer(blockID string, contentLength int64, sourceURL string, sourceRange *string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, leaseID *string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -358,6 +434,21 @@ func (client blockBlobClient) stageBlockFromURLPreparer(blockID string, contentL
if sourceContentMD5 != nil { if sourceContentMD5 != nil {
req.Header.Set("x-ms-source-content-md5", base64.StdEncoding.EncodeToString(sourceContentMD5)) req.Header.Set("x-ms-source-content-md5", base64.StdEncoding.EncodeToString(sourceContentMD5))
} }
if sourceContentcrc64 != nil {
req.Header.Set("x-ms-source-content-crc64", base64.StdEncoding.EncodeToString(sourceContentcrc64))
}
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
@ -400,27 +491,37 @@ func (client blockBlobClient) stageBlockFromURLResponder(resp pipeline.Response)
// error.contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more // error.contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more
// information, see <a // information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> blobContentType is optional. Sets the blob's content type. If specified, // Timeouts for Blob Service Operations.</a> transactionalContentMD5 is specify the transactional md5 for the body, to
// this property is stored with the blob and returned with a read request. blobContentEncoding is optional. Sets the // be validated by the service. blobContentType is optional. Sets the blob's content type. If specified, this property
// blob's content encoding. If specified, this property is stored with the blob and returned with a read request. // is stored with the blob and returned with a read request. blobContentEncoding is optional. Sets the blob's content
// blobContentLanguage is optional. Set the blob's content language. If specified, this property is stored with the // encoding. If specified, this property is stored with the blob and returned with a read request. blobContentLanguage
// blob and returned with a read request. blobContentMD5 is optional. An MD5 hash of the blob content. Note that this // is optional. Set the blob's content language. If specified, this property is stored with the blob and returned with
// hash is not validated, as the hashes for the individual blocks were validated when each was uploaded. // a read request. blobContentMD5 is optional. An MD5 hash of the blob content. Note that this hash is not validated,
// blobCacheControl is optional. Sets the blob's cache control. If specified, this property is stored with the blob and // as the hashes for the individual blocks were validated when each was uploaded. blobCacheControl is optional. Sets
// returned with a read request. metadata is optional. Specifies a user-defined name-value pair associated with the // the blob's cache control. If specified, this property is stored with the blob and returned with a read request.
// blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the // metadata is optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are
// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified // specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more
// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, // name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not
// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and // copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the
// Metadata for more information. leaseID is if specified, the operation only succeeds if the resource's lease is // naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information.
// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. // leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified // blobContentDisposition is optional. Sets the blob's Content-Disposition header. encryptionKey is optional. Specifies
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified // the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed
// since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value. // with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services.
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a // encryptionKeySha256 is the SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key
// header is provided. encryptionAlgorithm is the algorithm used to produce the encryption key hash. Currently, the
// only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. encryptionScope is
// optional. Version 2019-07-07 and later. Specifies the name of the encryption scope to use to encrypt the data
// provided in the request. If not specified, encryption is performed with the default account encryption scope. For
// more information, see Encryption at Rest for Azure Storage Services. tier is optional. Indicates the tier to be set
// on the blob. ifModifiedSince is specify this header value to operate only on a blob if it has been modified since
// the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been
// modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching
// value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. ifTags is specify a
// SQL where clause on blob tags to operate only on blobs with a matching value. requestID is provides a
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
// analytics logging is enabled. // analytics logging is enabled. blobTagsString is optional. Used to set blob tags in various blob operations.
func (client blockBlobClient) Upload(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlockBlobUploadResponse, error) { func (client blockBlobClient) Upload(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, tier AccessTierType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string, blobTagsString *string) (*BlockBlobUploadResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: body, {targetValue: body,
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
@ -429,7 +530,7 @@ func (client blockBlobClient) Upload(ctx context.Context, body io.ReadSeeker, co
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.uploadPreparer(body, contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID) req, err := client.uploadPreparer(body, contentLength, timeout, transactionalContentMD5, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, tier, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, requestID, blobTagsString)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -441,7 +542,7 @@ func (client blockBlobClient) Upload(ctx context.Context, body io.ReadSeeker, co
} }
// uploadPreparer prepares the Upload request. // uploadPreparer prepares the Upload request.
func (client blockBlobClient) uploadPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blockBlobClient) uploadPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, tier AccessTierType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string, blobTagsString *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, body) req, err := pipeline.NewRequest("PUT", client.url, body)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -451,6 +552,9 @@ func (client blockBlobClient) uploadPreparer(body io.ReadSeeker, contentLength i
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
} }
req.URL.RawQuery = params.Encode() req.URL.RawQuery = params.Encode()
if transactionalContentMD5 != nil {
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
}
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
if blobContentType != nil { if blobContentType != nil {
req.Header.Set("x-ms-blob-content-type", *blobContentType) req.Header.Set("x-ms-blob-content-type", *blobContentType)
@ -478,6 +582,21 @@ func (client blockBlobClient) uploadPreparer(body io.ReadSeeker, contentLength i
if blobContentDisposition != nil { if blobContentDisposition != nil {
req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition) req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition)
} }
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if tier != AccessTierNone {
req.Header.Set("x-ms-access-tier", string(tier))
}
if ifModifiedSince != nil { if ifModifiedSince != nil {
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
} }
@ -490,10 +609,16 @@ func (client blockBlobClient) uploadPreparer(body io.ReadSeeker, contentLength i
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
req.Header.Set("x-ms-version", ServiceVersion) req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
} }
if blobTagsString != nil {
req.Header.Set("x-ms-tags", *blobTagsString)
}
req.Header.Set("x-ms-blob-type", "BlockBlob") req.Header.Set("x-ms-blob-type", "BlockBlob")
return req, nil return req, nil
} }

View file

@ -10,7 +10,7 @@ import (
const ( const (
// ServiceVersion specifies the version of the operations used in this package. // ServiceVersion specifies the version of the operations used in this package.
ServiceVersion = "2018-11-09" ServiceVersion = "2019-12-12"
) )
// managementClient is the base client for Azblob. // managementClient is the base client for Azblob.

View file

@ -259,14 +259,18 @@ func (client containerClient) changeLeaseResponder(resp pipeline.Response) (pipe
// Containers, Blobs, and Metadata for more information. access is specifies whether data in the container may be // Containers, Blobs, and Metadata for more information. access is specifies whether data in the container may be
// accessed publicly and the level of access requestID is provides a client-generated, opaque value with a 1 KB // accessed publicly and the level of access requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled. // character limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client containerClient) Create(ctx context.Context, timeout *int32, metadata map[string]string, access PublicAccessType, requestID *string) (*ContainerCreateResponse, error) { // defaultEncryptionScope is optional. Version 2019-07-07 and later. Specifies the default encryption scope to set on
// the container and use for all future writes. preventEncryptionScopeOverride is optional. Version 2019-07-07 and
// newer. If true, prevents any request from specifying a different encryption scope than the scope set on the
// container.
func (client containerClient) Create(ctx context.Context, timeout *int32, metadata map[string]string, access PublicAccessType, requestID *string, defaultEncryptionScope *string, preventEncryptionScopeOverride *bool) (*ContainerCreateResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.createPreparer(timeout, metadata, access, requestID) req, err := client.createPreparer(timeout, metadata, access, requestID, defaultEncryptionScope, preventEncryptionScopeOverride)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -278,7 +282,7 @@ func (client containerClient) Create(ctx context.Context, timeout *int32, metada
} }
// createPreparer prepares the Create request. // createPreparer prepares the Create request.
func (client containerClient) createPreparer(timeout *int32, metadata map[string]string, access PublicAccessType, requestID *string) (pipeline.Request, error) { func (client containerClient) createPreparer(timeout *int32, metadata map[string]string, access PublicAccessType, requestID *string, defaultEncryptionScope *string, preventEncryptionScopeOverride *bool) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -301,6 +305,12 @@ func (client containerClient) createPreparer(timeout *int32, metadata map[string
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
} }
if defaultEncryptionScope != nil {
req.Header.Set("x-ms-default-encryption-scope", *defaultEncryptionScope)
}
if preventEncryptionScopeOverride != nil {
req.Header.Set("x-ms-deny-encryption-scope-override", strconv.FormatBool(*preventEncryptionScopeOverride))
}
return req, nil return req, nil
} }
@ -881,6 +891,70 @@ func (client containerClient) renewLeaseResponder(resp pipeline.Response) (pipel
return &ContainerRenewLeaseResponse{rawResponse: resp.Response()}, err return &ContainerRenewLeaseResponse{rawResponse: resp.Response()}, err
} }
// Restore restores a previously-deleted container.
//
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
// deletedContainerName is optional. Version 2019-12-12 and laster. Specifies the name of the deleted container to
// restore. deletedContainerVersion is optional. Version 2019-12-12 and laster. Specifies the version of the deleted
// container to restore.
func (client containerClient) Restore(ctx context.Context, timeout *int32, requestID *string, deletedContainerName *string, deletedContainerVersion *string) (*ContainerRestoreResponse, error) {
if err := validate([]validation{
{targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err
}
req, err := client.restorePreparer(timeout, requestID, deletedContainerName, deletedContainerVersion)
if err != nil {
return nil, err
}
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.restoreResponder}, req)
if err != nil {
return nil, err
}
return resp.(*ContainerRestoreResponse), err
}
// restorePreparer prepares the Restore request.
func (client containerClient) restorePreparer(timeout *int32, requestID *string, deletedContainerName *string, deletedContainerVersion *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil {
return req, pipeline.NewError(err, "failed to create request")
}
params := req.URL.Query()
if timeout != nil {
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
}
params.Set("restype", "container")
params.Set("comp", "undelete")
req.URL.RawQuery = params.Encode()
req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID)
}
if deletedContainerName != nil {
req.Header.Set("x-ms-deleted-container-name", *deletedContainerName)
}
if deletedContainerVersion != nil {
req.Header.Set("x-ms-deleted-container-version", *deletedContainerVersion)
}
return req, nil
}
// restoreResponder handles the response to the Restore request.
func (client containerClient) restoreResponder(resp pipeline.Response) (pipeline.Response, error) {
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
if resp == nil {
return nil, err
}
io.Copy(ioutil.Discard, resp.Response().Body)
resp.Response().Body.Close()
return &ContainerRestoreResponse{rawResponse: resp.Response()}, err
}
// SetAccessPolicy sets the permissions for the specified container. The permissions indicate whether blobs in a // SetAccessPolicy sets the permissions for the specified container. The permissions indicate whether blobs in a
// container may be accessed publicly. // container may be accessed publicly.
// //

File diff suppressed because it is too large Load diff

View file

@ -33,6 +33,14 @@ func newPageBlobClient(url url.URL, p pipeline.Pipeline) pageBlobClient {
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified // Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified
// range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID. // range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
// encryptionKey is optional. Specifies the encryption key to use to encrypt the data provided in the request. If not
// specified, encryption is performed with the root account encryption key. For more information, see Encryption at
// Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the provided encryption key. Must be
// provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the algorithm used to produce the
// encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key
// header is provided. encryptionScope is optional. Version 2019-07-07 and later. Specifies the name of the encryption
// scope to use to encrypt the data provided in the request. If not specified, encryption is performed with the default
// account encryption scope. For more information, see Encryption at Rest for Azure Storage Services.
// ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has a sequence number // ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has a sequence number
// less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to operate only on a blob // less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to operate only on a blob
// if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this header value to operate // if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this header value to operate
@ -42,14 +50,14 @@ func newPageBlobClient(url url.URL, p pipeline.Pipeline) pageBlobClient {
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs // to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs
// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is // without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is
// recorded in the analytics logs when storage analytics logging is enabled. // recorded in the analytics logs when storage analytics logging is enabled.
func (client pageBlobClient) ClearPages(ctx context.Context, contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobClearPagesResponse, error) { func (client pageBlobClient) ClearPages(ctx context.Context, contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobClearPagesResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.clearPagesPreparer(contentLength, timeout, rangeParameter, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID) req, err := client.clearPagesPreparer(contentLength, timeout, rangeParameter, leaseID, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -61,7 +69,7 @@ func (client pageBlobClient) ClearPages(ctx context.Context, contentLength int64
} }
// clearPagesPreparer prepares the ClearPages request. // clearPagesPreparer prepares the ClearPages request.
func (client pageBlobClient) clearPagesPreparer(contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) clearPagesPreparer(contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -79,6 +87,18 @@ func (client pageBlobClient) clearPagesPreparer(contentLength int64, timeout *in
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if ifSequenceNumberLessThanOrEqualTo != nil { if ifSequenceNumberLessThanOrEqualTo != nil {
req.Header.Set("x-ms-if-sequence-number-le", strconv.FormatInt(*ifSequenceNumberLessThanOrEqualTo, 10)) req.Header.Set("x-ms-if-sequence-number-le", strconv.FormatInt(*ifSequenceNumberLessThanOrEqualTo, 10))
} }
@ -202,35 +222,45 @@ func (client pageBlobClient) copyIncrementalResponder(resp pipeline.Response) (p
// blob, up to 1 TB. The page blob size must be aligned to a 512-byte boundary. timeout is the timeout parameter is // blob, up to 1 TB. The page blob size must be aligned to a 512-byte boundary. timeout is the timeout parameter is
// expressed in seconds. For more information, see <a // expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> blobContentType is optional. Sets the blob's content type. If specified, // Timeouts for Blob Service Operations.</a> tier is optional. Indicates the tier to be set on the page blob.
// this property is stored with the blob and returned with a read request. blobContentEncoding is optional. Sets the // blobContentType is optional. Sets the blob's content type. If specified, this property is stored with the blob and
// blob's content encoding. If specified, this property is stored with the blob and returned with a read request. // returned with a read request. blobContentEncoding is optional. Sets the blob's content encoding. If specified, this
// blobContentLanguage is optional. Set the blob's content language. If specified, this property is stored with the // property is stored with the blob and returned with a read request. blobContentLanguage is optional. Set the blob's
// blob and returned with a read request. blobContentMD5 is optional. An MD5 hash of the blob content. Note that this // content language. If specified, this property is stored with the blob and returned with a read request.
// hash is not validated, as the hashes for the individual blocks were validated when each was uploaded. // blobContentMD5 is optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for
// blobCacheControl is optional. Sets the blob's cache control. If specified, this property is stored with the blob and // the individual blocks were validated when each was uploaded. blobCacheControl is optional. Sets the blob's cache
// returned with a read request. metadata is optional. Specifies a user-defined name-value pair associated with the // control. If specified, this property is stored with the blob and returned with a read request. metadata is optional.
// blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the // Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the
// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified // operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value
// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, // pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from
// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and // the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules
// Metadata for more information. leaseID is if specified, the operation only succeeds if the resource's lease is // for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. leaseID is if
// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. // specified, the operation only succeeds if the resource's lease is active and matches this ID. blobContentDisposition
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified // is optional. Sets the blob's Content-Disposition header. encryptionKey is optional. Specifies the encryption key to
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified // use to encrypt the data provided in the request. If not specified, encryption is performed with the root account
// since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value. // encryption key. For more information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. blobSequenceNumber is set // SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided.
// for page blobs only. The sequence number is a user-controlled value that you can use to track requests. The value of // encryptionAlgorithm is the algorithm used to produce the encryption key hash. Currently, the only accepted value is
// the sequence number must be between 0 and 2^63 - 1. requestID is provides a client-generated, opaque value with a 1 // "AES256". Must be provided if the x-ms-encryption-key header is provided. encryptionScope is optional. Version
// KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. // 2019-07-07 and later. Specifies the name of the encryption scope to use to encrypt the data provided in the
func (client pageBlobClient) Create(ctx context.Context, contentLength int64, blobContentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (*PageBlobCreateResponse, error) { // request. If not specified, encryption is performed with the default account encryption scope. For more information,
// see Encryption at Rest for Azure Storage Services. ifModifiedSince is specify this header value to operate only on a
// blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to
// operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs
// without a matching value. ifTags is specify a SQL where clause on blob tags to operate only on blobs with a matching
// value. blobSequenceNumber is set for page blobs only. The sequence number is a user-controlled value that you can
// use to track requests. The value of the sequence number must be between 0 and 2^63 - 1. requestID is provides a
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
// analytics logging is enabled. blobTagsString is optional. Used to set blob tags in various blob operations.
func (client pageBlobClient) Create(ctx context.Context, contentLength int64, blobContentLength int64, timeout *int32, tier PremiumPageBlobAccessTierType, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, blobSequenceNumber *int64, requestID *string, blobTagsString *string) (*PageBlobCreateResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.createPreparer(contentLength, blobContentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, blobSequenceNumber, requestID) req, err := client.createPreparer(contentLength, blobContentLength, timeout, tier, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, blobSequenceNumber, requestID, blobTagsString)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -242,7 +272,7 @@ func (client pageBlobClient) Create(ctx context.Context, contentLength int64, bl
} }
// createPreparer prepares the Create request. // createPreparer prepares the Create request.
func (client pageBlobClient) createPreparer(contentLength int64, blobContentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) createPreparer(contentLength int64, blobContentLength int64, timeout *int32, tier PremiumPageBlobAccessTierType, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, blobSequenceNumber *int64, requestID *string, blobTagsString *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -253,6 +283,9 @@ func (client pageBlobClient) createPreparer(contentLength int64, blobContentLeng
} }
req.URL.RawQuery = params.Encode() req.URL.RawQuery = params.Encode()
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
if tier != PremiumPageBlobAccessTierNone {
req.Header.Set("x-ms-access-tier", string(tier))
}
if blobContentType != nil { if blobContentType != nil {
req.Header.Set("x-ms-blob-content-type", *blobContentType) req.Header.Set("x-ms-blob-content-type", *blobContentType)
} }
@ -279,6 +312,18 @@ func (client pageBlobClient) createPreparer(contentLength int64, blobContentLeng
if blobContentDisposition != nil { if blobContentDisposition != nil {
req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition) req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition)
} }
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if ifModifiedSince != nil { if ifModifiedSince != nil {
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
} }
@ -291,6 +336,9 @@ func (client pageBlobClient) createPreparer(contentLength int64, blobContentLeng
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
req.Header.Set("x-ms-blob-content-length", strconv.FormatInt(blobContentLength, 10)) req.Header.Set("x-ms-blob-content-length", strconv.FormatInt(blobContentLength, 10))
if blobSequenceNumber != nil { if blobSequenceNumber != nil {
req.Header.Set("x-ms-blob-sequence-number", strconv.FormatInt(*blobSequenceNumber, 10)) req.Header.Set("x-ms-blob-sequence-number", strconv.FormatInt(*blobSequenceNumber, 10))
@ -299,6 +347,9 @@ func (client pageBlobClient) createPreparer(contentLength int64, blobContentLeng
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
} }
if blobTagsString != nil {
req.Header.Set("x-ms-tags", *blobTagsString)
}
req.Header.Set("x-ms-blob-type", "PageBlob") req.Header.Set("x-ms-blob-type", "PageBlob")
return req, nil return req, nil
} }
@ -327,17 +378,18 @@ func (client pageBlobClient) createResponder(resp pipeline.Response) (pipeline.R
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified // ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified // date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified
// since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value. // since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value.
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a // ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. ifTags is specify a SQL
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // where clause on blob tags to operate only on blobs with a matching value. requestID is provides a client-generated,
// analytics logging is enabled. // opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is
func (client pageBlobClient) GetPageRanges(ctx context.Context, snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageList, error) { // enabled.
func (client pageBlobClient) GetPageRanges(ctx context.Context, snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string) (*PageList, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.getPageRangesPreparer(snapshot, timeout, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID) req, err := client.getPageRangesPreparer(snapshot, timeout, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -349,7 +401,7 @@ func (client pageBlobClient) GetPageRanges(ctx context.Context, snapshot *string
} }
// getPageRangesPreparer prepares the GetPageRanges request. // getPageRangesPreparer prepares the GetPageRanges request.
func (client pageBlobClient) getPageRangesPreparer(snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) getPageRangesPreparer(snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil) req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -381,6 +433,9 @@ func (client pageBlobClient) getPageRangesPreparer(snapshot *string, timeout *in
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
req.Header.Set("x-ms-version", ServiceVersion) req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
@ -425,22 +480,25 @@ func (client pageBlobClient) getPageRangesResponder(resp pipeline.Response) (pip
// parameter is a DateTime value that specifies that the response will contain only pages that were changed between // parameter is a DateTime value that specifies that the response will contain only pages that were changed between
// target blob and previous snapshot. Changed pages include both updated and cleared pages. The target blob may be a // target blob and previous snapshot. Changed pages include both updated and cleared pages. The target blob may be a
// snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. Note that incremental snapshots // snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. Note that incremental snapshots
// are currently supported only for blobs created on or after January 1, 2016. rangeParameter is return only the bytes // are currently supported only for blobs created on or after January 1, 2016. prevSnapshotURL is optional. This header
// of the blob in the specified range. leaseID is if specified, the operation only succeeds if the resource's lease is // is only supported in service versions 2019-04-19 and after and specifies the URL of a previous snapshot of the
// active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it has been // target blob. The response will only contain pages that were changed between the target blob and its previous
// modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if // snapshot. rangeParameter is return only the bytes of the blob in the specified range. leaseID is if specified, the
// it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs // operation only succeeds if the resource's lease is active and matches this ID. ifModifiedSince is specify this
// with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. // header value to operate only on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is
// requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics // specify this header value to operate only on a blob if it has not been modified since the specified date/time.
// logs when storage analytics logging is enabled. // ifMatch is specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is specify an ETag
func (client pageBlobClient) GetPageRangesDiff(ctx context.Context, snapshot *string, timeout *int32, prevsnapshot *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageList, error) { // value to operate only on blobs without a matching value. ifTags is specify a SQL where clause on blob tags to
// operate only on blobs with a matching value. requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client pageBlobClient) GetPageRangesDiff(ctx context.Context, snapshot *string, timeout *int32, prevsnapshot *string, prevSnapshotURL *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string) (*PageList, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.getPageRangesDiffPreparer(snapshot, timeout, prevsnapshot, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID) req, err := client.getPageRangesDiffPreparer(snapshot, timeout, prevsnapshot, prevSnapshotURL, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -452,7 +510,7 @@ func (client pageBlobClient) GetPageRangesDiff(ctx context.Context, snapshot *st
} }
// getPageRangesDiffPreparer prepares the GetPageRangesDiff request. // getPageRangesDiffPreparer prepares the GetPageRangesDiff request.
func (client pageBlobClient) getPageRangesDiffPreparer(snapshot *string, timeout *int32, prevsnapshot *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) getPageRangesDiffPreparer(snapshot *string, timeout *int32, prevsnapshot *string, prevSnapshotURL *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil) req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -469,6 +527,9 @@ func (client pageBlobClient) getPageRangesDiffPreparer(snapshot *string, timeout
} }
params.Set("comp", "pagelist") params.Set("comp", "pagelist")
req.URL.RawQuery = params.Encode() req.URL.RawQuery = params.Encode()
if prevSnapshotURL != nil {
req.Header.Set("x-ms-previous-snapshot-url", *prevSnapshotURL)
}
if rangeParameter != nil { if rangeParameter != nil {
req.Header.Set("x-ms-range", *rangeParameter) req.Header.Set("x-ms-range", *rangeParameter)
} }
@ -487,6 +548,9 @@ func (client pageBlobClient) getPageRangesDiffPreparer(snapshot *string, timeout
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
req.Header.Set("x-ms-version", ServiceVersion) req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
@ -526,20 +590,28 @@ func (client pageBlobClient) getPageRangesDiffResponder(resp pipeline.Response)
// see <a // see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it // lease is active and matches this ID. encryptionKey is optional. Specifies the encryption key to use to encrypt the
// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a // data provided in the request. If not specified, encryption is performed with the root account encryption key. For
// blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on // more information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the
// blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. // provided encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the
// requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics // algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided
// logs when storage analytics logging is enabled. // if the x-ms-encryption-key header is provided. encryptionScope is optional. Version 2019-07-07 and later. Specifies
func (client pageBlobClient) Resize(ctx context.Context, blobContentLength int64, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobResizeResponse, error) { // the name of the encryption scope to use to encrypt the data provided in the request. If not specified, encryption is
// performed with the default account encryption scope. For more information, see Encryption at Rest for Azure Storage
// Services. ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the
// specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been
// modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching
// value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides
// a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
// analytics logging is enabled.
func (client pageBlobClient) Resize(ctx context.Context, blobContentLength int64, timeout *int32, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobResizeResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.resizePreparer(blobContentLength, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID) req, err := client.resizePreparer(blobContentLength, timeout, leaseID, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -551,7 +623,7 @@ func (client pageBlobClient) Resize(ctx context.Context, blobContentLength int64
} }
// resizePreparer prepares the Resize request. // resizePreparer prepares the Resize request.
func (client pageBlobClient) resizePreparer(blobContentLength int64, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) resizePreparer(blobContentLength int64, timeout *int32, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -565,6 +637,18 @@ func (client pageBlobClient) resizePreparer(blobContentLength int64, timeout *in
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if ifModifiedSince != nil { if ifModifiedSince != nil {
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
} }
@ -682,11 +766,19 @@ func (client pageBlobClient) updateSequenceNumberResponder(resp pipeline.Respons
// //
// body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an // body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an
// error.contentLength is the length of the request. transactionalContentMD5 is specify the transactional md5 for the // error.contentLength is the length of the request. transactionalContentMD5 is specify the transactional md5 for the
// body, to be validated by the service. timeout is the timeout parameter is expressed in seconds. For more // body, to be validated by the service. transactionalContentCrc64 is specify the transactional crc64 for the body, to
// information, see <a // be validated by the service. timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified // Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified
// range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID. // range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
// encryptionKey is optional. Specifies the encryption key to use to encrypt the data provided in the request. If not
// specified, encryption is performed with the root account encryption key. For more information, see Encryption at
// Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the provided encryption key. Must be
// provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the algorithm used to produce the
// encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key
// header is provided. encryptionScope is optional. Version 2019-07-07 and later. Specifies the name of the encryption
// scope to use to encrypt the data provided in the request. If not specified, encryption is performed with the default
// account encryption scope. For more information, see Encryption at Rest for Azure Storage Services.
// ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has a sequence number // ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has a sequence number
// less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to operate only on a blob // less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to operate only on a blob
// if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this header value to operate // if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this header value to operate
@ -694,9 +786,10 @@ func (client pageBlobClient) updateSequenceNumberResponder(resp pipeline.Respons
// on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to // on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to
// operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value // operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs // to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs
// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is // without a matching value. ifTags is specify a SQL where clause on blob tags to operate only on blobs with a matching
// recorded in the analytics logs when storage analytics logging is enabled. // value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the
func (client pageBlobClient) UploadPages(ctx context.Context, body io.ReadSeeker, contentLength int64, transactionalContentMD5 []byte, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobUploadPagesResponse, error) { // analytics logs when storage analytics logging is enabled.
func (client pageBlobClient) UploadPages(ctx context.Context, body io.ReadSeeker, contentLength int64, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, timeout *int32, rangeParameter *string, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string) (*PageBlobUploadPagesResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: body, {targetValue: body,
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
@ -705,7 +798,7 @@ func (client pageBlobClient) UploadPages(ctx context.Context, body io.ReadSeeker
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.uploadPagesPreparer(body, contentLength, transactionalContentMD5, timeout, rangeParameter, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID) req, err := client.uploadPagesPreparer(body, contentLength, transactionalContentMD5, transactionalContentCrc64, timeout, rangeParameter, leaseID, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -717,7 +810,7 @@ func (client pageBlobClient) UploadPages(ctx context.Context, body io.ReadSeeker
} }
// uploadPagesPreparer prepares the UploadPages request. // uploadPagesPreparer prepares the UploadPages request.
func (client pageBlobClient) uploadPagesPreparer(body io.ReadSeeker, contentLength int64, transactionalContentMD5 []byte, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) uploadPagesPreparer(body io.ReadSeeker, contentLength int64, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, timeout *int32, rangeParameter *string, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, body) req, err := pipeline.NewRequest("PUT", client.url, body)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -732,12 +825,27 @@ func (client pageBlobClient) uploadPagesPreparer(body io.ReadSeeker, contentLeng
if transactionalContentMD5 != nil { if transactionalContentMD5 != nil {
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5)) req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
} }
if transactionalContentCrc64 != nil {
req.Header.Set("x-ms-content-crc64", base64.StdEncoding.EncodeToString(transactionalContentCrc64))
}
if rangeParameter != nil { if rangeParameter != nil {
req.Header.Set("x-ms-range", *rangeParameter) req.Header.Set("x-ms-range", *rangeParameter)
} }
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if ifSequenceNumberLessThanOrEqualTo != nil { if ifSequenceNumberLessThanOrEqualTo != nil {
req.Header.Set("x-ms-if-sequence-number-le", strconv.FormatInt(*ifSequenceNumberLessThanOrEqualTo, 10)) req.Header.Set("x-ms-if-sequence-number-le", strconv.FormatInt(*ifSequenceNumberLessThanOrEqualTo, 10))
} }
@ -759,6 +867,9 @@ func (client pageBlobClient) uploadPagesPreparer(body io.ReadSeeker, contentLeng
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
req.Header.Set("x-ms-version", ServiceVersion) req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
@ -785,32 +896,41 @@ func (client pageBlobClient) uploadPagesResponder(resp pipeline.Response) (pipel
// length of this range should match the ContentLength header and x-ms-range/Range destination range header. // length of this range should match the ContentLength header and x-ms-range/Range destination range header.
// contentLength is the length of the request. rangeParameter is the range of bytes to which the source range would be // contentLength is the length of the request. rangeParameter is the range of bytes to which the source range would be
// written. The range should be 512 aligned and range-end is required. sourceContentMD5 is specify the md5 calculated // written. The range should be 512 aligned and range-end is required. sourceContentMD5 is specify the md5 calculated
// for the range of bytes that must be read from the copy source. sourceContentcrc64 is specify the crc64 calculated
// for the range of bytes that must be read from the copy source. timeout is the timeout parameter is expressed in // for the range of bytes that must be read from the copy source. timeout is the timeout parameter is expressed in
// seconds. For more information, see <a // seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's // Timeouts for Blob Service Operations.</a> encryptionKey is optional. Specifies the encryption key to use to encrypt
// lease is active and matches this ID. ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only // the data provided in the request. If not specified, encryption is performed with the root account encryption key.
// on a blob if it has a sequence number less than or equal to the specified. ifSequenceNumberLessThan is specify this // For more information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of
// header value to operate only on a blob if it has a sequence number less than the specified. ifSequenceNumberEqualTo // the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is
// is specify this header value to operate only on a blob if it has the specified sequence number. ifModifiedSince is // the algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be
// specify this header value to operate only on a blob if it has been modified since the specified date/time. // provided if the x-ms-encryption-key header is provided. encryptionScope is optional. Version 2019-07-07 and later.
// ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified since the // Specifies the name of the encryption scope to use to encrypt the data provided in the request. If not specified,
// specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is // encryption is performed with the default account encryption scope. For more information, see Encryption at Rest for
// specify an ETag value to operate only on blobs without a matching value. sourceIfModifiedSince is specify this // Azure Storage Services. leaseID is if specified, the operation only succeeds if the resource's lease is active and
// header value to operate only on a blob if it has been modified since the specified date/time. // matches this ID. ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has
// sourceIfUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified since the // a sequence number less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to
// specified date/time. sourceIfMatch is specify an ETag value to operate only on blobs with a matching value. // operate only on a blob if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this
// sourceIfNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides // header value to operate only on a blob if it has the specified sequence number. ifModifiedSince is specify this
// a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // header value to operate only on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is
// analytics logging is enabled. // specify this header value to operate only on a blob if it has not been modified since the specified date/time.
func (client pageBlobClient) UploadPagesFromURL(ctx context.Context, sourceURL string, sourceRange string, contentLength int64, rangeParameter string, sourceContentMD5 []byte, timeout *int32, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (*PageBlobUploadPagesFromURLResponse, error) { // ifMatch is specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is specify an ETag
// value to operate only on blobs without a matching value. ifTags is specify a SQL where clause on blob tags to
// operate only on blobs with a matching value. sourceIfModifiedSince is specify this header value to operate only on a
// blob if it has been modified since the specified date/time. sourceIfUnmodifiedSince is specify this header value to
// operate only on a blob if it has not been modified since the specified date/time. sourceIfMatch is specify an ETag
// value to operate only on blobs with a matching value. sourceIfNoneMatch is specify an ETag value to operate only on
// blobs without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit
// that is recorded in the analytics logs when storage analytics logging is enabled.
func (client pageBlobClient) UploadPagesFromURL(ctx context.Context, sourceURL string, sourceRange string, contentLength int64, rangeParameter string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (*PageBlobUploadPagesFromURLResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.uploadPagesFromURLPreparer(sourceURL, sourceRange, contentLength, rangeParameter, sourceContentMD5, timeout, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, requestID) req, err := client.uploadPagesFromURLPreparer(sourceURL, sourceRange, contentLength, rangeParameter, sourceContentMD5, sourceContentcrc64, timeout, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -822,7 +942,7 @@ func (client pageBlobClient) UploadPagesFromURL(ctx context.Context, sourceURL s
} }
// uploadPagesFromURLPreparer prepares the UploadPagesFromURL request. // uploadPagesFromURLPreparer prepares the UploadPagesFromURL request.
func (client pageBlobClient) uploadPagesFromURLPreparer(sourceURL string, sourceRange string, contentLength int64, rangeParameter string, sourceContentMD5 []byte, timeout *int32, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) uploadPagesFromURLPreparer(sourceURL string, sourceRange string, contentLength int64, rangeParameter string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, encryptionScope *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, ifTags *string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -838,8 +958,23 @@ func (client pageBlobClient) uploadPagesFromURLPreparer(sourceURL string, source
if sourceContentMD5 != nil { if sourceContentMD5 != nil {
req.Header.Set("x-ms-source-content-md5", base64.StdEncoding.EncodeToString(sourceContentMD5)) req.Header.Set("x-ms-source-content-md5", base64.StdEncoding.EncodeToString(sourceContentMD5))
} }
if sourceContentcrc64 != nil {
req.Header.Set("x-ms-source-content-crc64", base64.StdEncoding.EncodeToString(sourceContentcrc64))
}
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
req.Header.Set("x-ms-range", rangeParameter) req.Header.Set("x-ms-range", rangeParameter)
if encryptionKey != nil {
req.Header.Set("x-ms-encryption-key", *encryptionKey)
}
if encryptionKeySha256 != nil {
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
}
if encryptionAlgorithm != EncryptionAlgorithmNone {
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
}
if encryptionScope != nil {
req.Header.Set("x-ms-encryption-scope", *encryptionScope)
}
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
@ -864,6 +999,9 @@ func (client pageBlobClient) uploadPagesFromURLPreparer(sourceURL string, source
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if ifTags != nil {
req.Header.Set("x-ms-if-tags", *ifTags)
}
if sourceIfModifiedSince != nil { if sourceIfModifiedSince != nil {
req.Header.Set("x-ms-source-if-modified-since", (*sourceIfModifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("x-ms-source-if-modified-since", (*sourceIfModifiedSince).In(gmt).Format(time.RFC1123))
} }

View file

@ -25,6 +25,98 @@ func newServiceClient(url url.URL, p pipeline.Pipeline) serviceClient {
return serviceClient{newManagementClient(url, p)} return serviceClient{newManagementClient(url, p)}
} }
// FilterBlobs the Filter Blobs operation enables callers to list blobs across all containers whose tags match a given
// search expression. Filter blobs searches across all containers within a storage account but can be scoped within
// the expression to a single container.
//
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled. where is filters
// the results to return only to return only blobs whose tags match the specified expression. marker is a string value
// that identifies the portion of the list of containers to be returned with the next listing operation. The operation
// returns the NextMarker value within the response body if the listing operation did not return all containers
// remaining to be listed with the current page. The NextMarker value can be used as the value for the marker parameter
// in a subsequent call to request the next page of list items. The marker value is opaque to the client. maxresults is
// specifies the maximum number of containers to return. If the request does not specify maxresults, or specifies a
// value greater than 5000, the server will return up to 5000 items. Note that if the listing operation crosses a
// partition boundary, then the service will return a continuation token for retrieving the remainder of the results.
// For this reason, it is possible that the service will return fewer results than specified by maxresults, or than the
// default of 5000.
func (client serviceClient) FilterBlobs(ctx context.Context, timeout *int32, requestID *string, where *string, marker *string, maxresults *int32) (*FilterBlobSegment, error) {
if err := validate([]validation{
{targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}},
{targetValue: maxresults,
constraints: []constraint{{target: "maxresults", name: null, rule: false,
chain: []constraint{{target: "maxresults", name: inclusiveMinimum, rule: 1, chain: nil}}}}}}); err != nil {
return nil, err
}
req, err := client.filterBlobsPreparer(timeout, requestID, where, marker, maxresults)
if err != nil {
return nil, err
}
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.filterBlobsResponder}, req)
if err != nil {
return nil, err
}
return resp.(*FilterBlobSegment), err
}
// filterBlobsPreparer prepares the FilterBlobs request.
func (client serviceClient) filterBlobsPreparer(timeout *int32, requestID *string, where *string, marker *string, maxresults *int32) (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil {
return req, pipeline.NewError(err, "failed to create request")
}
params := req.URL.Query()
if timeout != nil {
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
}
if where != nil && len(*where) > 0 {
params.Set("where", *where)
}
if marker != nil && len(*marker) > 0 {
params.Set("marker", *marker)
}
if maxresults != nil {
params.Set("maxresults", strconv.FormatInt(int64(*maxresults), 10))
}
params.Set("comp", "blobs")
req.URL.RawQuery = params.Encode()
req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID)
}
return req, nil
}
// filterBlobsResponder handles the response to the FilterBlobs request.
func (client serviceClient) filterBlobsResponder(resp pipeline.Response) (pipeline.Response, error) {
err := validateResponse(resp, http.StatusOK)
if resp == nil {
return nil, err
}
result := &FilterBlobSegment{rawResponse: resp.Response()}
if err != nil {
return result, err
}
defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil {
return result, err
}
if len(b) > 0 {
b = removeBOM(b)
err = xml.Unmarshal(b, result)
if err != nil {
return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
}
}
return result, nil
}
// GetAccountInfo returns the sku name and account kind // GetAccountInfo returns the sku name and account kind
func (client serviceClient) GetAccountInfo(ctx context.Context) (*ServiceGetAccountInfoResponse, error) { func (client serviceClient) GetAccountInfo(ctx context.Context) (*ServiceGetAccountInfoResponse, error) {
req, err := client.getAccountInfoPreparer() req, err := client.getAccountInfoPreparer()
@ -203,7 +295,7 @@ func (client serviceClient) getStatisticsResponder(resp pipeline.Response) (pipe
return result, nil return result, nil
} }
// GetUserDelegationKey retrieves a user delgation key for the Blob service. This is only a valid operation when using // GetUserDelegationKey retrieves a user delegation key for the Blob service. This is only a valid operation when using
// bearer token authentication. // bearer token authentication.
// //
// timeout is the timeout parameter is expressed in seconds. For more information, see <a // timeout is the timeout parameter is expressed in seconds. For more information, see <a
@ -300,7 +392,7 @@ func (client serviceClient) getUserDelegationKeyResponder(resp pipeline.Response
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB // Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled. // character limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client serviceClient) ListContainersSegment(ctx context.Context, prefix *string, marker *string, maxresults *int32, include ListContainersIncludeType, timeout *int32, requestID *string) (*ListContainersSegmentResponse, error) { func (client serviceClient) ListContainersSegment(ctx context.Context, prefix *string, marker *string, maxresults *int32, include []ListContainersIncludeType, timeout *int32, requestID *string) (*ListContainersSegmentResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: maxresults, {targetValue: maxresults,
constraints: []constraint{{target: "maxresults", name: null, rule: false, constraints: []constraint{{target: "maxresults", name: null, rule: false,
@ -322,7 +414,7 @@ func (client serviceClient) ListContainersSegment(ctx context.Context, prefix *s
} }
// listContainersSegmentPreparer prepares the ListContainersSegment request. // listContainersSegmentPreparer prepares the ListContainersSegment request.
func (client serviceClient) listContainersSegmentPreparer(prefix *string, marker *string, maxresults *int32, include ListContainersIncludeType, timeout *int32, requestID *string) (pipeline.Request, error) { func (client serviceClient) listContainersSegmentPreparer(prefix *string, marker *string, maxresults *int32, include []ListContainersIncludeType, timeout *int32, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil) req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -337,8 +429,8 @@ func (client serviceClient) listContainersSegmentPreparer(prefix *string, marker
if maxresults != nil { if maxresults != nil {
params.Set("maxresults", strconv.FormatInt(int64(*maxresults), 10)) params.Set("maxresults", strconv.FormatInt(int64(*maxresults), 10))
} }
if include != ListContainersIncludeNone { if include != nil && len(include) > 0 {
params.Set("include", string(include)) params.Set("include", joinConst(include, ","))
} }
if timeout != nil { if timeout != nil {
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
@ -465,3 +557,62 @@ func (client serviceClient) setPropertiesResponder(resp pipeline.Response) (pipe
resp.Response().Body.Close() resp.Response().Body.Close()
return &ServiceSetPropertiesResponse{rawResponse: resp.Response()}, err return &ServiceSetPropertiesResponse{rawResponse: resp.Response()}, err
} }
// SubmitBatch the Batch operation allows multiple API calls to be embedded into a single HTTP request.
//
// body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an
// error.contentLength is the length of the request. multipartContentType is required. The value of this header must be
// multipart/mixed with a batch boundary. Example header value: multipart/mixed; boundary=batch_<GUID> timeout is the
// timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client serviceClient) SubmitBatch(ctx context.Context, body io.ReadSeeker, contentLength int64, multipartContentType string, timeout *int32, requestID *string) (*SubmitBatchResponse, error) {
if err := validate([]validation{
{targetValue: body,
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
{targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err
}
req, err := client.submitBatchPreparer(body, contentLength, multipartContentType, timeout, requestID)
if err != nil {
return nil, err
}
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.submitBatchResponder}, req)
if err != nil {
return nil, err
}
return resp.(*SubmitBatchResponse), err
}
// submitBatchPreparer prepares the SubmitBatch request.
func (client serviceClient) submitBatchPreparer(body io.ReadSeeker, contentLength int64, multipartContentType string, timeout *int32, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("POST", client.url, body)
if err != nil {
return req, pipeline.NewError(err, "failed to create request")
}
params := req.URL.Query()
if timeout != nil {
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
}
params.Set("comp", "batch")
req.URL.RawQuery = params.Encode()
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
req.Header.Set("Content-Type", multipartContentType)
req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID)
}
return req, nil
}
// submitBatchResponder handles the response to the SubmitBatch request.
func (client serviceClient) submitBatchResponder(resp pipeline.Response) (pipeline.Response, error) {
err := validateResponse(resp, http.StatusOK)
if resp == nil {
return nil, err
}
return &SubmitBatchResponse{rawResponse: resp.Response()}, err
}

View file

@ -5,7 +5,7 @@ package azblob
// UserAgent returns the UserAgent string to use when sending http.Requests. // UserAgent returns the UserAgent string to use when sending http.Requests.
func UserAgent() string { func UserAgent() string {
return "Azure-SDK-For-Go/0.0.0 azblob/2018-11-09" return "Azure-SDK-For-Go/0.0.0 azblob/2019-12-12"
} }
// Version returns the semantic version (see http://semver.org) of the client. // Version returns the semantic version (see http://semver.org) of the client.

View file

@ -45,7 +45,7 @@ func (dr downloadResponse) NewHTTPHeaders() BlobHTTPHeaders {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// DownloadResponse wraps AutoRest generated downloadResponse and helps to provide info for retry. // DownloadResponse wraps AutoRest generated DownloadResponse and helps to provide info for retry.
type DownloadResponse struct { type DownloadResponse struct {
r *downloadResponse r *downloadResponse
ctx context.Context ctx context.Context
@ -63,11 +63,9 @@ func (r *DownloadResponse) Body(o RetryReaderOptions) io.ReadCloser {
} }
return NewRetryReader(r.ctx, r.Response(), r.getInfo, o, return NewRetryReader(r.ctx, r.Response(), r.getInfo, o,
func(ctx context.Context, getInfo HTTPGetterInfo) (*http.Response, error) { func(ctx context.Context, getInfo HTTPGetterInfo) (*http.Response, error) {
resp, err := r.b.Download(ctx, getInfo.Offset, getInfo.Count, resp, err := r.b.Download(ctx, getInfo.Offset, getInfo.Count, BlobAccessConditions{
BlobAccessConditions{ ModifiedAccessConditions: ModifiedAccessConditions{IfMatch: getInfo.ETag},
ModifiedAccessConditions: ModifiedAccessConditions{IfMatch: getInfo.ETag}, }, false, o.ClientProvidedKeyOptions)
},
false)
if err != nil { if err != nil {
return nil, err return nil, err
} }

32
vendor/github.com/Azure/go-autorest/.gitignore generated vendored Normal file
View file

@ -0,0 +1,32 @@
# The standard Go .gitignore file follows. (Sourced from: github.com/github/gitignore/master/Go.gitignore)
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
.DS_Store
.idea/
.vscode/
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
# go-autorest specific
vendor/
autorest/azure/example/example

1004
vendor/github.com/Azure/go-autorest/CHANGELOG.md generated vendored Normal file

File diff suppressed because it is too large Load diff

23
vendor/github.com/Azure/go-autorest/GNUmakefile generated vendored Normal file
View file

@ -0,0 +1,23 @@
DIR?=./autorest/
default: build
build: fmt
go install $(DIR)
test:
go test $(DIR) || exit 1
vet:
@echo "go vet ."
@go vet $(DIR)... ; if [ $$? -eq 1 ]; then \
echo ""; \
echo "Vet found suspicious constructs. Please check the reported constructs"; \
echo "and fix them if necessary before submitting the code for review."; \
exit 1; \
fi
fmt:
gofmt -w $(DIR)
.PHONY: build test vet fmt

324
vendor/github.com/Azure/go-autorest/Gopkg.lock generated vendored Normal file
View file

@ -0,0 +1,324 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:892e39e5c083d0943f1e80ab8351690f183c6a5ab24e1d280adcad424c26255e"
name = "contrib.go.opencensus.io/exporter/ocagent"
packages = ["."]
pruneopts = "UT"
revision = "a8a6f458bbc1d5042322ad1f9b65eeb0b69be9ea"
version = "v0.6.0"
[[projects]]
digest = "1:8f5acd4d4462b5136af644d25101f0968a7a94ee90fcb2059cec5b7cc42e0b20"
name = "github.com/census-instrumentation/opencensus-proto"
packages = [
"gen-go/agent/common/v1",
"gen-go/agent/metrics/v1",
"gen-go/agent/trace/v1",
"gen-go/metrics/v1",
"gen-go/resource/v1",
"gen-go/trace/v1",
]
pruneopts = "UT"
revision = "d89fa54de508111353cb0b06403c00569be780d8"
version = "v0.2.1"
[[projects]]
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
pruneopts = "UT"
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
version = "v1.1.1"
[[projects]]
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
pruneopts = "UT"
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
version = "v3.2.0"
[[projects]]
digest = "1:cf0d2e435fd4ce45b789e93ef24b5f08e86be0e9807a16beb3694e2d8c9af965"
name = "github.com/dimchansky/utfbom"
packages = ["."]
pruneopts = "UT"
revision = "d2133a1ce379ef6fa992b0514a77146c60db9d1c"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:b7cb6054d3dff43b38ad2e92492f220f57ae6087ee797dca298139776749ace8"
name = "github.com/golang/groupcache"
packages = ["lru"]
pruneopts = "UT"
revision = "611e8accdfc92c4187d399e95ce826046d4c8d73"
[[projects]]
digest = "1:e3839df32927e8d3403cd5aa7253d966e8ff80fc8f10e2e35d146461cd83fcfa"
name = "github.com/golang/protobuf"
packages = [
"descriptor",
"jsonpb",
"proto",
"protoc-gen-go/descriptor",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/struct",
"ptypes/timestamp",
"ptypes/wrappers",
]
pruneopts = "UT"
revision = "6c65a5562fc06764971b7c5d05c76c75e84bdbf7"
version = "v1.3.2"
[[projects]]
digest = "1:c560cd79300fac84f124b96225181a637a70b60155919a3c36db50b7cca6b806"
name = "github.com/grpc-ecosystem/grpc-gateway"
packages = [
"internal",
"runtime",
"utilities",
]
pruneopts = "UT"
revision = "f7120437bb4f6c71f7f5076ad65a45310de2c009"
version = "v1.12.1"
[[projects]]
digest = "1:5d231480e1c64a726869bc4142d270184c419749d34f167646baa21008eb0a79"
name = "github.com/mitchellh/go-homedir"
packages = ["."]
pruneopts = "UT"
revision = "af06845cf3004701891bf4fdb884bfe4920b3727"
version = "v1.1.0"
[[projects]]
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
pruneopts = "UT"
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
digest = "1:99d32780e5238c2621fff621123997c3e3cca96db8be13179013aea77dfab551"
name = "github.com/stretchr/testify"
packages = [
"assert",
"require",
]
pruneopts = "UT"
revision = "221dbe5ed46703ee255b1da0dec05086f5035f62"
version = "v1.4.0"
[[projects]]
digest = "1:7c5e00383399fe13de0b4b65c9fdde16275407ce8ac02d867eafeaa916edcc71"
name = "go.opencensus.io"
packages = [
".",
"internal",
"internal/tagencoding",
"metric/metricdata",
"metric/metricproducer",
"plugin/ocgrpc",
"plugin/ochttp",
"plugin/ochttp/propagation/b3",
"plugin/ochttp/propagation/tracecontext",
"resource",
"stats",
"stats/internal",
"stats/view",
"tag",
"trace",
"trace/internal",
"trace/propagation",
"trace/tracestate",
]
pruneopts = "UT"
revision = "aad2c527c5defcf89b5afab7f37274304195a6b2"
version = "v0.22.2"
[[projects]]
branch = "master"
digest = "1:f604f5e2ee721b6757d962dfe7bab4f28aae50c456e39cfb2f3819762a44a6ae"
name = "golang.org/x/crypto"
packages = [
"pkcs12",
"pkcs12/internal/rc2",
]
pruneopts = "UT"
revision = "e9b2fee46413994441b28dfca259d911d963dfed"
[[projects]]
branch = "master"
digest = "1:334b27eac455cb6567ea28cd424230b07b1a64334a2f861a8075ac26ce10af43"
name = "golang.org/x/lint"
packages = [
".",
"golint",
]
pruneopts = "UT"
revision = "fdd1cda4f05fd1fd86124f0ef9ce31a0b72c8448"
[[projects]]
branch = "master"
digest = "1:257a75d024975428ab9192bfc334c3490882f8cb21322ea5784ca8eca000a910"
name = "golang.org/x/net"
packages = [
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/timeseries",
"trace",
]
pruneopts = "UT"
revision = "1ddd1de85cb0337b623b740a609d35817d516a8d"
[[projects]]
branch = "master"
digest = "1:382bb5a7fb4034db3b6a2d19e5a4a6bcf52f4750530603c01ca18a172fa3089b"
name = "golang.org/x/sync"
packages = ["semaphore"]
pruneopts = "UT"
revision = "cd5d95a43a6e21273425c7ae415d3df9ea832eeb"
[[projects]]
branch = "master"
digest = "1:4da420ceda5f68e8d748aa2169d0ed44ffadb1bbd6537cf778a49563104189b8"
name = "golang.org/x/sys"
packages = ["unix"]
pruneopts = "UT"
revision = "ce4227a45e2eb77e5c847278dcc6a626742e2945"
[[projects]]
digest = "1:8d8faad6b12a3a4c819a3f9618cb6ee1fa1cfc33253abeeea8b55336721e3405"
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/language",
"internal/language/compact",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable",
]
pruneopts = "UT"
revision = "342b2e1fbaa52c93f31447ad2c6abc048c63e475"
version = "v0.3.2"
[[projects]]
branch = "master"
digest = "1:4eb5ea8395fb60212dd58b92c9db80bab59d5e99c7435f9a6a0a528c373b60e7"
name = "golang.org/x/tools"
packages = [
"go/ast/astutil",
"go/gcexportdata",
"go/internal/gcimporter",
"go/types/typeutil",
]
pruneopts = "UT"
revision = "259af5ff87bdcd4abf2ecda8edc3f13f04f26a42"
[[projects]]
digest = "1:964bb30febc27fabfbec4759fa530c6ec35e77a7c85fed90b9317ea39a054877"
name = "google.golang.org/api"
packages = ["support/bundler"]
pruneopts = "UT"
revision = "8a410c21381766a810817fd6200fce8838ecb277"
version = "v0.14.0"
[[projects]]
branch = "master"
digest = "1:a8d5c2c6e746b3485e36908ab2a9e3d77b86b81f8156d88403c7d2b462431dfd"
name = "google.golang.org/genproto"
packages = [
"googleapis/api/httpbody",
"googleapis/rpc/status",
"protobuf/field_mask",
]
pruneopts = "UT"
revision = "51378566eb590fa106d1025ea12835a4416dda84"
[[projects]]
digest = "1:b59ce3ddb11daeeccccc9cb3183b58ebf8e9a779f1c853308cd91612e817a301"
name = "google.golang.org/grpc"
packages = [
".",
"backoff",
"balancer",
"balancer/base",
"balancer/roundrobin",
"binarylog/grpc_binarylog_v1",
"codes",
"connectivity",
"credentials",
"credentials/internal",
"encoding",
"encoding/proto",
"grpclog",
"internal",
"internal/backoff",
"internal/balancerload",
"internal/binarylog",
"internal/buffer",
"internal/channelz",
"internal/envconfig",
"internal/grpcrand",
"internal/grpcsync",
"internal/resolver/dns",
"internal/resolver/passthrough",
"internal/syscall",
"internal/transport",
"keepalive",
"metadata",
"naming",
"peer",
"resolver",
"serviceconfig",
"stats",
"status",
"tap",
]
pruneopts = "UT"
revision = "1a3960e4bd028ac0cec0a2afd27d7d8e67c11514"
version = "v1.25.1"
[[projects]]
digest = "1:b75b3deb2bce8bc079e16bb2aecfe01eb80098f5650f9e93e5643ca8b7b73737"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = "UT"
revision = "1f64d6156d11335c3f22d9330b0ad14fc1e789ce"
version = "v2.2.7"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"contrib.go.opencensus.io/exporter/ocagent",
"github.com/dgrijalva/jwt-go",
"github.com/dimchansky/utfbom",
"github.com/mitchellh/go-homedir",
"github.com/stretchr/testify/require",
"go.opencensus.io/plugin/ochttp",
"go.opencensus.io/plugin/ochttp/propagation/tracecontext",
"go.opencensus.io/stats/view",
"go.opencensus.io/trace",
"golang.org/x/crypto/pkcs12",
"golang.org/x/lint/golint",
]
solver-name = "gps-cdcl"
solver-version = 1

59
vendor/github.com/Azure/go-autorest/Gopkg.toml generated vendored Normal file
View file

@ -0,0 +1,59 @@
# Gopkg.toml example
#
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
required = ["golang.org/x/lint/golint"]
[prune]
go-tests = true
unused-packages = true
[[constraint]]
name = "contrib.go.opencensus.io/exporter/ocagent"
version = "0.6.0"
[[constraint]]
name = "github.com/dgrijalva/jwt-go"
version = "3.2.0"
[[constraint]]
name = "github.com/dimchansky/utfbom"
version = "1.1.0"
[[constraint]]
name = "github.com/mitchellh/go-homedir"
version = "1.1.0"
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.3.0"
[[constraint]]
name = "go.opencensus.io"
version = "0.22.0"
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"

191
vendor/github.com/Azure/go-autorest/LICENSE generated vendored Normal file
View file

@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor 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, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2015 Microsoft Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

165
vendor/github.com/Azure/go-autorest/README.md generated vendored Normal file
View file

@ -0,0 +1,165 @@
# go-autorest
[![GoDoc](https://godoc.org/github.com/Azure/go-autorest/autorest?status.png)](https://godoc.org/github.com/Azure/go-autorest/autorest)
[![Build Status](https://dev.azure.com/azure-sdk/public/_apis/build/status/go/Azure.go-autorest?branchName=master)](https://dev.azure.com/azure-sdk/public/_build/latest?definitionId=625&branchName=master)
[![Go Report Card](https://goreportcard.com/badge/Azure/go-autorest)](https://goreportcard.com/report/Azure/go-autorest)
Package go-autorest provides an HTTP request client for use with [Autorest](https://github.com/Azure/autorest.go)-generated API client packages.
An authentication client tested with Azure Active Directory (AAD) is also
provided in this repo in the package
`github.com/Azure/go-autorest/autorest/adal`. Despite its name, this package
is maintained only as part of the Azure Go SDK and is not related to other
"ADAL" libraries in [github.com/AzureAD](https://github.com/AzureAD).
## Overview
Package go-autorest implements an HTTP request pipeline suitable for use across
multiple goroutines and provides the shared routines used by packages generated
by [Autorest](https://github.com/Azure/autorest.go).
The package breaks sending and responding to HTTP requests into three phases: Preparing, Sending,
and Responding. A typical pattern is:
```go
req, err := Prepare(&http.Request{},
token.WithAuthorization())
resp, err := Send(req,
WithLogging(logger),
DoErrorIfStatusCode(http.StatusInternalServerError),
DoCloseIfError(),
DoRetryForAttempts(5, time.Second))
err = Respond(resp,
ByDiscardingBody(),
ByClosing())
```
Each phase relies on decorators to modify and / or manage processing. Decorators may first modify
and then pass the data along, pass the data first and then modify the result, or wrap themselves
around passing the data (such as a logger might do). Decorators run in the order provided. For
example, the following:
```go
req, err := Prepare(&http.Request{},
WithBaseURL("https://microsoft.com/"),
WithPath("a"),
WithPath("b"),
WithPath("c"))
```
will set the URL to:
```
https://microsoft.com/a/b/c
```
Preparers and Responders may be shared and re-used (assuming the underlying decorators support
sharing and re-use). Performant use is obtained by creating one or more Preparers and Responders
shared among multiple go-routines, and a single Sender shared among multiple sending go-routines,
all bound together by means of input / output channels.
Decorators hold their passed state within a closure (such as the path components in the example
above). Be careful to share Preparers and Responders only in a context where such held state
applies. For example, it may not make sense to share a Preparer that applies a query string from a
fixed set of values. Similarly, sharing a Responder that reads the response body into a passed
struct (e.g., `ByUnmarshallingJson`) is likely incorrect.
Errors raised by autorest objects and methods will conform to the `autorest.Error` interface.
See the included examples for more detail. For details on the suggested use of this package by
generated clients, see the Client described below.
## Helpers
### Handling Swagger Dates
The Swagger specification (https://swagger.io) that drives AutoRest
(https://github.com/Azure/autorest/) precisely defines two date forms: date and date-time. The
github.com/Azure/go-autorest/autorest/date package provides time.Time derivations to ensure correct
parsing and formatting.
### Handling Empty Values
In JSON, missing values have different semantics than empty values. This is especially true for
services using the HTTP PATCH verb. The JSON submitted with a PATCH request generally contains
only those values to modify. Missing values are to be left unchanged. Developers, then, require a
means to both specify an empty value and to leave the value out of the submitted JSON.
The Go JSON package (`encoding/json`) supports the `omitempty` tag. When specified, it omits
empty values from the rendered JSON. Since Go defines default values for all base types (such as ""
for string and 0 for int) and provides no means to mark a value as actually empty, the JSON package
treats default values as meaning empty, omitting them from the rendered JSON. This means that, using
the Go base types encoded through the default JSON package, it is not possible to create JSON to
clear a value at the server.
The workaround within the Go community is to use pointers to base types in lieu of base types within
structures that map to JSON. For example, instead of a value of type `string`, the workaround uses
`*string`. While this enables distinguishing empty values from those to be unchanged, creating
pointers to a base type (notably constant, in-line values) requires additional variables. This, for
example,
```go
s := struct {
S *string
}{ S: &"foo" }
```
fails, while, this
```go
v := "foo"
s := struct {
S *string
}{ S: &v }
```
succeeds.
To ease using pointers, the subpackage `to` contains helpers that convert to and from pointers for
Go base types which have Swagger analogs. It also provides a helper that converts between
`map[string]string` and `map[string]*string`, enabling the JSON to specify that the value
associated with a key should be cleared. With the helpers, the previous example becomes
```go
s := struct {
S *string
}{ S: to.StringPtr("foo") }
```
## Install
```bash
go get github.com/Azure/go-autorest/autorest
go get github.com/Azure/go-autorest/autorest/azure
go get github.com/Azure/go-autorest/autorest/date
go get github.com/Azure/go-autorest/autorest/to
```
### Using with Go Modules
In [v12.0.1](https://github.com/Azure/go-autorest/pull/386), this repository introduced the following modules.
- autorest/adal
- autorest/azure/auth
- autorest/azure/cli
- autorest/date
- autorest/mocks
- autorest/to
- autorest/validation
- autorest
- logger
- tracing
Tagging cumulative SDK releases as a whole (e.g. `v12.3.0`) is still enabled to support consumers of this repo that have not yet migrated to modules.
## License
See LICENSE file.
-----
This project has adopted the [Microsoft Open Source Code of
Conduct](https://opensource.microsoft.com/codeofconduct/). 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.

View file

@ -222,6 +222,10 @@ func CheckForUserCompletionWithContext(ctx context.Context, sender Sender, code
case "code_expired": case "code_expired":
return nil, ErrDeviceCodeExpired return nil, ErrDeviceCodeExpired
default: default:
// return a more meaningful error message if available
if token.ErrorDescription != nil {
return nil, fmt.Errorf("%s %s: %s", logPrefix, *token.Error, *token.ErrorDescription)
}
return nil, ErrDeviceGeneric return nil, ErrDeviceGeneric
} }
} }

View file

@ -3,10 +3,10 @@ module github.com/Azure/go-autorest/autorest/adal
go 1.12 go 1.12
require ( require (
github.com/Azure/go-autorest/autorest v0.9.0 github.com/Azure/go-autorest v14.2.0+incompatible
github.com/Azure/go-autorest/autorest/date v0.2.0 github.com/Azure/go-autorest/autorest/date v0.3.0
github.com/Azure/go-autorest/autorest/mocks v0.3.0 github.com/Azure/go-autorest/autorest/mocks v0.4.1
github.com/Azure/go-autorest/tracing v0.5.0 github.com/Azure/go-autorest/tracing v0.6.0
github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
) )

View file

@ -1,26 +1,17 @@
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.1.0 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/autorest/mocks v0.1.0 h1:Kx+AUU2Te+A3JIyYn6Dfs+cFgx5XorQKuIXrZGoq/SI= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0 h1:Ww5g4zThfD/6cLb4z6xxgeyDa7QDkizMkJKe0ysZXp0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc=
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View file

@ -16,9 +16,9 @@ package adal
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// This file, and the github.com/Azure/go-autorest/autorest import, won't actually become part of // This file, and the github.com/Azure/go-autorest import, won't actually become part of
// the resultant binary. // the resultant binary.
// Necessary for safely adding multi-module repo. // Necessary for safely adding multi-module repo.
// See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository // See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository
import _ "github.com/Azure/go-autorest/autorest" import _ "github.com/Azure/go-autorest"

View file

@ -15,11 +15,24 @@ package adal
// limitations under the License. // limitations under the License.
import ( import (
"crypto/rsa"
"crypto/x509"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"golang.org/x/crypto/pkcs12"
)
var (
// ErrMissingCertificate is returned when no local certificate is found in the provided PFX data.
ErrMissingCertificate = errors.New("adal: certificate missing")
// ErrMissingPrivateKey is returned when no private key is found in the provided PFX data.
ErrMissingPrivateKey = errors.New("adal: private key missing")
) )
// LoadToken restores a Token object from a file located at 'path'. // LoadToken restores a Token object from a file located at 'path'.
@ -71,3 +84,52 @@ func SaveToken(path string, mode os.FileMode, token Token) error {
} }
return nil return nil
} }
// DecodePfxCertificateData extracts the x509 certificate and RSA private key from the provided PFX data.
// The PFX data must contain a private key along with a certificate whose public key matches that of the
// private key or an error is returned.
// If the private key is not password protected pass the empty string for password.
func DecodePfxCertificateData(pfxData []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
blocks, err := pkcs12.ToPEM(pfxData, password)
if err != nil {
return nil, nil, err
}
// first extract the private key
var priv *rsa.PrivateKey
for _, block := range blocks {
if block.Type == "PRIVATE KEY" {
priv, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, nil, err
}
break
}
}
if priv == nil {
return nil, nil, ErrMissingPrivateKey
}
// now find the certificate with the matching public key of our private key
var cert *x509.Certificate
for _, block := range blocks {
if block.Type == "CERTIFICATE" {
pcert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, nil, err
}
certKey, ok := pcert.PublicKey.(*rsa.PublicKey)
if !ok {
// keep looking
continue
}
if priv.E == certKey.E && priv.N.Cmp(certKey.N) == 0 {
// found a match
cert = pcert
break
}
}
}
if cert == nil {
return nil, nil, ErrMissingCertificate
}
return cert, priv, nil
}

View file

@ -62,6 +62,9 @@ const (
// msiEndpoint is the well known endpoint for getting MSI authentications tokens // msiEndpoint is the well known endpoint for getting MSI authentications tokens
msiEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token" msiEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token"
// the API version to use for the MSI endpoint
msiAPIVersion = "2018-02-01"
// the default number of attempts to refresh an MSI authentication token // the default number of attempts to refresh an MSI authentication token
defaultMaxMSIRefreshAttempts = 5 defaultMaxMSIRefreshAttempts = 5
@ -70,6 +73,9 @@ const (
// asMSISecretEnv is the environment variable used to store the request secret on App Service and Functions // asMSISecretEnv is the environment variable used to store the request secret on App Service and Functions
asMSISecretEnv = "MSI_SECRET" asMSISecretEnv = "MSI_SECRET"
// the API version to use for the App Service MSI endpoint
appServiceAPIVersion = "2017-09-01"
) )
// OAuthTokenProvider is an interface which should be implemented by an access token retriever // OAuthTokenProvider is an interface which should be implemented by an access token retriever
@ -354,6 +360,7 @@ type ServicePrincipalToken struct {
customRefreshFunc TokenRefresh customRefreshFunc TokenRefresh
refreshCallbacks []TokenRefreshCallback refreshCallbacks []TokenRefreshCallback
// MaxMSIRefreshAttempts is the maximum number of attempts to refresh an MSI token. // MaxMSIRefreshAttempts is the maximum number of attempts to refresh an MSI token.
// Settings this to a value less than 1 will use the default value.
MaxMSIRefreshAttempts int MaxMSIRefreshAttempts int
} }
@ -650,6 +657,8 @@ func GetMSIVMEndpoint() (string, error) {
return msiEndpoint, nil return msiEndpoint, nil
} }
// NOTE: this only indicates if the ASE environment credentials have been set
// which does not necessarily mean that the caller is authenticating via ASE!
func isAppService() bool { func isAppService() bool {
_, asMSIEndpointEnvExists := os.LookupEnv(asMSIEndpointEnv) _, asMSIEndpointEnvExists := os.LookupEnv(asMSIEndpointEnv)
_, asMSISecretEnvExists := os.LookupEnv(asMSISecretEnv) _, asMSISecretEnvExists := os.LookupEnv(asMSISecretEnv)
@ -678,16 +687,22 @@ func GetMSIEndpoint() (string, error) {
// NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension. // NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension.
// It will use the system assigned identity when creating the token. // It will use the system assigned identity when creating the token.
func NewServicePrincipalTokenFromMSI(msiEndpoint, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { func NewServicePrincipalTokenFromMSI(msiEndpoint, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, nil, callbacks...) return newServicePrincipalTokenFromMSI(msiEndpoint, resource, nil, nil, callbacks...)
} }
// NewServicePrincipalTokenFromMSIWithUserAssignedID creates a ServicePrincipalToken via the MSI VM Extension. // NewServicePrincipalTokenFromMSIWithUserAssignedID creates a ServicePrincipalToken via the MSI VM Extension.
// It will use the specified user assigned identity when creating the token. // It will use the clientID of specified user assigned identity when creating the token.
func NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint, resource string, userAssignedID string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { func NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint, resource string, userAssignedID string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, &userAssignedID, callbacks...) return newServicePrincipalTokenFromMSI(msiEndpoint, resource, &userAssignedID, nil, callbacks...)
} }
func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedID *string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { // NewServicePrincipalTokenFromMSIWithIdentityResourceID creates a ServicePrincipalToken via the MSI VM Extension.
// It will use the azure resource id of user assigned identity when creating the token.
func NewServicePrincipalTokenFromMSIWithIdentityResourceID(msiEndpoint, resource string, identityResourceID string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, nil, &identityResourceID, callbacks...)
}
func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedID *string, identityResourceID *string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
if err := validateStringParam(msiEndpoint, "msiEndpoint"); err != nil { if err := validateStringParam(msiEndpoint, "msiEndpoint"); err != nil {
return nil, err return nil, err
} }
@ -699,6 +714,11 @@ func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedI
return nil, err return nil, err
} }
} }
if identityResourceID != nil {
if err := validateStringParam(*identityResourceID, "identityResourceID"); err != nil {
return nil, err
}
}
// We set the oauth config token endpoint to be MSI's endpoint // We set the oauth config token endpoint to be MSI's endpoint
msiEndpointURL, err := url.Parse(msiEndpoint) msiEndpointURL, err := url.Parse(msiEndpoint)
if err != nil { if err != nil {
@ -709,13 +729,16 @@ func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedI
v.Set("resource", resource) v.Set("resource", resource)
// App Service MSI currently only supports token API version 2017-09-01 // App Service MSI currently only supports token API version 2017-09-01
if isAppService() { if isAppService() {
v.Set("api-version", "2017-09-01") v.Set("api-version", appServiceAPIVersion)
} else { } else {
v.Set("api-version", "2018-02-01") v.Set("api-version", msiAPIVersion)
} }
if userAssignedID != nil { if userAssignedID != nil {
v.Set("client_id", *userAssignedID) v.Set("client_id", *userAssignedID)
} }
if identityResourceID != nil {
v.Set("mi_res_id", *identityResourceID)
}
msiEndpointURL.RawQuery = v.Encode() msiEndpointURL.RawQuery = v.Encode()
spt := &ServicePrincipalToken{ spt := &ServicePrincipalToken{
@ -771,8 +794,9 @@ func (spt *ServicePrincipalToken) EnsureFresh() error {
// EnsureFreshWithContext will refresh the token if it will expire within the refresh window (as set by // EnsureFreshWithContext will refresh the token if it will expire within the refresh window (as set by
// RefreshWithin) and autoRefresh flag is on. This method is safe for concurrent use. // RefreshWithin) and autoRefresh flag is on. This method is safe for concurrent use.
func (spt *ServicePrincipalToken) EnsureFreshWithContext(ctx context.Context) error { func (spt *ServicePrincipalToken) EnsureFreshWithContext(ctx context.Context) error {
if spt.inner.AutoRefresh && spt.inner.Token.WillExpireIn(spt.inner.RefreshWithin) { // must take the read lock when initially checking the token's expiration
// take the write lock then check to see if the token was already refreshed if spt.inner.AutoRefresh && spt.Token().WillExpireIn(spt.inner.RefreshWithin) {
// take the write lock then check again to see if the token was already refreshed
spt.refreshLock.Lock() spt.refreshLock.Lock()
defer spt.refreshLock.Unlock() defer spt.refreshLock.Unlock()
if spt.inner.Token.WillExpireIn(spt.inner.RefreshWithin) { if spt.inner.Token.WillExpireIn(spt.inner.RefreshWithin) {
@ -835,11 +859,28 @@ func (spt *ServicePrincipalToken) getGrantType() string {
} }
func isIMDS(u url.URL) bool { func isIMDS(u url.URL) bool {
imds, err := url.Parse(msiEndpoint) return isMSIEndpoint(u) == true || isASEEndpoint(u) == true
}
func isMSIEndpoint(endpoint url.URL) bool {
msi, err := url.Parse(msiEndpoint)
if err != nil { if err != nil {
return false return false
} }
return (u.Host == imds.Host && u.Path == imds.Path) || isAppService() return endpoint.Host == msi.Host && endpoint.Path == msi.Path
}
func isASEEndpoint(endpoint url.URL) bool {
aseEndpoint, err := GetMSIAppServiceEndpoint()
if err != nil {
// app service environment isn't enabled
return false
}
ase, err := url.Parse(aseEndpoint)
if err != nil {
return false
}
return endpoint.Host == ase.Host && endpoint.Path == ase.Path
} }
func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource string) error { func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource string) error {
@ -858,7 +899,7 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource
} }
req.Header.Add("User-Agent", UserAgent()) req.Header.Add("User-Agent", UserAgent())
// Add header when runtime is on App Service or Functions // Add header when runtime is on App Service or Functions
if isAppService() { if isASEEndpoint(spt.inner.OauthConfig.TokenEndpoint) {
asMSISecret, _ := os.LookupEnv(asMSISecretEnv) asMSISecret, _ := os.LookupEnv(asMSISecretEnv)
req.Header.Add("Secret", asMSISecret) req.Header.Add("Secret", asMSISecret)
} }
@ -900,6 +941,10 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource
} }
var resp *http.Response var resp *http.Response
if isMSIEndpoint(spt.inner.OauthConfig.TokenEndpoint) && !MSIAvailable(ctx, spt.sender) {
// return a TokenRefreshError here so that we don't keep retrying
return newTokenRefreshError("the MSI endpoint is not available", nil)
}
if isIMDS(spt.inner.OauthConfig.TokenEndpoint) { if isIMDS(spt.inner.OauthConfig.TokenEndpoint) {
resp, err = retryForIMDS(spt.sender, req, spt.MaxMSIRefreshAttempts) resp, err = retryForIMDS(spt.sender, req, spt.MaxMSIRefreshAttempts)
} else { } else {
@ -972,6 +1017,11 @@ func retryForIMDS(sender Sender, req *http.Request, maxAttempts int) (resp *http
attempt := 0 attempt := 0
delay := time.Duration(0) delay := time.Duration(0)
// maxAttempts is user-specified, ensure that its value is greater than zero else no request will be made
if maxAttempts < 1 {
maxAttempts = defaultMaxMSIRefreshAttempts
}
for attempt < maxAttempts { for attempt < maxAttempts {
if resp != nil && resp.Body != nil { if resp != nil && resp.Body != nil {
io.Copy(ioutil.Discard, resp.Body) io.Copy(ioutil.Discard, resp.Body)
@ -1133,3 +1183,17 @@ func NewMultiTenantServicePrincipalToken(multiTenantCfg MultiTenantOAuthConfig,
} }
return &m, nil return &m, nil
} }
// MSIAvailable returns true if the MSI endpoint is available for authentication.
func MSIAvailable(ctx context.Context, sender Sender) bool {
// this cannot fail, the return sig is due to legacy reasons
msiEndpoint, _ := GetMSIVMEndpoint()
tempCtx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
defer cancel()
req, _ := http.NewRequestWithContext(tempCtx, http.MethodGet, msiEndpoint, nil)
q := req.URL.Query()
q.Add("api-version", msiAPIVersion)
req.URL.RawQuery = q.Encode()
_, err := sender.Do(req)
return err == nil
}

View file

@ -2,4 +2,4 @@ module github.com/Azure/go-autorest/autorest/date
go 1.12 go 1.12
require github.com/Azure/go-autorest/autorest v0.9.0 require github.com/Azure/go-autorest v14.2.0+incompatible

View file

@ -1,16 +1,2 @@
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0 h1:Ww5g4zThfD/6cLb4z6xxgeyDa7QDkizMkJKe0ysZXp0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View file

@ -16,9 +16,9 @@ package date
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// This file, and the github.com/Azure/go-autorest/autorest import, won't actually become part of // This file, and the github.com/Azure/go-autorest import, won't actually become part of
// the resultant binary. // the resultant binary.
// Necessary for safely adding multi-module repo. // Necessary for safely adding multi-module repo.
// See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository // See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository
import _ "github.com/Azure/go-autorest/autorest" import _ "github.com/Azure/go-autorest"

105
vendor/github.com/Azure/go-autorest/azure-pipelines.yml generated vendored Normal file
View file

@ -0,0 +1,105 @@
variables:
GOPATH: '$(system.defaultWorkingDirectory)/work'
sdkPath: '$(GOPATH)/src/github.com/$(build.repository.name)'
jobs:
- job: 'goautorest'
displayName: 'Run go-autorest CI Checks'
strategy:
matrix:
Linux_Go113:
vm.image: 'ubuntu-18.04'
go.version: '1.13'
Linux_Go114:
vm.image: 'ubuntu-18.04'
go.version: '1.14'
pool:
vmImage: '$(vm.image)'
steps:
- task: GoTool@0
inputs:
version: '$(go.version)'
displayName: "Select Go Version"
- script: |
set -e
mkdir -p '$(GOPATH)/bin'
mkdir -p '$(sdkPath)'
shopt -s extglob
mv !(work) '$(sdkPath)'
echo '##vso[task.prependpath]$(GOPATH)/bin'
displayName: 'Create Go Workspace'
- script: |
set -e
curl -sSL https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
dep ensure -v
go install ./vendor/golang.org/x/lint/golint
go get github.com/jstemmer/go-junit-report
go get github.com/axw/gocov/gocov
go get github.com/AlekSi/gocov-xml
go get -u github.com/matm/gocov-html
workingDirectory: '$(sdkPath)'
displayName: 'Install Dependencies'
- script: |
go vet ./autorest/...
go vet ./logger/...
go vet ./tracing/...
workingDirectory: '$(sdkPath)'
displayName: 'Vet'
- script: |
go build -v ./autorest/...
go build -v ./logger/...
go build -v ./tracing/...
workingDirectory: '$(sdkPath)'
displayName: 'Build'
- script: |
set -e
go test -race -v -coverprofile=coverage.txt -covermode atomic ./autorest/... ./logger/... ./tracing/... 2>&1 | go-junit-report > report.xml
gocov convert coverage.txt > coverage.json
gocov-xml < coverage.json > coverage.xml
gocov-html < coverage.json > coverage.html
workingDirectory: '$(sdkPath)'
displayName: 'Run Tests'
- script: grep -L -r --include *.go --exclude-dir vendor -P "Copyright (\d{4}|\(c\)) Microsoft" ./ | tee >&2
workingDirectory: '$(sdkPath)'
displayName: 'Copyright Header Check'
failOnStderr: true
condition: succeededOrFailed()
- script: |
gofmt -s -l -w ./autorest/. >&2
gofmt -s -l -w ./logger/. >&2
gofmt -s -l -w ./tracing/. >&2
workingDirectory: '$(sdkPath)'
displayName: 'Format Check'
failOnStderr: true
condition: succeededOrFailed()
- script: |
golint ./autorest/... >&2
golint ./logger/... >&2
golint ./tracing/... >&2
workingDirectory: '$(sdkPath)'
displayName: 'Linter Check'
failOnStderr: true
condition: succeededOrFailed()
- task: PublishTestResults@2
inputs:
testRunner: JUnit
testResultsFiles: $(sdkPath)/report.xml
failTaskOnFailedTests: true
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: $(sdkPath)/coverage.xml
additionalCodeCoverageFiles: $(sdkPath)/coverage.html

18
vendor/github.com/Azure/go-autorest/doc.go generated vendored Normal file
View file

@ -0,0 +1,18 @@
/*
Package go-autorest provides an HTTP request client for use with Autorest-generated API client packages.
*/
package go_autorest
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

View file

@ -1,3 +1,5 @@
module github.com/Azure/go-autorest/tracing module github.com/Azure/go-autorest/tracing
go 1.12 go 1.12
require github.com/Azure/go-autorest v14.2.0+incompatible

2
vendor/github.com/Azure/go-autorest/tracing/go.sum generated vendored Normal file
View file

@ -0,0 +1,2 @@
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=

View file

@ -0,0 +1,24 @@
// +build modhack
package tracing
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file, and the github.com/Azure/go-autorest import, won't actually become part of
// the resultant binary.
// Necessary for safely adding multi-module repo.
// See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository
import _ "github.com/Azure/go-autorest"

9
vendor/github.com/mattn/go-ieproxy/go.mod generated vendored Normal file
View file

@ -0,0 +1,9 @@
module github.com/mattn/go-ieproxy
go 1.14
require (
golang.org/x/net v0.0.0-20191112182307-2180aed22343
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea
golang.org/x/text v0.3.2 // indirect
)

11
vendor/github.com/mattn/go-ieproxy/go.sum generated vendored Normal file
View file

@ -0,0 +1,11 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20191112182307-2180aed22343 h1:00ohfJ4K98s3m6BGUoBd8nyfp4Yl0GoIKvw5abItTjI=
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea h1:Mz1TMnfJDRJLk8S8OPCoJYgrsp/Se/2TBre2+vwX128=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View file

@ -25,33 +25,55 @@ func getConf() ProxyConf {
} }
func writeConf() { func writeConf() {
var ( proxy := ""
cfg *tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyByPass := ""
err error autoConfigUrl := ""
) autoDetect := false
if cfg, err = getUserConfigFromWindowsSyscall(); err != nil { // Try from IE first.
if ieCfg, err := getUserConfigFromWindowsSyscall(); err == nil {
defer globalFreeWrapper(ieCfg.lpszProxy)
defer globalFreeWrapper(ieCfg.lpszProxyBypass)
defer globalFreeWrapper(ieCfg.lpszAutoConfigUrl)
proxy = StringFromUTF16Ptr(ieCfg.lpszProxy)
proxyByPass = StringFromUTF16Ptr(ieCfg.lpszProxyBypass)
autoConfigUrl = StringFromUTF16Ptr(ieCfg.lpszAutoConfigUrl)
autoDetect = ieCfg.fAutoDetect
}
if proxy == "" && !autoDetect{
// Try WinHTTP default proxy.
if defaultCfg, err := getDefaultProxyConfiguration(); err == nil {
defer globalFreeWrapper(defaultCfg.lpszProxy)
defer globalFreeWrapper(defaultCfg.lpszProxyBypass)
// Always set both of these (they are a pair, it doesn't make sense to set one here and keep the value of the other from above)
proxy = StringFromUTF16Ptr(defaultCfg.lpszProxy)
proxyByPass = StringFromUTF16Ptr(defaultCfg.lpszProxyBypass)
}
}
if proxy == "" && !autoDetect {
// Fall back to IE registry or manual detection if nothing is found there..
regedit, _ := readRegedit() // If the syscall fails, backup to manual detection. regedit, _ := readRegedit() // If the syscall fails, backup to manual detection.
windowsProxyConf = parseRegedit(regedit) windowsProxyConf = parseRegedit(regedit)
return return
} }
defer globalFreeWrapper(cfg.lpszProxy) // Setting the proxy settings.
defer globalFreeWrapper(cfg.lpszProxyBypass)
defer globalFreeWrapper(cfg.lpszAutoConfigUrl)
windowsProxyConf = ProxyConf{ windowsProxyConf = ProxyConf{
Static: StaticProxyConf{ Static: StaticProxyConf{
Active: cfg.lpszProxy != nil, Active: len(proxy) > 0,
}, },
Automatic: ProxyScriptConf{ Automatic: ProxyScriptConf{
Active: cfg.lpszAutoConfigUrl != nil || cfg.fAutoDetect, Active: len(autoConfigUrl) > 0 || autoDetect,
}, },
} }
if windowsProxyConf.Static.Active { if windowsProxyConf.Static.Active {
protocol := make(map[string]string) protocol := make(map[string]string)
for _, s := range strings.Split(StringFromUTF16Ptr(cfg.lpszProxy), ";") { for _, s := range strings.Split(proxy, ";") {
s = strings.TrimSpace(s) s = strings.TrimSpace(s)
if s == "" { if s == "" {
continue continue
@ -65,31 +87,38 @@ func writeConf() {
} }
windowsProxyConf.Static.Protocols = protocol windowsProxyConf.Static.Protocols = protocol
if cfg.lpszProxyBypass != nil { if len(proxyByPass) > 0 {
windowsProxyConf.Static.NoProxy = strings.Replace(StringFromUTF16Ptr(cfg.lpszProxyBypass), ";", ",", -1) windowsProxyConf.Static.NoProxy = strings.Replace(proxyByPass, ";", ",", -1)
} }
} }
if windowsProxyConf.Automatic.Active { if windowsProxyConf.Automatic.Active {
windowsProxyConf.Automatic.PreConfiguredURL = StringFromUTF16Ptr(cfg.lpszAutoConfigUrl) windowsProxyConf.Automatic.PreConfiguredURL = autoConfigUrl
} }
} }
func getUserConfigFromWindowsSyscall() (*tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG, error) { func getUserConfigFromWindowsSyscall() (*tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG, error) {
handle, _, err := winHttpOpen.Call(0, 0, 0, 0, 0) if err := winHttpGetIEProxyConfigForCurrentUser.Find(); err != nil {
if handle == 0 { return nil, err
return &tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG{}, err
} }
defer winHttpCloseHandle.Call(handle) p := new(tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG)
r, _, err := winHttpGetIEProxyConfigForCurrentUser.Call(uintptr(unsafe.Pointer(p)))
config := new(tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG) if rTrue(r) {
return p, nil
ret, _, err := winHttpGetIEProxyConfigForCurrentUser.Call(uintptr(unsafe.Pointer(config)))
if ret > 0 {
err = nil
} }
return nil, err
}
return config, err func getDefaultProxyConfiguration() (*tWINHTTP_PROXY_INFO, error) {
pInfo := new(tWINHTTP_PROXY_INFO)
if err := winHttpGetDefaultProxyConfiguration.Find(); err != nil {
return nil, err
}
r, _, err := winHttpGetDefaultProxyConfiguration.Call(uintptr(unsafe.Pointer(pInfo)))
if rTrue(r) {
return pInfo, nil
}
return nil, err
} }
// OverrideEnvWithStaticProxy writes new values to the // OverrideEnvWithStaticProxy writes new values to the
@ -135,7 +164,27 @@ func parseRegedit(regedit regeditValues) ProxyConf {
} }
func readRegedit() (values regeditValues, err error) { func readRegedit() (values regeditValues, err error) {
k, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE) var proxySettingsPerUser uint64 = 1 // 1 is the default value to consider current user
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE)
if err == nil {
//We had used the below variable tempPrxUsrSettings, because the Golang method GetIntegerValue
//sets the value to zero even it fails.
tempPrxUsrSettings, _, err := k.GetIntegerValue("ProxySettingsPerUser")
if err == nil {
//consider the value of tempPrxUsrSettings if it is a success
proxySettingsPerUser = tempPrxUsrSettings
}
k.Close()
}
var hkey registry.Key
if proxySettingsPerUser == 0 {
hkey = registry.LOCAL_MACHINE
} else {
hkey = registry.CURRENT_USER
}
k, err = registry.OpenKey(hkey, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE)
if err != nil { if err != nil {
return return
} }

View file

@ -13,3 +13,7 @@ func globalFreeWrapper(ptr *uint16) {
_, _, _ = globalFree.Call(uintptr(unsafe.Pointer(ptr))) _, _, _ = globalFree.Call(uintptr(unsafe.Pointer(ptr)))
} }
} }
func rTrue(r uintptr) bool {
return r == 1
}

View file

@ -1,4 +1,4 @@
//+build darwin unix linux // +build !windows
package ieproxy package ieproxy

View file

@ -15,30 +15,31 @@ func proxyMiddleman() func(req *http.Request) (i *url.URL, e error) {
if envcfg.HTTPProxy != "" || envcfg.HTTPSProxy != "" { if envcfg.HTTPProxy != "" || envcfg.HTTPSProxy != "" {
// If the user manually specifies environment variables, prefer those over the Windows config. // If the user manually specifies environment variables, prefer those over the Windows config.
return http.ProxyFromEnvironment return http.ProxyFromEnvironment
} else if conf.Automatic.Active {
// If automatic proxy obtaining is specified
return func(req *http.Request) (i *url.URL, e error) {
host := conf.Automatic.FindProxyForURL(req.URL.String())
if host == "" {
return nil, nil
}
return &url.URL{Host: host}, nil
}
} else if conf.Static.Active {
// If static proxy obtaining is specified
prox := httpproxy.Config{
HTTPSProxy: mapFallback("https", "", conf.Static.Protocols),
HTTPProxy: mapFallback("http", "", conf.Static.Protocols),
NoProxy: conf.Static.NoProxy,
}
return func(req *http.Request) (i *url.URL, e error) {
return prox.ProxyFunc()(req.URL)
}
} else {
// Final fallthrough case; use the environment variables.
return http.ProxyFromEnvironment
} }
return func(req *http.Request) (i *url.URL, e error) {
if conf.Automatic.Active {
host := conf.Automatic.FindProxyForURL(req.URL.String())
if host != "" {
return &url.URL{Host: host}, nil
}
}
if conf.Static.Active {
return staticProxy(conf, req)
}
// Should return no proxy; fallthrough.
return http.ProxyFromEnvironment(req)
}
}
func staticProxy(conf ProxyConf, req *http.Request) (i *url.URL, e error) {
// If static proxy obtaining is specified
prox := httpproxy.Config{
HTTPSProxy: mapFallback("https", "", conf.Static.Protocols),
HTTPProxy: mapFallback("http", "", conf.Static.Protocols),
NoProxy: conf.Static.NoProxy,
}
return prox.ProxyFunc()(req.URL)
} }
// Return oKey or fbKey if oKey doesn't exist in the map. // Return oKey or fbKey if oKey doesn't exist in the map.

View file

@ -7,6 +7,7 @@ var winHttpGetProxyForURL = winHttp.NewProc("WinHttpGetProxyForUrl")
var winHttpOpen = winHttp.NewProc("WinHttpOpen") var winHttpOpen = winHttp.NewProc("WinHttpOpen")
var winHttpCloseHandle = winHttp.NewProc("WinHttpCloseHandle") var winHttpCloseHandle = winHttp.NewProc("WinHttpCloseHandle")
var winHttpGetIEProxyConfigForCurrentUser = winHttp.NewProc("WinHttpGetIEProxyConfigForCurrentUser") var winHttpGetIEProxyConfigForCurrentUser = winHttp.NewProc("WinHttpGetIEProxyConfigForCurrentUser")
var winHttpGetDefaultProxyConfiguration = winHttp.NewProc("WinHttpGetDefaultProxyConfiguration")
type tWINHTTP_AUTOPROXY_OPTIONS struct { type tWINHTTP_AUTOPROXY_OPTIONS struct {
dwFlags autoProxyFlag dwFlags autoProxyFlag

View file

@ -55,8 +55,9 @@ const (
ALPNProto = "acme-tls/1" ALPNProto = "acme-tls/1"
) )
// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge. // idPeACMEIdentifier is the OID for the ACME extension for the TLS-ALPN challenge.
var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1} // https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05#section-5.1
var idPeACMEIdentifier = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31}
const ( const (
maxChainLen = 5 // max depth and breadth of a certificate chain maxChainLen = 5 // max depth and breadth of a certificate chain
@ -778,7 +779,7 @@ func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption)
return tls.Certificate{}, err return tls.Certificate{}, err
} }
acmeExtension := pkix.Extension{ acmeExtension := pkix.Extension{
Id: idPeACMEIdentifierV1, Id: idPeACMEIdentifier,
Critical: true, Critical: true,
Value: extValue, Value: extValue,
} }

View file

@ -72,7 +72,6 @@ func NewListener(domains ...string) net.Listener {
// the Manager m's Prompt, Cache, HostPolicy, and other desired options. // the Manager m's Prompt, Cache, HostPolicy, and other desired options.
func (m *Manager) Listener() net.Listener { func (m *Manager) Listener() net.Listener {
ln := &listener{ ln := &listener{
m: m,
conf: m.TLSConfig(), conf: m.TLSConfig(),
} }
ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443") ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
@ -80,7 +79,6 @@ func (m *Manager) Listener() net.Listener {
} }
type listener struct { type listener struct {
m *Manager
conf *tls.Config conf *tls.Config
tcpListener net.Listener tcpListener net.Listener

View file

@ -102,7 +102,12 @@ func (a *AuthorizationError) Error() string {
for i, err := range a.Errors { for i, err := range a.Errors {
e[i] = err.Error() e[i] = err.Error()
} }
return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
if a.Identifier != "" {
return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
}
return fmt.Sprintf("acme: authorization error: %s", strings.Join(e, "; "))
} }
// OrderError is returned from Client's order related methods. // OrderError is returned from Client's order related methods.
@ -407,6 +412,7 @@ type wireAuthz struct {
Wildcard bool Wildcard bool
Challenges []wireChallenge Challenges []wireChallenge
Combinations [][]int Combinations [][]int
Error *wireError
} }
func (z *wireAuthz) authorization(uri string) *Authorization { func (z *wireAuthz) authorization(uri string) *Authorization {
@ -430,11 +436,17 @@ func (z *wireAuthz) error(uri string) *AuthorizationError {
URI: uri, URI: uri,
Identifier: z.Identifier.Value, Identifier: z.Identifier.Value,
} }
if z.Error != nil {
err.Errors = append(err.Errors, z.Error.error(nil))
}
for _, raw := range z.Challenges { for _, raw := range z.Challenges {
if raw.Error != nil { if raw.Error != nil {
err.Errors = append(err.Errors, raw.Error.error(nil)) err.Errors = append(err.Errors, raw.Error.error(nil))
} }
} }
return err return err
} }

View file

@ -0,0 +1,30 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package unsafeheader contains header declarations for the Go runtime's
// slice and string implementations.
//
// This package allows x/sys to use types equivalent to
// reflect.SliceHeader and reflect.StringHeader without introducing
// a dependency on the (relatively heavy) "reflect" package.
package unsafeheader
import (
"unsafe"
)
// Slice is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may change in a later release.
type Slice struct {
Data unsafe.Pointer
Len int
Cap int
}
// String is the runtime representation of a string.
// It cannot be used safely or portably and its representation may change in a later release.
type String struct {
Data unsafe.Pointer
Len int
}

View file

@ -89,7 +89,7 @@ constants.
Adding new syscall numbers is mostly done by running the build on a sufficiently Adding new syscall numbers is mostly done by running the build on a sufficiently
new installation of the target OS (or updating the source checkouts for the new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you make need to update the new build system). However, depending on the OS, you may need to update the
parsing in mksysnum. parsing in mksysnum.
### mksyscall.go ### mksyscall.go
@ -149,10 +149,21 @@ To add a constant, add the header that includes it to the appropriate variable.
Then, edit the regex (if necessary) to match the desired constant. Avoid making Then, edit the regex (if necessary) to match the desired constant. Avoid making
the regex too broad to avoid matching unintended constants. the regex too broad to avoid matching unintended constants.
### mkmerge.go
This program is used to extract duplicate const, func, and type declarations
from the generated architecture-specific files listed below, and merge these
into a common file for each OS.
The merge is performed in the following steps:
1. Construct the set of common code that is idential in all architecture-specific files.
2. Write this common code to the merged file.
3. Remove the common code from all architecture-specific files.
## Generated files ## Generated files
### `zerror_${GOOS}_${GOARCH}.go` ### `zerrors_${GOOS}_${GOARCH}.go`
A file containing all of the system's generated error numbers, error strings, A file containing all of the system's generated error numbers, error strings,
signal numbers, and constants. Generated by `mkerrors.sh` (see above). signal numbers, and constants. Generated by `mkerrors.sh` (see above).

29
vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s generated vendored Normal file
View file

@ -0,0 +1,29 @@
// 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.
// +build !gccgo
#include "textflag.h"
//
// System call support for mips64, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

View file

@ -8,6 +8,7 @@
package unix package unix
const ( const (
DLT_HHDLC = 0x79
IFF_SMART = 0x20 IFF_SMART = 0x20
IFT_1822 = 0x2 IFT_1822 = 0x2
IFT_A12MPPSWITCH = 0x82 IFT_A12MPPSWITCH = 0x82
@ -210,13 +211,18 @@ const (
IFT_XETHER = 0x1a IFT_XETHER = 0x1a
IPPROTO_MAXID = 0x34 IPPROTO_MAXID = 0x34
IPV6_FAITH = 0x1d IPV6_FAITH = 0x1d
IPV6_MIN_MEMBERSHIPS = 0x1f
IP_FAITH = 0x16 IP_FAITH = 0x16
IP_MAX_SOURCE_FILTER = 0x400
IP_MIN_MEMBERSHIPS = 0x1f
MAP_NORESERVE = 0x40 MAP_NORESERVE = 0x40
MAP_RENAME = 0x20 MAP_RENAME = 0x20
NET_RT_MAXID = 0x6 NET_RT_MAXID = 0x6
RTF_PRCLONING = 0x10000 RTF_PRCLONING = 0x10000
RTM_OLDADD = 0x9 RTM_OLDADD = 0x9
RTM_OLDDEL = 0xa RTM_OLDDEL = 0xa
RT_CACHING_CONTEXT = 0x1
RT_NORTREF = 0x2
SIOCADDRT = 0x8030720a SIOCADDRT = 0x8030720a
SIOCALIFADDR = 0x8118691b SIOCALIFADDR = 0x8118691b
SIOCDELRT = 0x8030720b SIOCDELRT = 0x8030720b

View file

@ -8,6 +8,7 @@
package unix package unix
const ( const (
DLT_HHDLC = 0x79
IFF_SMART = 0x20 IFF_SMART = 0x20
IFT_1822 = 0x2 IFT_1822 = 0x2
IFT_A12MPPSWITCH = 0x82 IFT_A12MPPSWITCH = 0x82
@ -210,13 +211,18 @@ const (
IFT_XETHER = 0x1a IFT_XETHER = 0x1a
IPPROTO_MAXID = 0x34 IPPROTO_MAXID = 0x34
IPV6_FAITH = 0x1d IPV6_FAITH = 0x1d
IPV6_MIN_MEMBERSHIPS = 0x1f
IP_FAITH = 0x16 IP_FAITH = 0x16
IP_MAX_SOURCE_FILTER = 0x400
IP_MIN_MEMBERSHIPS = 0x1f
MAP_NORESERVE = 0x40 MAP_NORESERVE = 0x40
MAP_RENAME = 0x20 MAP_RENAME = 0x20
NET_RT_MAXID = 0x6 NET_RT_MAXID = 0x6
RTF_PRCLONING = 0x10000 RTF_PRCLONING = 0x10000
RTM_OLDADD = 0x9 RTM_OLDADD = 0x9
RTM_OLDDEL = 0xa RTM_OLDDEL = 0xa
RT_CACHING_CONTEXT = 0x1
RT_NORTREF = 0x2
SIOCADDRT = 0x8040720a SIOCADDRT = 0x8040720a
SIOCALIFADDR = 0x8118691b SIOCALIFADDR = 0x8118691b
SIOCDELRT = 0x8040720b SIOCDELRT = 0x8040720b

17
vendor/golang.org/x/sys/unix/errors_freebsd_arm64.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
// them here for backwards compatibility.
package unix
const (
DLT_HHDLC = 0x79
IPV6_MIN_MEMBERSHIPS = 0x1f
IP_MAX_SOURCE_FILTER = 0x400
IP_MIN_MEMBERSHIPS = 0x1f
RT_CACHING_CONTEXT = 0x1
RT_NORTREF = 0x2
)

View file

@ -20,6 +20,15 @@ func IoctlSetInt(fd int, req uint, value int) error {
return ioctl(fd, req, uintptr(value)) return ioctl(fd, req, uintptr(value))
} }
// IoctlSetPointerInt performs an ioctl operation which sets an
// integer value on fd, using the specified request number. The ioctl
// argument is called with a pointer to the integer value, rather than
// passing the integer value directly.
func IoctlSetPointerInt(fd int, req uint, value int) error {
v := int32(value)
return ioctl(fd, req, uintptr(unsafe.Pointer(&v)))
}
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument. // IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
// //
// To change fd's window size, the req argument should be TIOCSWINSZ. // To change fd's window size, the req argument should be TIOCSWINSZ.

View file

@ -73,26 +73,22 @@ aix_ppc64)
darwin_386) darwin_386)
mkerrors="$mkerrors -m32" mkerrors="$mkerrors -m32"
mksyscall="go run mksyscall.go -l32" mksyscall="go run mksyscall.go -l32"
mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h"
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm_darwin.go" mkasm="go run mkasm_darwin.go"
;; ;;
darwin_amd64) darwin_amd64)
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h"
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm_darwin.go" mkasm="go run mkasm_darwin.go"
;; ;;
darwin_arm) darwin_arm)
mkerrors="$mkerrors" mkerrors="$mkerrors"
mksyscall="go run mksyscall.go -l32" mksyscall="go run mksyscall.go -l32"
mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h"
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm_darwin.go" mkasm="go run mkasm_darwin.go"
;; ;;
darwin_arm64) darwin_arm64)
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h"
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm_darwin.go" mkasm="go run mkasm_darwin.go"
;; ;;
@ -124,7 +120,7 @@ freebsd_arm)
freebsd_arm64) freebsd_arm64)
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'" mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;; ;;
netbsd_386) netbsd_386)
mkerrors="$mkerrors -m32" mkerrors="$mkerrors -m32"
@ -184,12 +180,27 @@ openbsd_arm64)
# API consistent across platforms. # API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;; ;;
openbsd_mips64)
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd"
mksysctl="go run mksysctl_openbsd.go"
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
solaris_amd64) solaris_amd64)
mksyscall="go run mksyscall_solaris.go" mksyscall="go run mksyscall_solaris.go"
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
mksysnum= mksysnum=
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;; ;;
illumos_amd64)
mksyscall="go run mksyscall_solaris.go"
mkerrors=
mksysnum=
mktypes=
;;
*) *)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2 echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
exit 1 exit 1
@ -211,12 +222,15 @@ esac
# aix/ppc64 script generates files instead of writing to stdin. # aix/ppc64 script generates files instead of writing to stdin.
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ; echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
elif [ "$GOOS" == "darwin" ]; then elif [ "$GOOS" == "darwin" ]; then
# pre-1.12, direct syscalls
echo "$mksyscall -tags $GOOS,$GOARCH,!go1.12 $syscall_goos syscall_darwin_${GOARCH}.1_11.go $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.1_11.go";
# 1.12 and later, syscalls via libSystem # 1.12 and later, syscalls via libSystem
echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
# 1.13 and later, syscalls via libSystem (including syscallPtr) # 1.13 and later, syscalls via libSystem (including syscallPtr)
echo "$mksyscall -tags $GOOS,$GOARCH,go1.13 syscall_darwin.1_13.go |gofmt >zsyscall_$GOOSARCH.1_13.go"; echo "$mksyscall -tags $GOOS,$GOARCH,go1.13 syscall_darwin.1_13.go |gofmt >zsyscall_$GOOSARCH.1_13.go";
elif [ "$GOOS" == "illumos" ]; then
# illumos code generation requires a --illumos switch
echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";
# illumos implies solaris, so solaris code generation is also required
echo "$mksyscall -tags solaris,$GOARCH syscall_solaris.go syscall_solaris_$GOARCH.go |gofmt >zsyscall_solaris_$GOARCH.go";
else else
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
fi fi

View file

@ -105,7 +105,9 @@ includes_FreeBSD='
#include <sys/capsicum.h> #include <sys/capsicum.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/disk.h>
#include <sys/event.h> #include <sys/event.h>
#include <sys/sched.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/sockio.h> #include <sys/sockio.h>
@ -186,19 +188,24 @@ struct ltchars {
#include <sys/select.h> #include <sys/select.h>
#include <sys/signalfd.h> #include <sys/signalfd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/timerfd.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/xattr.h> #include <sys/xattr.h>
#include <linux/bpf.h> #include <linux/bpf.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/error.h>
#include <linux/can/raw.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/cryptouser.h> #include <linux/cryptouser.h>
#include <linux/devlink.h> #include <linux/devlink.h>
#include <linux/dm-ioctl.h>
#include <linux/errqueue.h> #include <linux/errqueue.h>
#include <linux/falloc.h> #include <linux/falloc.h>
#include <linux/fanotify.h> #include <linux/fanotify.h>
#include <linux/filter.h> #include <linux/filter.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/fscrypt.h> #include <linux/fscrypt.h>
#include <linux/fsverity.h>
#include <linux/genetlink.h> #include <linux/genetlink.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/icmpv6.h> #include <linux/icmpv6.h>
@ -280,6 +287,11 @@ struct ltchars {
// for the tipc_subscr timeout __u32 field. // for the tipc_subscr timeout __u32 field.
#undef TIPC_WAIT_FOREVER #undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff #define TIPC_WAIT_FOREVER 0xffffffff
// Copied from linux/l2tp.h
// Including linux/l2tp.h here causes conflicts between linux/in.h
// and netinet/in.h included via net/route.h above.
#define IPPROTO_L2TP 115
' '
includes_NetBSD=' includes_NetBSD='
@ -289,6 +301,7 @@ includes_NetBSD='
#include <sys/extattr.h> #include <sys/extattr.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/sched.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/sockio.h> #include <sys/sockio.h>
@ -317,6 +330,7 @@ includes_OpenBSD='
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/sched.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/sockio.h> #include <sys/sockio.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -473,12 +487,13 @@ ccflags="$@"
$2 ~ /^(MS|MNT|UMOUNT)_/ || $2 ~ /^(MS|MNT|UMOUNT)_/ ||
$2 ~ /^NS_GET_/ || $2 ~ /^NS_GET_/ ||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ || $2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
$2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT)_/ || $2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|TFD)_/ ||
$2 ~ /^KEXEC_/ || $2 ~ /^KEXEC_/ ||
$2 ~ /^LINUX_REBOOT_CMD_/ || $2 ~ /^LINUX_REBOOT_CMD_/ ||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ || $2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
$2 ~ /^MODULE_INIT_/ || $2 ~ /^MODULE_INIT_/ ||
$2 !~ "NLA_TYPE_MASK" && $2 !~ "NLA_TYPE_MASK" &&
$2 !~ /^RTC_VL_(ACCURACY|BACKUP|DATA)/ &&
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ || $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ ||
$2 ~ /^SIOC/ || $2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ || $2 ~ /^TIOC/ ||
@ -486,8 +501,9 @@ ccflags="$@"
$2 ~ /^TCSET/ || $2 ~ /^TCSET/ ||
$2 ~ /^TC(FLSH|SBRKP?|XONC)$/ || $2 ~ /^TC(FLSH|SBRKP?|XONC)$/ ||
$2 !~ "RTF_BITS" && $2 !~ "RTF_BITS" &&
$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ || $2 ~ /^(IFF|IFT|NET_RT|RTM(GRP)?|RTF|RTV|RTA|RTAX)_/ ||
$2 ~ /^BIOC/ || $2 ~ /^BIOC/ ||
$2 ~ /^DIOC/ ||
$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ || $2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|LOCKS|MEMLOCK|MSGQUEUE|NICE|NOFILE|NPROC|RSS|RTPRIO|RTTIME|SIGPENDING|STACK)|RLIM_INFINITY/ || $2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|LOCKS|MEMLOCK|MSGQUEUE|NICE|NOFILE|NPROC|RSS|RTPRIO|RTTIME|SIGPENDING|STACK)|RLIM_INFINITY/ ||
$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ || $2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
@ -497,10 +513,14 @@ ccflags="$@"
$2 ~ /^(CLOCK|TIMER)_/ || $2 ~ /^(CLOCK|TIMER)_/ ||
$2 ~ /^CAN_/ || $2 ~ /^CAN_/ ||
$2 ~ /^CAP_/ || $2 ~ /^CAP_/ ||
$2 ~ /^CP_/ ||
$2 ~ /^CPUSTATES$/ ||
$2 ~ /^ALG_/ || $2 ~ /^ALG_/ ||
$2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE)/ || $2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE)/ ||
$2 ~ /^FS_IOC_.*ENCRYPTION/ || $2 ~ /^FS_IOC_.*(ENCRYPTION|VERITY|[GS]ETFLAGS)/ ||
$2 ~ /^FS_VERITY_/ ||
$2 ~ /^FSCRYPT_/ || $2 ~ /^FSCRYPT_/ ||
$2 ~ /^DM_/ ||
$2 ~ /^GRND_/ || $2 ~ /^GRND_/ ||
$2 ~ /^RND/ || $2 ~ /^RND/ ||
$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ || $2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ ||

View file

@ -527,6 +527,23 @@ func SysctlClockinfo(name string) (*Clockinfo, error) {
return &ci, nil return &ci, nil
} }
func SysctlTimeval(name string) (*Timeval, error) {
mib, err := sysctlmib(name)
if err != nil {
return nil, err
}
var tv Timeval
n := uintptr(unsafe.Sizeof(tv))
if err := sysctl(mib, (*byte)(unsafe.Pointer(&tv)), &n, nil, 0); err != nil {
return nil, err
}
if n != unsafe.Sizeof(tv) {
return nil, EIO
}
return &tv, nil
}
//sys utimes(path string, timeval *[2]Timeval) (err error) //sys utimes(path string, timeval *[2]Timeval) (err error)
func Utimes(path string, tv []Timeval) error { func Utimes(path string, tv []Timeval) error {

View file

@ -10,6 +10,8 @@ import (
"unsafe" "unsafe"
) )
const _SYS_GETDIRENTRIES64 = 344
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
// To implement this using libSystem we'd need syscall_syscallPtr for // To implement this using libSystem we'd need syscall_syscallPtr for
// fdopendir. However, syscallPtr was only added in Go 1.13, so we fall // fdopendir. However, syscallPtr was only added in Go 1.13, so we fall
@ -20,7 +22,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
} else { } else {
p = unsafe.Pointer(&_zero) p = unsafe.Pointer(&_zero)
} }
r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(p), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) r0, _, e1 := Syscall6(_SYS_GETDIRENTRIES64, uintptr(fd), uintptr(p), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
n = int(r0) n = int(r0)
if e1 != 0 { if e1 != 0 {
return n, errnoErr(e1) return n, errnoErr(e1)

View file

@ -6,7 +6,11 @@
package unix package unix
import "unsafe" import (
"unsafe"
"golang.org/x/sys/internal/unsafeheader"
)
//sys closedir(dir uintptr) (err error) //sys closedir(dir uintptr) (err error)
//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) //sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
@ -71,6 +75,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
cnt++ cnt++
continue continue
} }
reclen := int(entry.Reclen) reclen := int(entry.Reclen)
if reclen > len(buf) { if reclen > len(buf) {
// Not enough room. Return for now. // Not enough room. Return for now.
@ -79,13 +84,15 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
// restarting is O(n^2) in the length of the directory. Oh well. // restarting is O(n^2) in the length of the directory. Oh well.
break break
} }
// Copy entry into return buffer. // Copy entry into return buffer.
s := struct { var s []byte
ptr unsafe.Pointer hdr := (*unsafeheader.Slice)(unsafe.Pointer(&s))
siz int hdr.Data = unsafe.Pointer(&entry)
cap int hdr.Cap = reclen
}{ptr: unsafe.Pointer(&entry), siz: reclen, cap: reclen} hdr.Len = reclen
copy(buf, *(*[]byte)(unsafe.Pointer(&s))) copy(buf, s)
buf = buf[reclen:] buf = buf[reclen:]
n += reclen n += reclen
cnt++ cnt++

View file

@ -423,6 +423,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sysnb Getrlimit(which int, lim *Rlimit) (err error) //sysnb Getrlimit(which int, lim *Rlimit) (err error)
//sysnb Getrusage(who int, rusage *Rusage) (err error) //sysnb Getrusage(who int, rusage *Rusage) (err error)
//sysnb Getsid(pid int) (sid int, err error) //sysnb Getsid(pid int) (sid int, err error)
//sysnb Gettimeofday(tp *Timeval) (err error)
//sysnb Getuid() (uid int) //sysnb Getuid() (uid int)
//sysnb Issetugid() (tainted bool) //sysnb Issetugid() (tainted bool)
//sys Kqueue() (fd int, err error) //sys Kqueue() (fd int, err error)

View file

@ -1,9 +0,0 @@
// 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.
// +build darwin,386,!go1.12
package unix
//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64

View file

@ -20,17 +20,6 @@ func setTimeval(sec, usec int64) Timeval {
return Timeval{Sec: int32(sec), Usec: int32(usec)} return Timeval{Sec: int32(sec), Usec: int32(usec)}
} }
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = int32(sec)
tv.Usec = int32(usec)
return err
}
func SetKevent(k *Kevent_t, fd, mode, flags int) { func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint32(fd) k.Ident = uint32(fd)
k.Filter = int16(mode) k.Filter = int16(mode)
@ -55,10 +44,6 @@ func (cmsg *Cmsghdr) SetLen(length int) {
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
// of darwin/386 the syscall is called sysctl instead of __sysctl.
const SYS___SYSCTL = SYS_SYSCTL
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 //sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 //sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64 //sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64

View file

@ -1,9 +0,0 @@
// 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.
// +build darwin,amd64,!go1.12
package unix
//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64

View file

@ -20,17 +20,6 @@ func setTimeval(sec, usec int64) Timeval {
return Timeval{Sec: sec, Usec: int32(usec)} return Timeval{Sec: sec, Usec: int32(usec)}
} }
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = sec
tv.Usec = usec
return err
}
func SetKevent(k *Kevent_t, fd, mode, flags int) { func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint64(fd) k.Ident = uint64(fd)
k.Filter = int16(mode) k.Filter = int16(mode)
@ -55,10 +44,6 @@ func (cmsg *Cmsghdr) SetLen(length int) {
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
// of darwin/amd64 the syscall is called sysctl instead of __sysctl.
const SYS___SYSCTL = SYS_SYSCTL
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 //sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 //sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64 //sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64

View file

@ -1,11 +0,0 @@
// 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.
// +build darwin,arm,!go1.12
package unix
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
return 0, ENOSYS
}

View file

@ -20,17 +20,6 @@ func setTimeval(sec, usec int64) Timeval {
return Timeval{Sec: int32(sec), Usec: int32(usec)} return Timeval{Sec: int32(sec), Usec: int32(usec)}
} }
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = int32(sec)
tv.Usec = int32(usec)
return err
}
func SetKevent(k *Kevent_t, fd, mode, flags int) { func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint32(fd) k.Ident = uint32(fd)
k.Filter = int16(mode) k.Filter = int16(mode)
@ -55,10 +44,6 @@ func (cmsg *Cmsghdr) SetLen(length int) {
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic
// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
// of darwin/arm the syscall is called sysctl instead of __sysctl.
const SYS___SYSCTL = SYS_SYSCTL
//sys Fstat(fd int, stat *Stat_t) (err error) //sys Fstat(fd int, stat *Stat_t) (err error)
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) //sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
//sys Fstatfs(fd int, stat *Statfs_t) (err error) //sys Fstatfs(fd int, stat *Statfs_t) (err error)

View file

@ -1,11 +0,0 @@
// 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.
// +build darwin,arm64,!go1.12
package unix
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
return 0, ENOSYS
}

View file

@ -22,17 +22,6 @@ func setTimeval(sec, usec int64) Timeval {
return Timeval{Sec: sec, Usec: int32(usec)} return Timeval{Sec: sec, Usec: int32(usec)}
} }
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = sec
tv.Usec = usec
return err
}
func SetKevent(k *Kevent_t, fd, mode, flags int) { func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint64(fd) k.Ident = uint64(fd)
k.Filter = int16(mode) k.Filter = int16(mode)
@ -57,10 +46,6 @@ func (cmsg *Cmsghdr) SetLen(length int) {
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic
// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
// of darwin/arm64 the syscall is called sysctl instead of __sysctl.
const SYS___SYSCTL = SYS_SYSCTL
//sys Fstat(fd int, stat *Stat_t) (err error) //sys Fstat(fd int, stat *Stat_t) (err error)
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) //sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
//sys Fstatfs(fd int, stat *Statfs_t) (err error) //sys Fstatfs(fd int, stat *Statfs_t) (err error)

View file

@ -521,10 +521,6 @@ func PtraceGetFpRegs(pid int, fpregsout *FpReg) (err error) {
return ptrace(PTRACE_GETFPREGS, pid, uintptr(unsafe.Pointer(fpregsout)), 0) return ptrace(PTRACE_GETFPREGS, pid, uintptr(unsafe.Pointer(fpregsout)), 0)
} }
func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
return ptrace(PTRACE_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
}
func PtraceGetRegs(pid int, regsout *Reg) (err error) { func PtraceGetRegs(pid int, regsout *Reg) (err error) {
return ptrace(PTRACE_GETREGS, pid, uintptr(unsafe.Pointer(regsout)), 0) return ptrace(PTRACE_GETREGS, pid, uintptr(unsafe.Pointer(regsout)), 0)
} }

View file

@ -55,6 +55,10 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
return ptrace(PTRACE_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
}
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) { func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint32(countin)} ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint32(countin)}
err = ptrace(PTRACE_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0) err = ptrace(PTRACE_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)

View file

@ -55,6 +55,10 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
return ptrace(PTRACE_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
}
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) { func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint64(countin)} ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint64(countin)}
err = ptrace(PTRACE_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0) err = ptrace(PTRACE_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)

57
vendor/golang.org/x/sys/unix/syscall_illumos.go generated vendored Normal file
View file

@ -0,0 +1,57 @@
// Copyright 2009 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.
// illumos system calls not present on Solaris.
// +build amd64,illumos
package unix
import "unsafe"
func bytes2iovec(bs [][]byte) []Iovec {
iovecs := make([]Iovec, len(bs))
for i, b := range bs {
iovecs[i].SetLen(len(b))
if len(b) > 0 {
// somehow Iovec.Base on illumos is (*int8), not (*byte)
iovecs[i].Base = (*int8)(unsafe.Pointer(&b[0]))
} else {
iovecs[i].Base = (*int8)(unsafe.Pointer(&_zero))
}
}
return iovecs
}
//sys readv(fd int, iovs []Iovec) (n int, err error)
func Readv(fd int, iovs [][]byte) (n int, err error) {
iovecs := bytes2iovec(iovs)
n, err = readv(fd, iovecs)
return n, err
}
//sys preadv(fd int, iovs []Iovec, off int64) (n int, err error)
func Preadv(fd int, iovs [][]byte, off int64) (n int, err error) {
iovecs := bytes2iovec(iovs)
n, err = preadv(fd, iovecs, off)
return n, err
}
//sys writev(fd int, iovs []Iovec) (n int, err error)
func Writev(fd int, iovs [][]byte) (n int, err error) {
iovecs := bytes2iovec(iovs)
n, err = writev(fd, iovecs)
return n, err
}
//sys pwritev(fd int, iovs []Iovec, off int64) (n int, err error)
func Pwritev(fd int, iovs [][]byte, off int64) (n int, err error) {
iovecs := bytes2iovec(iovs)
n, err = pwritev(fd, iovecs, off)
return n, err
}

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