Support SDDLs on Azure Files
This commit is contained in:
Родитель
825ad79141
Коммит
f90cde75cd
|
@ -58,10 +58,26 @@ func (d DirectoryURL) NewDirectoryURL(directoryName string) DirectoryURL {
|
|||
// Create creates a new directory within a storage account.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/create-directory.
|
||||
// Pass default values for SMB properties (ex: "None" for file attributes).
|
||||
func (d DirectoryURL) Create(ctx context.Context, metadata Metadata) (*DirectoryCreateResponse, error) {
|
||||
defaultPermissions := "inherit"
|
||||
// If permissions is empty, the default permission "inherit" is used.
|
||||
// For SDDL strings over 9KB, upload using ShareURL.CreatePermission, and supply the permissionKey.
|
||||
func (d DirectoryURL) Create(ctx context.Context, metadata Metadata, permissions, permissionKey string) (*DirectoryCreateResponse, error) {
|
||||
defaultPermissions := &defaultPermissionString
|
||||
// pkptr (permission key pointer) remains nil unless the user defines a permission key.
|
||||
var pkptr *string
|
||||
|
||||
// If the user is supplying a permission key, permissions will be empty.
|
||||
if permissions != "" {
|
||||
defaultPermissions = &permissions
|
||||
}
|
||||
|
||||
// This is handled AFTER permissions, in case the user accidentally supplies both.
|
||||
if permissionKey != "" {
|
||||
defaultPermissions = nil
|
||||
pkptr = &permissionKey
|
||||
}
|
||||
|
||||
return d.directoryClient.Create(ctx, "None", "now", "now", nil, metadata,
|
||||
&defaultPermissions, nil)
|
||||
defaultPermissions, pkptr)
|
||||
}
|
||||
|
||||
// Delete removes the specified empty directory. Note that the directory must be empty before it can be deleted..
|
||||
|
@ -76,6 +92,28 @@ func (d DirectoryURL) GetProperties(ctx context.Context) (*DirectoryGetPropertie
|
|||
return d.directoryClient.GetProperties(ctx, nil, nil)
|
||||
}
|
||||
|
||||
// SetProperties sets the directory's metadata and system properties.
|
||||
// Preserves values for SMB properties.
|
||||
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/set-directory-properties.
|
||||
func (d DirectoryURL) SetProperties(ctx context.Context, permissions, permissionKey string) (*DirectorySetPropertiesResponse, error) {
|
||||
defaultPermissions := &defaultPreservePermissionString
|
||||
// pkptr (permission key pointer) remains nil unless the user defines a permission key.
|
||||
var pkptr *string
|
||||
|
||||
// If the user is supplying a permission key, permissions will be empty.
|
||||
if permissions != "" {
|
||||
defaultPermissions = &permissions
|
||||
}
|
||||
|
||||
// This is handled AFTER permissions, in case the user accidentally supplies both.
|
||||
if permissionKey != "" {
|
||||
defaultPermissions = nil
|
||||
pkptr = &permissionKey
|
||||
}
|
||||
|
||||
return d.directoryClient.SetProperties(ctx, "preserve", "preserve", "preserve", nil, defaultPermissions, pkptr)
|
||||
}
|
||||
|
||||
// SetMetadata sets the directory's metadata.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-directory-metadata.
|
||||
func (d DirectoryURL) SetMetadata(ctx context.Context, metadata Metadata) (*DirectorySetMetadataResponse, error) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package azfile
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -20,6 +21,11 @@ const (
|
|||
FileMaxSizeInBytes int64 = 1 * 1024 * 1024 * 1024 * 1024 // 1TB
|
||||
)
|
||||
|
||||
// For all intents and purposes, this is a constant.
|
||||
// But you can't take the address of a constant string, so it's a variable.
|
||||
var defaultPermissionString = "inherit"
|
||||
var defaultPreservePermissionString = "preserve"
|
||||
|
||||
// A FileURL represents a URL to an Azure Storage file.
|
||||
type FileURL struct {
|
||||
fileClient fileClient
|
||||
|
@ -60,10 +66,24 @@ func (f FileURL) WithSnapshot(shareSnapshot string) FileURL {
|
|||
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/create-file.
|
||||
// Pass default values for SMB properties (ex: "None" for file attributes).
|
||||
func (f FileURL) Create(ctx context.Context, size int64, h FileHTTPHeaders, metadata Metadata) (*FileCreateResponse, error) {
|
||||
defaultPermissions := "inherit"
|
||||
defaultPermissions := &defaultPermissionString
|
||||
// pkptr (permission key pointer) remains nil unless the user defines a permission key.
|
||||
var pkptr *string
|
||||
|
||||
// If the user is supplying a permission key, permissions will be empty.
|
||||
if h.PermissionString != "" {
|
||||
defaultPermissions = &h.PermissionString
|
||||
}
|
||||
|
||||
// This is handled AFTER permissions, in case the user accidentally supplies both.
|
||||
if h.PermissionKey != "" {
|
||||
defaultPermissions = nil
|
||||
pkptr = &h.PermissionKey
|
||||
}
|
||||
|
||||
return f.fileClient.Create(ctx, size, "None", "now", "now", nil,
|
||||
&h.ContentType, &h.ContentEncoding, &h.ContentLanguage, &h.CacheControl,
|
||||
h.ContentMD5, &h.ContentDisposition, metadata, &defaultPermissions, nil)
|
||||
h.ContentMD5, &h.ContentDisposition, metadata, defaultPermissions, pkptr)
|
||||
}
|
||||
|
||||
// StartCopy copies the data at the source URL to a file.
|
||||
|
@ -142,10 +162,26 @@ func (f FileURL) GetProperties(ctx context.Context) (*FileGetPropertiesResponse,
|
|||
// SetHTTPHeaders sets file's system properties.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-file-properties.
|
||||
func (f FileURL) SetHTTPHeaders(ctx context.Context, h FileHTTPHeaders) (*FileSetHTTPHeadersResponse, error) {
|
||||
defaultPermissions := "preserve"
|
||||
defaultPermissions := &defaultPreservePermissionString
|
||||
// pkptr (permission key pointer) remains nil unless the user defines a permission key.
|
||||
var pkptr *string
|
||||
|
||||
// If the user is supplying a permission key, permissions will be empty.
|
||||
if h.PermissionString != "" {
|
||||
defaultPermissions = &h.PermissionString
|
||||
}
|
||||
|
||||
// This is handled AFTER permissions, in case the user accidentally supplies both.
|
||||
if h.PermissionKey != "" {
|
||||
defaultPermissions = nil
|
||||
pkptr = &h.PermissionKey
|
||||
}
|
||||
|
||||
fmt.Println(defaultPermissions, *defaultPermissions, pkptr)
|
||||
|
||||
return f.fileClient.SetHTTPHeaders(ctx, "preserve", "preserve", "preserve", nil,
|
||||
nil, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, &h.CacheControl, h.ContentMD5,
|
||||
&h.ContentDisposition, &defaultPermissions, nil)
|
||||
&h.ContentDisposition, defaultPermissions, nil)
|
||||
}
|
||||
|
||||
// SetMetadata sets a file's metadata.
|
||||
|
|
|
@ -116,6 +116,22 @@ func (s ShareURL) GetPermissions(ctx context.Context) (*SignedIdentifiers, error
|
|||
return s.shareClient.GetAccessPolicy(ctx, nil)
|
||||
}
|
||||
|
||||
// CreatePermission uploads a SDDL permission string, and returns a permission key to use in conjunction with a file or folder.
|
||||
// Note that this is only required for 9KB or larger permission strings.
|
||||
// Furthermore, note that SDDL strings should be converted to a portable format before being uploaded.
|
||||
// In order to make a SDDL portable, please replace well-known SIDs with their domain specific counterpart.
|
||||
// Well-known SIDs are listed here: https://docs.microsoft.com/en-us/windows/win32/secauthz/sid-strings
|
||||
// More info about SDDL strings can be located at: https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format
|
||||
func (s ShareURL) CreatePermission(ctx context.Context, permission string) (*ShareCreatePermissionResponse, error) {
|
||||
perm := SharePermission{Permission: permission}
|
||||
return s.shareClient.CreatePermission(ctx, perm, nil)
|
||||
}
|
||||
|
||||
// GetPermission obtains a SDDL permission string from the service using a known permission key.
|
||||
func (s ShareURL) GetPermission(ctx context.Context, permissionKey string) (*SharePermission, error) {
|
||||
return s.shareClient.GetPermission(ctx, permissionKey, nil)
|
||||
}
|
||||
|
||||
// The AccessPolicyPermission type simplifies creating the permissions string for a share's access policy.
|
||||
// Initialize an instance of this type and then call its String method to set AccessPolicy's Permission field.
|
||||
type AccessPolicyPermission struct {
|
||||
|
|
|
@ -99,7 +99,7 @@ func Example() {
|
|||
|
||||
// New a reference to a directory with name DemoDir in share, and create the directory.
|
||||
directoryDemoURL := shareURL.NewDirectoryURL("DemoDir")
|
||||
_, err = directoryDemoURL.Create(ctx, azfile.Metadata{})
|
||||
_, err = directoryDemoURL.Create(ctx, azfile.Metadata{}, "", "")
|
||||
if err != nil && err.(azfile.StorageError) != nil && err.(azfile.StorageError).ServiceCode() != azfile.ServiceCodeResourceAlreadyExists {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ func createNewDirectoryWithPrefix(c *chk.C, parentDirectory azfile.DirectoryURL,
|
|||
name = generateName(prefix)
|
||||
dir = parentDirectory.NewDirectoryURL(name)
|
||||
|
||||
cResp, err := dir.Create(ctx, azfile.Metadata{})
|
||||
cResp, err := dir.Create(ctx, azfile.Metadata{}, "", "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
c.Assert(cResp.StatusCode(), chk.Equals, 201)
|
||||
return dir, name
|
||||
|
@ -202,7 +202,7 @@ func createNewFileWithPrefix(c *chk.C, dir azfile.DirectoryURL, prefix string, s
|
|||
func createNewDirectoryFromShare(c *chk.C, share azfile.ShareURL) (dir azfile.DirectoryURL, name string) {
|
||||
dir, name = getDirectoryURLFromShare(c, share)
|
||||
|
||||
cResp, err := dir.Create(ctx, nil)
|
||||
cResp, err := dir.Create(ctx, nil, "", "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
c.Assert(cResp.StatusCode(), chk.Equals, 201)
|
||||
return dir, name
|
||||
|
@ -211,7 +211,7 @@ func createNewDirectoryFromShare(c *chk.C, share azfile.ShareURL) (dir azfile.Di
|
|||
func createNewDirectoryFromDirectory(c *chk.C, parentDirectory azfile.DirectoryURL) (dir azfile.DirectoryURL, name string) {
|
||||
dir, name = getDirectoryURLFromDirectory(c, parentDirectory)
|
||||
|
||||
cResp, err := dir.Create(ctx, nil)
|
||||
cResp, err := dir.Create(ctx, nil, "", "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
c.Assert(cResp.StatusCode(), chk.Equals, 201)
|
||||
return dir, name
|
||||
|
|
|
@ -52,7 +52,7 @@ func (s *DirectoryURLSuite) TestDirWithNewPipeline(c *chk.C) {
|
|||
dirURL := fsu.NewShareURL(sharePrefix).NewDirectoryURL(directoryPrefix)
|
||||
|
||||
newDirURL := dirURL.WithPipeline(testPipeline{})
|
||||
_, err := newDirURL.Create(ctx, azfile.Metadata{})
|
||||
_, err := newDirURL.Create(ctx, azfile.Metadata{}, "", "")
|
||||
c.Assert(err, chk.NotNil)
|
||||
c.Assert(err.Error(), chk.Equals, testPipelineMessage)
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ func (s *DirectoryURLSuite) TestDirCreateDeleteDefault(c *chk.C) {
|
|||
|
||||
directory := share.NewDirectoryURL(directoryName)
|
||||
|
||||
cResp, err := directory.Create(context.Background(), azfile.Metadata{})
|
||||
cResp, err := directory.Create(context.Background(), azfile.Metadata{}, "", "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
c.Assert(cResp.Response().StatusCode, chk.Equals, 201)
|
||||
c.Assert(cResp.Date().IsZero(), chk.Equals, false)
|
||||
|
@ -82,6 +82,31 @@ func (s *DirectoryURLSuite) TestDirCreateDeleteDefault(c *chk.C) {
|
|||
defer delDirectory(c, directory)
|
||||
}
|
||||
|
||||
func (s *DirectoryURLSuite) TestDirSetProperties(c *chk.C) {
|
||||
directoryName := generateDirectoryName()
|
||||
sa := getFSU()
|
||||
share, _ := createNewShare(c, sa)
|
||||
|
||||
defer delShare(c, share, azfile.DeleteSnapshotsOptionNone)
|
||||
|
||||
directory := share.NewDirectoryURL(directoryName)
|
||||
|
||||
cResp, err := directory.Create(ctx, azfile.Metadata{}, "", "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
key := cResp.FilePermissionKey()
|
||||
|
||||
// Set the custom permissions
|
||||
sResp, err := directory.SetProperties(ctx, sampleSDDL, "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
c.Assert(sResp.FilePermissionKey(), chk.Not(chk.Equals), key)
|
||||
key = sResp.FilePermissionKey()
|
||||
|
||||
gResp, err := directory.GetProperties(ctx)
|
||||
c.Assert(err, chk.IsNil)
|
||||
// Ensure the new key is present when we GetProperties
|
||||
c.Assert(gResp.FilePermissionKey(), chk.Equals, key)
|
||||
}
|
||||
|
||||
func (s *DirectoryURLSuite) TestDirCreateDeleteNonDefault(c *chk.C) {
|
||||
directoryName := generateDirectoryName()
|
||||
sa := getFSU()
|
||||
|
@ -96,8 +121,10 @@ func (s *DirectoryURLSuite) TestDirCreateDeleteNonDefault(c *chk.C) {
|
|||
"bar": "bArvaLue",
|
||||
}
|
||||
|
||||
cResp, err := directory.Create(context.Background(), md)
|
||||
cResp, err := directory.Create(context.Background(), md, sampleSDDL, "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
// Ensure that the file key isn't empty, but don't worry about checking the permission. We just need to know it exists.
|
||||
c.Assert(cResp.FilePermissionKey(), chk.Not(chk.Equals), "")
|
||||
c.Assert(cResp.Response().StatusCode, chk.Equals, 201)
|
||||
c.Assert(cResp.Date().IsZero(), chk.Equals, false)
|
||||
c.Assert(cResp.ETag(), chk.Not(chk.Equals), azfile.ETagNone)
|
||||
|
@ -110,7 +137,7 @@ func (s *DirectoryURLSuite) TestDirCreateDeleteNonDefault(c *chk.C) {
|
|||
c.Assert(gResp.StatusCode(), chk.Equals, 200)
|
||||
|
||||
// Creating again will result in 409 and ResourceAlreadyExists.
|
||||
cResp, err = directory.Create(context.Background(), md)
|
||||
cResp, err = directory.Create(context.Background(), md, "", "")
|
||||
c.Assert(err, chk.Not(chk.IsNil))
|
||||
serr := err.(azfile.StorageError)
|
||||
c.Assert(serr.Response().StatusCode, chk.Equals, 409)
|
||||
|
@ -142,17 +169,17 @@ func (s *DirectoryURLSuite) TestDirCreateDeleteNegativeMultiLevelDir(c *chk.C) {
|
|||
subDirURL := parentDirURL.NewDirectoryURL(subDirName)
|
||||
|
||||
// Directory create with subDirURL
|
||||
cResp, err := subDirURL.Create(context.Background(), nil)
|
||||
cResp, err := subDirURL.Create(context.Background(), nil, "", "")
|
||||
c.Assert(err, chk.NotNil)
|
||||
serr := err.(azfile.StorageError)
|
||||
c.Assert(serr.Response().StatusCode, chk.Equals, 404)
|
||||
c.Assert(serr.ServiceCode(), chk.Equals, azfile.ServiceCodeParentNotFound)
|
||||
|
||||
cResp, err = parentDirURL.Create(context.Background(), nil)
|
||||
cResp, err = parentDirURL.Create(context.Background(), nil, "", "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
c.Assert(cResp.Response().StatusCode, chk.Equals, 201)
|
||||
|
||||
cResp, err = subDirURL.Create(context.Background(), nil)
|
||||
cResp, err = subDirURL.Create(context.Background(), nil, "", "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
c.Assert(cResp.Response().StatusCode, chk.Equals, 201)
|
||||
|
||||
|
@ -187,7 +214,7 @@ func (s *DirectoryURLSuite) TestDirCreateEndWithSlash(c *chk.C) {
|
|||
|
||||
defer delDirectory(c, directory)
|
||||
|
||||
cResp, err := directory.Create(context.Background(), nil)
|
||||
cResp, err := directory.Create(context.Background(), nil, "", "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
c.Assert(cResp.Response().StatusCode, chk.Equals, 201)
|
||||
c.Assert(cResp.Date().IsZero(), chk.Equals, false)
|
||||
|
|
|
@ -163,6 +163,7 @@ func (s *FileURLSuite) TestFileGetSetPropertiesNonDefault(c *chk.C) {
|
|||
ContentMD5: testMd5,
|
||||
CacheControl: "no-transform",
|
||||
ContentDisposition: "attachment",
|
||||
PermissionString: sampleSDDL, // Because our permission string is less than 9KB, it can be used here.
|
||||
}
|
||||
setResp, err := fileURL.SetHTTPHeaders(context.Background(), properties)
|
||||
c.Assert(err, chk.IsNil)
|
||||
|
@ -187,6 +188,8 @@ func (s *FileURLSuite) TestFileGetSetPropertiesNonDefault(c *chk.C) {
|
|||
c.Assert(getResp.CacheControl(), chk.Equals, properties.CacheControl)
|
||||
c.Assert(getResp.ContentDisposition(), chk.Equals, properties.ContentDisposition)
|
||||
c.Assert(getResp.ContentLength(), chk.Equals, int64(0))
|
||||
// We'll just ensure a permission exists, no need to test overlapping functionality.
|
||||
c.Assert(getResp.FilePermissionKey(), chk.Not(chk.Equals), "")
|
||||
|
||||
c.Assert(getResp.ETag(), chk.Not(chk.Equals), azfile.ETagNone)
|
||||
c.Assert(getResp.RequestID(), chk.Not(chk.Equals), "")
|
||||
|
@ -739,7 +742,7 @@ func (f *FileURLSuite) TestServiceSASShareSAS(c *chk.C) {
|
|||
_, err = fileURL.Delete(ctx)
|
||||
c.Assert(err, chk.IsNil)
|
||||
|
||||
_, err = dirURL.Create(ctx, azfile.Metadata{})
|
||||
_, err = dirURL.Create(ctx, azfile.Metadata{}, "", "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
|
||||
_, err = dirURL.ListFilesAndDirectoriesSegment(ctx, azfile.Marker{}, azfile.ListFilesAndDirectoriesOptions{})
|
||||
|
|
|
@ -350,7 +350,7 @@ func (s *StorageAccountSuite) TestAccountSAS(c *chk.C) {
|
|||
testDirURL := dParts.URL()
|
||||
dirURLWithSAS := azfile.NewDirectoryURL(testDirURL, azfile.NewPipeline(azfile.NewAnonymousCredential(), azfile.PipelineOptions{}))
|
||||
// Create
|
||||
_, err = dirURLWithSAS.Create(ctx, azfile.Metadata{})
|
||||
_, err = dirURLWithSAS.Create(ctx, azfile.Metadata{}, "", "")
|
||||
c.Assert(err, chk.IsNil)
|
||||
// Write
|
||||
_, err = dirURLWithSAS.SetMetadata(ctx, metadata)
|
||||
|
|
|
@ -17,12 +17,40 @@ type ShareURLSuite struct{}
|
|||
|
||||
var _ = chk.Suite(&ShareURLSuite{})
|
||||
|
||||
// a sample SDDL string at https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format
|
||||
var sampleSDDL = `O:S-1-5-32-548G:S-1-5-21-397955417-626881126-188441444-512D:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)`
|
||||
|
||||
func delShare(c *chk.C, share azfile.ShareURL, option azfile.DeleteSnapshotsOptionType) {
|
||||
resp, err := share.Delete(context.Background(), option)
|
||||
c.Assert(err, chk.IsNil)
|
||||
c.Assert(resp.Response().StatusCode, chk.Equals, 202)
|
||||
}
|
||||
|
||||
func (s *ShareURLSuite) TestPutAndGetPermission(c *chk.C) {
|
||||
fsu := getFSU()
|
||||
shareURL, _ := getShareURL(c, fsu)
|
||||
|
||||
// Create the share.
|
||||
_, err := shareURL.Create(ctx, azfile.Metadata{}, 0)
|
||||
c.Assert(err, chk.IsNil)
|
||||
|
||||
// Create a permission and check that it's not empty.
|
||||
createResp, err := shareURL.CreatePermission(ctx, sampleSDDL)
|
||||
c.Assert(err, chk.IsNil)
|
||||
c.Assert(createResp.FilePermissionKey(), chk.Not(chk.Equals), "")
|
||||
|
||||
getResp, err := shareURL.GetPermission(ctx, createResp.FilePermissionKey())
|
||||
c.Assert(err, chk.IsNil)
|
||||
// Why check for emptiness instead of against the original?
|
||||
// Fun fact: Azure Files does some processing themselves, apparently!
|
||||
// This is a mitigation for it.
|
||||
/*
|
||||
Expected :string = "O:S-1-5-32-548G:S-1-5-21-397955417-626881126-188441444-512D:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
|
||||
Actual :string = "O:AOG:S-1-5-21-397955417-626881126-188441444-512D:(A;;CCDCLCSWRPWPRCWDWOGA;;;S-1-0-0)S:NO_ACCESS_CONTROL"
|
||||
*/
|
||||
c.Assert(getResp.Permission, chk.Not(chk.Equals), "")
|
||||
}
|
||||
|
||||
func (s *ShareURLSuite) TestShareCreateRootDirectoryURL(c *chk.C) {
|
||||
fsu := getFSU()
|
||||
testURL := fsu.NewShareURL(sharePrefix).NewRootDirectoryURL()
|
||||
|
|
|
@ -177,6 +177,16 @@ const (
|
|||
StorageErrorCodeAuthenticationFailed StorageErrorCodeType = "AuthenticationFailed"
|
||||
// StorageErrorCodeAuthorizationFailure ...
|
||||
StorageErrorCodeAuthorizationFailure StorageErrorCodeType = "AuthorizationFailure"
|
||||
// StorageErrorCodeAuthorizationPermissionMismatch ...
|
||||
StorageErrorCodeAuthorizationPermissionMismatch StorageErrorCodeType = "AuthorizationPermissionMismatch"
|
||||
// StorageErrorCodeAuthorizationProtocolMismatch ...
|
||||
StorageErrorCodeAuthorizationProtocolMismatch StorageErrorCodeType = "AuthorizationProtocolMismatch"
|
||||
// StorageErrorCodeAuthorizationResourceTypeMismatch ...
|
||||
StorageErrorCodeAuthorizationResourceTypeMismatch StorageErrorCodeType = "AuthorizationResourceTypeMismatch"
|
||||
// StorageErrorCodeAuthorizationServiceMismatch ...
|
||||
StorageErrorCodeAuthorizationServiceMismatch StorageErrorCodeType = "AuthorizationServiceMismatch"
|
||||
// StorageErrorCodeAuthorizationSourceIPMismatch ...
|
||||
StorageErrorCodeAuthorizationSourceIPMismatch StorageErrorCodeType = "AuthorizationSourceIPMismatch"
|
||||
// StorageErrorCodeCannotDeleteFileOrDirectory ...
|
||||
StorageErrorCodeCannotDeleteFileOrDirectory StorageErrorCodeType = "CannotDeleteFileOrDirectory"
|
||||
// StorageErrorCodeClientCacheFlushDelay ...
|
||||
|
@ -193,6 +203,8 @@ const (
|
|||
StorageErrorCodeDirectoryNotEmpty StorageErrorCodeType = "DirectoryNotEmpty"
|
||||
// StorageErrorCodeEmptyMetadataKey ...
|
||||
StorageErrorCodeEmptyMetadataKey StorageErrorCodeType = "EmptyMetadataKey"
|
||||
// StorageErrorCodeFeatureVersionMismatch ...
|
||||
StorageErrorCodeFeatureVersionMismatch StorageErrorCodeType = "FeatureVersionMismatch"
|
||||
// StorageErrorCodeFileLockConflict ...
|
||||
StorageErrorCodeFileLockConflict StorageErrorCodeType = "FileLockConflict"
|
||||
// StorageErrorCodeInsufficientAccountPermissions ...
|
||||
|
@ -293,7 +305,7 @@ const (
|
|||
|
||||
// PossibleStorageErrorCodeTypeValues returns an array of possible values for the StorageErrorCodeType const type.
|
||||
func PossibleStorageErrorCodeTypeValues() []StorageErrorCodeType {
|
||||
return []StorageErrorCodeType{StorageErrorCodeAccountAlreadyExists, StorageErrorCodeAccountBeingCreated, StorageErrorCodeAccountIsDisabled, StorageErrorCodeAuthenticationFailed, StorageErrorCodeAuthorizationFailure, StorageErrorCodeCannotDeleteFileOrDirectory, StorageErrorCodeClientCacheFlushDelay, StorageErrorCodeConditionHeadersNotSupported, StorageErrorCodeConditionNotMet, StorageErrorCodeContainerQuotaDowngradeNotAllowed, StorageErrorCodeDeletePending, StorageErrorCodeDirectoryNotEmpty, StorageErrorCodeEmptyMetadataKey, StorageErrorCodeFileLockConflict, StorageErrorCodeInsufficientAccountPermissions, StorageErrorCodeInternalError, StorageErrorCodeInvalidAuthenticationInfo, StorageErrorCodeInvalidFileOrDirectoryPathName, StorageErrorCodeInvalidHeaderValue, StorageErrorCodeInvalidHTTPVerb, StorageErrorCodeInvalidInput, StorageErrorCodeInvalidMd5, StorageErrorCodeInvalidMetadata, StorageErrorCodeInvalidQueryParameterValue, StorageErrorCodeInvalidRange, StorageErrorCodeInvalidResourceName, StorageErrorCodeInvalidURI, StorageErrorCodeInvalidXMLDocument, StorageErrorCodeInvalidXMLNodeValue, StorageErrorCodeMd5Mismatch, StorageErrorCodeMetadataTooLarge, StorageErrorCodeMissingContentLengthHeader, StorageErrorCodeMissingRequiredHeader, StorageErrorCodeMissingRequiredQueryParameter, StorageErrorCodeMissingRequiredXMLNode, StorageErrorCodeMultipleConditionHeadersNotSupported, StorageErrorCodeNone, StorageErrorCodeOperationTimedOut, StorageErrorCodeOutOfRangeInput, StorageErrorCodeOutOfRangeQueryParameterValue, StorageErrorCodeParentNotFound, StorageErrorCodeReadOnlyAttribute, StorageErrorCodeRequestBodyTooLarge, StorageErrorCodeRequestURLFailedToParse, StorageErrorCodeResourceAlreadyExists, StorageErrorCodeResourceNotFound, StorageErrorCodeResourceTypeMismatch, StorageErrorCodeServerBusy, StorageErrorCodeShareAlreadyExists, StorageErrorCodeShareBeingDeleted, StorageErrorCodeShareDisabled, StorageErrorCodeShareHasSnapshots, StorageErrorCodeShareNotFound, StorageErrorCodeShareSnapshotCountExceeded, StorageErrorCodeShareSnapshotInProgress, StorageErrorCodeShareSnapshotOperationNotSupported, StorageErrorCodeSharingViolation, StorageErrorCodeUnsupportedHeader, StorageErrorCodeUnsupportedHTTPVerb, StorageErrorCodeUnsupportedQueryParameter, StorageErrorCodeUnsupportedXMLNode}
|
||||
return []StorageErrorCodeType{StorageErrorCodeAccountAlreadyExists, StorageErrorCodeAccountBeingCreated, StorageErrorCodeAccountIsDisabled, StorageErrorCodeAuthenticationFailed, StorageErrorCodeAuthorizationFailure, StorageErrorCodeAuthorizationPermissionMismatch, StorageErrorCodeAuthorizationProtocolMismatch, StorageErrorCodeAuthorizationResourceTypeMismatch, StorageErrorCodeAuthorizationServiceMismatch, StorageErrorCodeAuthorizationSourceIPMismatch, StorageErrorCodeCannotDeleteFileOrDirectory, StorageErrorCodeClientCacheFlushDelay, StorageErrorCodeConditionHeadersNotSupported, StorageErrorCodeConditionNotMet, StorageErrorCodeContainerQuotaDowngradeNotAllowed, StorageErrorCodeDeletePending, StorageErrorCodeDirectoryNotEmpty, StorageErrorCodeEmptyMetadataKey, StorageErrorCodeFeatureVersionMismatch, StorageErrorCodeFileLockConflict, StorageErrorCodeInsufficientAccountPermissions, StorageErrorCodeInternalError, StorageErrorCodeInvalidAuthenticationInfo, StorageErrorCodeInvalidFileOrDirectoryPathName, StorageErrorCodeInvalidHeaderValue, StorageErrorCodeInvalidHTTPVerb, StorageErrorCodeInvalidInput, StorageErrorCodeInvalidMd5, StorageErrorCodeInvalidMetadata, StorageErrorCodeInvalidQueryParameterValue, StorageErrorCodeInvalidRange, StorageErrorCodeInvalidResourceName, StorageErrorCodeInvalidURI, StorageErrorCodeInvalidXMLDocument, StorageErrorCodeInvalidXMLNodeValue, StorageErrorCodeMd5Mismatch, StorageErrorCodeMetadataTooLarge, StorageErrorCodeMissingContentLengthHeader, StorageErrorCodeMissingRequiredHeader, StorageErrorCodeMissingRequiredQueryParameter, StorageErrorCodeMissingRequiredXMLNode, StorageErrorCodeMultipleConditionHeadersNotSupported, StorageErrorCodeNone, StorageErrorCodeOperationTimedOut, StorageErrorCodeOutOfRangeInput, StorageErrorCodeOutOfRangeQueryParameterValue, StorageErrorCodeParentNotFound, StorageErrorCodeReadOnlyAttribute, StorageErrorCodeRequestBodyTooLarge, StorageErrorCodeRequestURLFailedToParse, StorageErrorCodeResourceAlreadyExists, StorageErrorCodeResourceNotFound, StorageErrorCodeResourceTypeMismatch, StorageErrorCodeServerBusy, StorageErrorCodeShareAlreadyExists, StorageErrorCodeShareBeingDeleted, StorageErrorCodeShareDisabled, StorageErrorCodeShareHasSnapshots, StorageErrorCodeShareNotFound, StorageErrorCodeShareSnapshotCountExceeded, StorageErrorCodeShareSnapshotInProgress, StorageErrorCodeShareSnapshotOperationNotSupported, StorageErrorCodeSharingViolation, StorageErrorCodeUnsupportedHeader, StorageErrorCodeUnsupportedHTTPVerb, StorageErrorCodeUnsupportedQueryParameter, StorageErrorCodeUnsupportedXMLNode}
|
||||
}
|
||||
|
||||
// AccessPolicy - An Access policy.
|
||||
|
@ -2676,7 +2688,7 @@ type ShareItem struct {
|
|||
type SharePermission struct {
|
||||
rawResponse *http.Response
|
||||
// Permission - The permission in the Security Descriptor Definition Language (SDDL).
|
||||
Permission string `xml:"permission"`
|
||||
Permission string
|
||||
}
|
||||
|
||||
// Response returns the raw HTTP response object.
|
||||
|
|
|
@ -6,6 +6,7 @@ package azfile
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
||||
"io"
|
||||
|
@ -126,7 +127,7 @@ func (client shareClient) createPermissionPreparer(sharePermission SharePermissi
|
|||
params.Set("comp", "filepermission")
|
||||
req.URL.RawQuery = params.Encode()
|
||||
req.Header.Set("x-ms-version", ServiceVersion)
|
||||
b, err := xml.Marshal(sharePermission)
|
||||
b, err := json.Marshal(sharePermission)
|
||||
if err != nil {
|
||||
return req, pipeline.NewError(err, "failed to marshal request body")
|
||||
}
|
||||
|
@ -331,12 +332,11 @@ func (client shareClient) getAccessPolicyResponder(resp pipeline.Response) (pipe
|
|||
|
||||
// GetPermission returns the permission (security descriptor) for a given key
|
||||
//
|
||||
// filePermissionKey is key of the permission to be set for the directory/file. Note: Only one of the
|
||||
// x-ms-file-permission or x-ms-file-permission-key should be specified. timeout is the timeout parameter is expressed
|
||||
// in seconds. For more information, see <a
|
||||
// filePermissionKey is key of the permission to be set for the directory/file. timeout is the timeout parameter is
|
||||
// expressed in seconds. For more information, see <a
|
||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting
|
||||
// Timeouts for File Service Operations.</a>
|
||||
func (client shareClient) GetPermission(ctx context.Context, filePermissionKey *string, timeout *int32) (*SharePermission, error) {
|
||||
func (client shareClient) GetPermission(ctx context.Context, filePermissionKey string, timeout *int32) (*SharePermission, error) {
|
||||
if err := validate([]validation{
|
||||
{targetValue: timeout,
|
||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
||||
|
@ -355,7 +355,7 @@ func (client shareClient) GetPermission(ctx context.Context, filePermissionKey *
|
|||
}
|
||||
|
||||
// getPermissionPreparer prepares the GetPermission request.
|
||||
func (client shareClient) getPermissionPreparer(filePermissionKey *string, timeout *int32) (pipeline.Request, error) {
|
||||
func (client shareClient) getPermissionPreparer(filePermissionKey string, timeout *int32) (pipeline.Request, error) {
|
||||
req, err := pipeline.NewRequest("GET", client.url, nil)
|
||||
if err != nil {
|
||||
return req, pipeline.NewError(err, "failed to create request")
|
||||
|
@ -367,9 +367,7 @@ func (client shareClient) getPermissionPreparer(filePermissionKey *string, timeo
|
|||
params.Set("restype", "share")
|
||||
params.Set("comp", "filepermission")
|
||||
req.URL.RawQuery = params.Encode()
|
||||
if filePermissionKey != nil {
|
||||
req.Header.Set("x-ms-file-permission-key", *filePermissionKey)
|
||||
}
|
||||
req.Header.Set("x-ms-file-permission-key", filePermissionKey)
|
||||
req.Header.Set("x-ms-version", ServiceVersion)
|
||||
return req, nil
|
||||
}
|
||||
|
@ -391,7 +389,7 @@ func (client shareClient) getPermissionResponder(resp pipeline.Response) (pipeli
|
|||
}
|
||||
if len(b) > 0 {
|
||||
b = removeBOM(b)
|
||||
err = xml.Unmarshal(b, result)
|
||||
err = json.Unmarshal(b, result)
|
||||
if err != nil {
|
||||
return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
|
||||
}
|
||||
|
|
|
@ -15,6 +15,10 @@ type FileHTTPHeaders struct {
|
|||
ContentLanguage string
|
||||
ContentDisposition string
|
||||
CacheControl string
|
||||
|
||||
// NOTE: Permission strings are required to be sub-9KB. Please upload the permission to the share, and submit a key instead if yours exceeds this limit.
|
||||
PermissionString string
|
||||
PermissionKey string
|
||||
}
|
||||
|
||||
// NewHTTPHeaders returns the user-modifiable properties for this file.
|
||||
|
|
1
go.mod
1
go.mod
|
@ -4,6 +4,7 @@ require (
|
|||
github.com/Azure/azure-pipeline-go v0.2.1
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/kr/pty v1.1.5 // indirect
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
|
||||
)
|
||||
|
|
6
go.sum
6
go.sum
|
@ -9,7 +9,13 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149 h1:HfxbT6/JcvIljmERptWhwa8XzP7H3T+Z2N26gTsaDaA=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/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-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/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=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
@ -9,6 +9,10 @@ autorest README.md --use=@microsoft.azure/autorest.go@v3.0.63
|
|||
gofmt -w Go_FileStorage/*
|
||||
```
|
||||
|
||||
More modifications have to be made after generation in order to fix issues that the Go generator can't work around right now`. Namely:
|
||||
- Under shareClient.getPermissionResponder and shareClient.createPermissionPreparer, change all xml.Marshal and xml.Unmarshal lines to json.Marshal and json.Unmarshal respectively
|
||||
- (Issue opened: https://github.com/Azure/go-autorest/issues/495)
|
||||
|
||||
### Settings
|
||||
``` yaml
|
||||
input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/storage-dataplane-preview/specification/storage/data-plane/Microsoft.FileStorage/preview/2019-02-02/file.json
|
||||
|
|
Загрузка…
Ссылка в новой задаче