From 615e36b81834d90eab9e4c15d69710057049ffcb Mon Sep 17 00:00:00 2001 From: tanyasethi-msft Date: Tue, 30 Jan 2024 11:46:53 +0530 Subject: [PATCH 1/6] path escape names to file and directory client --- sdk/storage/azdatalake/CHANGELOG.md | 1 + sdk/storage/azdatalake/filesystem/client.go | 5 +- .../azdatalake/filesystem/client_test.go | 49 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/sdk/storage/azdatalake/CHANGELOG.md b/sdk/storage/azdatalake/CHANGELOG.md index 1c764fbce113..380c32ad18e2 100644 --- a/sdk/storage/azdatalake/CHANGELOG.md +++ b/sdk/storage/azdatalake/CHANGELOG.md @@ -7,6 +7,7 @@ ### Breaking Changes ### Bugs Fixed +* Escape paths for NewDirectoryClient and New FileClient in a file system ### Other Changes diff --git a/sdk/storage/azdatalake/filesystem/client.go b/sdk/storage/azdatalake/filesystem/client.go index b69f14ba29eb..afb8dd408b6b 100644 --- a/sdk/storage/azdatalake/filesystem/client.go +++ b/sdk/storage/azdatalake/filesystem/client.go @@ -24,6 +24,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/sas" "net/http" + "net/url" "strings" "time" ) @@ -201,7 +202,7 @@ func (fs *Client) BlobURL() string { // NewDirectoryClient creates a new directory.Client object by concatenating directory path to the end of this Client's URL. // The new directory.Client uses the same request policy pipeline as the Client. func (fs *Client) NewDirectoryClient(directoryPath string) *directory.Client { - directoryPath = strings.ReplaceAll(directoryPath, "\\", "/") + directoryPath = url.PathEscape(strings.ReplaceAll(directoryPath, "\\", "/")) dirURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), directoryPath) blobURL, dirURL := shared.GetURLs(dirURL) return (*directory.Client)(base.NewPathClient(dirURL, blobURL, fs.containerClient().NewBlockBlobClient(directoryPath), fs.generatedFSClientWithDFS().InternalClient().WithClientName(exported.ModuleName), fs.sharedKey(), fs.identityCredential(), fs.getClientOptions())) @@ -210,7 +211,7 @@ func (fs *Client) NewDirectoryClient(directoryPath string) *directory.Client { // NewFileClient creates a new file.Client object by concatenating file path to the end of this Client's URL. // The new file.Client uses the same request policy pipeline as the Client. func (fs *Client) NewFileClient(filePath string) *file.Client { - filePath = strings.ReplaceAll(filePath, "\\", "/") + filePath = url.PathEscape(strings.ReplaceAll(filePath, "\\", "/")) fileURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), filePath) blobURL, fileURL := shared.GetURLs(fileURL) return (*file.Client)(base.NewPathClient(fileURL, blobURL, fs.containerClient().NewBlockBlobClient(filePath), fs.generatedFSClientWithDFS().InternalClient().WithClientName(exported.ModuleName), fs.sharedKey(), fs.identityCredential(), fs.getClientOptions())) diff --git a/sdk/storage/azdatalake/filesystem/client_test.go b/sdk/storage/azdatalake/filesystem/client_test.go index c5bad8f0628a..3b3621a828fd 100644 --- a/sdk/storage/azdatalake/filesystem/client_test.go +++ b/sdk/storage/azdatalake/filesystem/client_test.go @@ -8,6 +8,7 @@ package filesystem_test import ( "context" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/file" "strconv" "strings" "testing" @@ -1318,6 +1319,54 @@ func (s *UnrecordedTestSuite) TestSASFileSystemClient() { _require.NoError(err) } +func (s *RecordedTestSuite) TestCreateFileSystemDirectoryClientWithSpecialDirName() { + _require := require.New(s.T()) + testName := s.T().Name() + + filesystemName := testcommon.GenerateFileSystemName(testName) + fsClient, err := testcommon.GetFileSystemClient(filesystemName, s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + defer testcommon.DeleteFileSystem(context.Background(), _require, fsClient) + + _, err = fsClient.Create(context.Background(), nil) + _require.NoError(err) + + dirClient := fsClient.NewDirectoryClient("#,%,?") + _require.NoError(err) + + response, err := dirClient.Create(context.Background(), nil) + _require.NoError(err) + _require.NotNil(response) + + owner := "4cf4e284-f6a8-4540-b53e-c3469af032dc" + _, err = dirClient.SetAccessControl(context.Background(), &file.SetAccessControlOptions{Owner: &owner}) + _require.NoError(err) +} + +func (s *RecordedTestSuite) TestCreateFileSystemFileClientWithSpecialFileName() { + _require := require.New(s.T()) + testName := s.T().Name() + + filesystemName := testcommon.GenerateFileSystemName(testName) + fsClient, err := testcommon.GetFileSystemClient(filesystemName, s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + defer testcommon.DeleteFileSystem(context.Background(), _require, fsClient) + + _, err = fsClient.Create(context.Background(), nil) + _require.NoError(err) + + fileClient := fsClient.NewFileClient("#,%,?") + _require.NoError(err) + + response, err := fileClient.Create(context.Background(), nil) + _require.NoError(err) + _require.NotNil(response) + + owner := "4cf4e284-f6a8-4540-b53e-c3469af032dc" + _, err = fileClient.SetAccessControl(context.Background(), &file.SetAccessControlOptions{Owner: &owner}) + _require.NoError(err) +} + func (s *RecordedTestSuite) TestFilesystemListPathsWithRecursive() { _require := require.New(s.T()) testName := s.T().Name() From 7715da4341dcc9b7ded0ceb4fe3ca828104bad64 Mon Sep 17 00:00:00 2001 From: tanyasethi-msft Date: Wed, 31 Jan 2024 16:32:41 +0530 Subject: [PATCH 2/6] split path and escape logic --- sdk/storage/azdatalake/filesystem/client.go | 26 ++++++++++++++++--- .../azdatalake/filesystem/client_test.go | 7 ++++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/sdk/storage/azdatalake/filesystem/client.go b/sdk/storage/azdatalake/filesystem/client.go index afb8dd408b6b..fb07bf6e148b 100644 --- a/sdk/storage/azdatalake/filesystem/client.go +++ b/sdk/storage/azdatalake/filesystem/client.go @@ -202,8 +202,16 @@ func (fs *Client) BlobURL() string { // NewDirectoryClient creates a new directory.Client object by concatenating directory path to the end of this Client's URL. // The new directory.Client uses the same request policy pipeline as the Client. func (fs *Client) NewDirectoryClient(directoryPath string) *directory.Client { - directoryPath = url.PathEscape(strings.ReplaceAll(directoryPath, "\\", "/")) - dirURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), directoryPath) + directoryPath = strings.ReplaceAll(directoryPath, "\\", "/") + names := strings.Split(directoryPath, "/") + path := "" + for i, name := range names { + if i > 0 { + path += "/" + } + path += url.PathEscape(name) + } + dirURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), path) blobURL, dirURL := shared.GetURLs(dirURL) return (*directory.Client)(base.NewPathClient(dirURL, blobURL, fs.containerClient().NewBlockBlobClient(directoryPath), fs.generatedFSClientWithDFS().InternalClient().WithClientName(exported.ModuleName), fs.sharedKey(), fs.identityCredential(), fs.getClientOptions())) } @@ -211,8 +219,18 @@ func (fs *Client) NewDirectoryClient(directoryPath string) *directory.Client { // NewFileClient creates a new file.Client object by concatenating file path to the end of this Client's URL. // The new file.Client uses the same request policy pipeline as the Client. func (fs *Client) NewFileClient(filePath string) *file.Client { - filePath = url.PathEscape(strings.ReplaceAll(filePath, "\\", "/")) - fileURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), filePath) + filePath = strings.ReplaceAll(filePath, "\\", "/") + + names := strings.Split(filePath, "/") + path := "" + for i, name := range names { + if i > 0 { + path += "/" + } + path += url.PathEscape(name) + + } + fileURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), path) blobURL, fileURL := shared.GetURLs(fileURL) return (*file.Client)(base.NewPathClient(fileURL, blobURL, fs.containerClient().NewBlockBlobClient(filePath), fs.generatedFSClientWithDFS().InternalClient().WithClientName(exported.ModuleName), fs.sharedKey(), fs.identityCredential(), fs.getClientOptions())) } diff --git a/sdk/storage/azdatalake/filesystem/client_test.go b/sdk/storage/azdatalake/filesystem/client_test.go index 3b3621a828fd..9a0e83c13766 100644 --- a/sdk/storage/azdatalake/filesystem/client_test.go +++ b/sdk/storage/azdatalake/filesystem/client_test.go @@ -1331,16 +1331,21 @@ func (s *RecordedTestSuite) TestCreateFileSystemDirectoryClientWithSpecialDirNam _, err = fsClient.Create(context.Background(), nil) _require.NoError(err) - dirClient := fsClient.NewDirectoryClient("#,%,?") + dirClient := fsClient.NewDirectoryClient("#,%,?/%,#") _require.NoError(err) response, err := dirClient.Create(context.Background(), nil) _require.NoError(err) _require.NotNil(response) + // Perform an operation on dfs endpoint owner := "4cf4e284-f6a8-4540-b53e-c3469af032dc" _, err = dirClient.SetAccessControl(context.Background(), &file.SetAccessControlOptions{Owner: &owner}) _require.NoError(err) + + // Perform an operation on blob endpoint + _, err = dirClient.SetMetadata(context.Background(), testcommon.BasicMetadata, nil) + _require.NoError(err) } func (s *RecordedTestSuite) TestCreateFileSystemFileClientWithSpecialFileName() { From 8e03f975a3abf420a992d5a41ab8d6d3ed72367c Mon Sep 17 00:00:00 2001 From: tanyasethi-msft Date: Wed, 31 Jan 2024 16:56:29 +0530 Subject: [PATCH 3/6] recordings --- sdk/storage/azdatalake/assets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azdatalake/assets.json b/sdk/storage/azdatalake/assets.json index 626d6568abd4..6190e78a8551 100644 --- a/sdk/storage/azdatalake/assets.json +++ b/sdk/storage/azdatalake/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "go", "TagPrefix": "go/storage/azdatalake", - "Tag": "go/storage/azdatalake_3ae5e1441b" + "Tag": "go/storage/azdatalake_efb4a0575e" } From 6684ddb602f6b35018c2d9502a52c62ee1833c43 Mon Sep 17 00:00:00 2001 From: tanyasethi-msft Date: Wed, 31 Jan 2024 17:21:38 +0530 Subject: [PATCH 4/6] recordings --- sdk/storage/azdatalake/assets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azdatalake/assets.json b/sdk/storage/azdatalake/assets.json index 6190e78a8551..3d4b5d8113f5 100644 --- a/sdk/storage/azdatalake/assets.json +++ b/sdk/storage/azdatalake/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "go", "TagPrefix": "go/storage/azdatalake", - "Tag": "go/storage/azdatalake_efb4a0575e" + "Tag": "go/storage/azdatalake_9977ab7169" } From fc24832505ec687464f916d65613b9dde31b4bdd Mon Sep 17 00:00:00 2001 From: tanyasethi-msft Date: Thu, 1 Feb 2024 22:30:28 +0530 Subject: [PATCH 5/6] refactor --- sdk/storage/azdatalake/CHANGELOG.md | 2 +- sdk/storage/azdatalake/assets.json | 2 +- sdk/storage/azdatalake/filesystem/client.go | 23 ++----------------- .../azdatalake/filesystem/client_test.go | 6 ++++- sdk/storage/azdatalake/filesystem/utils.go | 23 +++++++++++++++++++ 5 files changed, 32 insertions(+), 24 deletions(-) create mode 100644 sdk/storage/azdatalake/filesystem/utils.go diff --git a/sdk/storage/azdatalake/CHANGELOG.md b/sdk/storage/azdatalake/CHANGELOG.md index 380c32ad18e2..a05617092be2 100644 --- a/sdk/storage/azdatalake/CHANGELOG.md +++ b/sdk/storage/azdatalake/CHANGELOG.md @@ -7,7 +7,7 @@ ### Breaking Changes ### Bugs Fixed -* Escape paths for NewDirectoryClient and New FileClient in a file system +* Escape paths for NewDirectoryClient and NewFileClient in a file system. Fixes [#22281](https://github.com/Azure/azure-sdk-for-go/issues/22281). ### Other Changes diff --git a/sdk/storage/azdatalake/assets.json b/sdk/storage/azdatalake/assets.json index 3d4b5d8113f5..c262e52c7f2b 100644 --- a/sdk/storage/azdatalake/assets.json +++ b/sdk/storage/azdatalake/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "go", "TagPrefix": "go/storage/azdatalake", - "Tag": "go/storage/azdatalake_9977ab7169" + "Tag": "go/storage/azdatalake_05091fc1bd" } diff --git a/sdk/storage/azdatalake/filesystem/client.go b/sdk/storage/azdatalake/filesystem/client.go index fb07bf6e148b..f7f374e713d1 100644 --- a/sdk/storage/azdatalake/filesystem/client.go +++ b/sdk/storage/azdatalake/filesystem/client.go @@ -24,7 +24,6 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/sas" "net/http" - "net/url" "strings" "time" ) @@ -203,15 +202,7 @@ func (fs *Client) BlobURL() string { // The new directory.Client uses the same request policy pipeline as the Client. func (fs *Client) NewDirectoryClient(directoryPath string) *directory.Client { directoryPath = strings.ReplaceAll(directoryPath, "\\", "/") - names := strings.Split(directoryPath, "/") - path := "" - for i, name := range names { - if i > 0 { - path += "/" - } - path += url.PathEscape(name) - } - dirURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), path) + dirURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), escapeSplitPaths(directoryPath)) blobURL, dirURL := shared.GetURLs(dirURL) return (*directory.Client)(base.NewPathClient(dirURL, blobURL, fs.containerClient().NewBlockBlobClient(directoryPath), fs.generatedFSClientWithDFS().InternalClient().WithClientName(exported.ModuleName), fs.sharedKey(), fs.identityCredential(), fs.getClientOptions())) } @@ -220,17 +211,7 @@ func (fs *Client) NewDirectoryClient(directoryPath string) *directory.Client { // The new file.Client uses the same request policy pipeline as the Client. func (fs *Client) NewFileClient(filePath string) *file.Client { filePath = strings.ReplaceAll(filePath, "\\", "/") - - names := strings.Split(filePath, "/") - path := "" - for i, name := range names { - if i > 0 { - path += "/" - } - path += url.PathEscape(name) - - } - fileURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), path) + fileURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), escapeSplitPaths(filePath)) blobURL, fileURL := shared.GetURLs(fileURL) return (*file.Client)(base.NewPathClient(fileURL, blobURL, fs.containerClient().NewBlockBlobClient(filePath), fs.generatedFSClientWithDFS().InternalClient().WithClientName(exported.ModuleName), fs.sharedKey(), fs.identityCredential(), fs.getClientOptions())) } diff --git a/sdk/storage/azdatalake/filesystem/client_test.go b/sdk/storage/azdatalake/filesystem/client_test.go index 9a0e83c13766..62939e0727fa 100644 --- a/sdk/storage/azdatalake/filesystem/client_test.go +++ b/sdk/storage/azdatalake/filesystem/client_test.go @@ -1360,7 +1360,7 @@ func (s *RecordedTestSuite) TestCreateFileSystemFileClientWithSpecialFileName() _, err = fsClient.Create(context.Background(), nil) _require.NoError(err) - fileClient := fsClient.NewFileClient("#,%,?") + fileClient := fsClient.NewFileClient("#,%,?/#") _require.NoError(err) response, err := fileClient.Create(context.Background(), nil) @@ -1370,6 +1370,10 @@ func (s *RecordedTestSuite) TestCreateFileSystemFileClientWithSpecialFileName() owner := "4cf4e284-f6a8-4540-b53e-c3469af032dc" _, err = fileClient.SetAccessControl(context.Background(), &file.SetAccessControlOptions{Owner: &owner}) _require.NoError(err) + + // Perform an operation on blob endpoint + _, err = fileClient.SetMetadata(context.Background(), testcommon.BasicMetadata, nil) + _require.NoError(err) } func (s *RecordedTestSuite) TestFilesystemListPathsWithRecursive() { diff --git a/sdk/storage/azdatalake/filesystem/utils.go b/sdk/storage/azdatalake/filesystem/utils.go new file mode 100644 index 000000000000..d4d48e89b381 --- /dev/null +++ b/sdk/storage/azdatalake/filesystem/utils.go @@ -0,0 +1,23 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package filesystem + +import ( + "net/url" + "strings" +) + +// escapeSplitPaths is utility function to escape the individual strings by eliminating "/" in the path +func escapeSplitPaths(filePath string) string { + names := strings.Split(filePath, "/") + path := make([]string, len(names)) + for i, name := range names { + path[i] = url.PathEscape(name) + } + escapedPathUrl := strings.Join(path, "/") + return escapedPathUrl +} From 40da8387f8cfba366fc6fa9a35bb97b7152b60ad Mon Sep 17 00:00:00 2001 From: tanyasethi-msft Date: Fri, 2 Feb 2024 09:51:55 +0530 Subject: [PATCH 6/6] add new tests --- sdk/storage/azdatalake/assets.json | 2 +- .../azdatalake/directory/client_test.go | 64 +++++++++++++++++++ sdk/storage/azdatalake/filesystem/client.go | 4 +- .../azdatalake/filesystem/client_test.go | 27 ++++++++ sdk/storage/azdatalake/filesystem/utils.go | 23 ------- .../azdatalake/internal/shared/shared.go | 11 ++++ 6 files changed, 105 insertions(+), 26 deletions(-) delete mode 100644 sdk/storage/azdatalake/filesystem/utils.go diff --git a/sdk/storage/azdatalake/assets.json b/sdk/storage/azdatalake/assets.json index c262e52c7f2b..a700b917992b 100644 --- a/sdk/storage/azdatalake/assets.json +++ b/sdk/storage/azdatalake/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "go", "TagPrefix": "go/storage/azdatalake", - "Tag": "go/storage/azdatalake_05091fc1bd" + "Tag": "go/storage/azdatalake_82ea48120e" } diff --git a/sdk/storage/azdatalake/directory/client_test.go b/sdk/storage/azdatalake/directory/client_test.go index 7214cdfd9726..6fb6b6e2eaa8 100644 --- a/sdk/storage/azdatalake/directory/client_test.go +++ b/sdk/storage/azdatalake/directory/client_test.go @@ -201,6 +201,35 @@ func (s *RecordedTestSuite) TestGetAndCreateFileClient() { _require.NoError(err) } +func (s *RecordedTestSuite) TestGetAndCreateFileClientWithSpecialNames() { + _require := require.New(s.T()) + testName := s.T().Name() + + filesystemName := testcommon.GenerateFileSystemName(testName) + fsClient, err := testcommon.GetFileSystemClient(filesystemName, s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + defer testcommon.DeleteFileSystem(context.Background(), _require, fsClient) + + _, err = fsClient.Create(context.Background(), nil) + _require.NoError(err) + + dirClient := fsClient.NewDirectoryClient("#,%,?") + _require.NoError(err) + + defer testcommon.DeleteDir(context.Background(), _require, dirClient) + + resp, err := dirClient.Create(context.Background(), nil) + _require.NoError(err) + _require.NotNil(resp) + + fileClient, err := dirClient.NewFileClient("?%#,") + _require.NoError(err) + _require.NotNil(fileClient) + + _, err = fileClient.Create(context.Background(), nil) + _require.NoError(err) +} + func (s *RecordedTestSuite) TestCreateNewSubdirectoryClient() { _require := require.New(s.T()) testName := s.T().Name() @@ -265,6 +294,41 @@ func (s *RecordedTestSuite) TestCreateNewSubdirectoryClient() { _require.True(datalakeerror.HasCode(err, datalakeerror.PathNotFound)) } +func (s *RecordedTestSuite) TestCreateNewSubdirectoryClientWithSpecialName() { + _require := require.New(s.T()) + testName := s.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDatalake) + _require.Greater(len(accountName), 0) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + fsName := testcommon.GenerateFileSystemName(testName) + fsClient := svcClient.NewFileSystemClient(fsName) + + _, err = fsClient.Create(context.Background(), nil) + _require.NoError(err) + + defer testcommon.DeleteFileSystem(context.Background(), _require, fsClient) + + dirClient := fsClient.NewDirectoryClient("?#%") + + _, err = dirClient.Create(context.Background(), nil) + _require.NoError(err) + + subdirClient, err := dirClient.NewSubdirectoryClient(",%,#,?") + _require.NoError(err) + + perm := "r-xr-x---" + + _, err = subdirClient.Create(context.Background(), &directory.CreateOptions{ + Permissions: &perm, + CPKInfo: &testcommon.TestCPKByValue, + }) + _require.NoError(err) +} + func (s *RecordedTestSuite) TestCreateDirWithNilAccessConditions() { _require := require.New(s.T()) testName := s.T().Name() diff --git a/sdk/storage/azdatalake/filesystem/client.go b/sdk/storage/azdatalake/filesystem/client.go index f7f374e713d1..4fc2e7878bb6 100644 --- a/sdk/storage/azdatalake/filesystem/client.go +++ b/sdk/storage/azdatalake/filesystem/client.go @@ -202,7 +202,7 @@ func (fs *Client) BlobURL() string { // The new directory.Client uses the same request policy pipeline as the Client. func (fs *Client) NewDirectoryClient(directoryPath string) *directory.Client { directoryPath = strings.ReplaceAll(directoryPath, "\\", "/") - dirURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), escapeSplitPaths(directoryPath)) + dirURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), shared.EscapeSplitPaths(directoryPath)) blobURL, dirURL := shared.GetURLs(dirURL) return (*directory.Client)(base.NewPathClient(dirURL, blobURL, fs.containerClient().NewBlockBlobClient(directoryPath), fs.generatedFSClientWithDFS().InternalClient().WithClientName(exported.ModuleName), fs.sharedKey(), fs.identityCredential(), fs.getClientOptions())) } @@ -211,7 +211,7 @@ func (fs *Client) NewDirectoryClient(directoryPath string) *directory.Client { // The new file.Client uses the same request policy pipeline as the Client. func (fs *Client) NewFileClient(filePath string) *file.Client { filePath = strings.ReplaceAll(filePath, "\\", "/") - fileURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), escapeSplitPaths(filePath)) + fileURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), shared.EscapeSplitPaths(filePath)) blobURL, fileURL := shared.GetURLs(fileURL) return (*file.Client)(base.NewPathClient(fileURL, blobURL, fs.containerClient().NewBlockBlobClient(filePath), fs.generatedFSClientWithDFS().InternalClient().WithClientName(exported.ModuleName), fs.sharedKey(), fs.identityCredential(), fs.getClientOptions())) } diff --git a/sdk/storage/azdatalake/filesystem/client_test.go b/sdk/storage/azdatalake/filesystem/client_test.go index 62939e0727fa..a1f42713d8cd 100644 --- a/sdk/storage/azdatalake/filesystem/client_test.go +++ b/sdk/storage/azdatalake/filesystem/client_test.go @@ -1367,6 +1367,7 @@ func (s *RecordedTestSuite) TestCreateFileSystemFileClientWithSpecialFileName() _require.NoError(err) _require.NotNil(response) + // Perform an operation on dfs endpoint owner := "4cf4e284-f6a8-4540-b53e-c3469af032dc" _, err = fileClient.SetAccessControl(context.Background(), &file.SetAccessControlOptions{Owner: &owner}) _require.NoError(err) @@ -1376,6 +1377,32 @@ func (s *RecordedTestSuite) TestCreateFileSystemFileClientWithSpecialFileName() _require.NoError(err) } +func (s *RecordedTestSuite) TestCreateFileClientFromDirectoryClientWithSpecialFileName() { + _require := require.New(s.T()) + testName := s.T().Name() + + filesystemName := testcommon.GenerateFileSystemName(testName) + fsClient, err := testcommon.GetFileSystemClient(filesystemName, s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + defer testcommon.DeleteFileSystem(context.Background(), _require, fsClient) + + _, err = fsClient.Create(context.Background(), nil) + _require.NoError(err) + + dirClient := fsClient.NewDirectoryClient("#,%,?/%,#") + _require.NoError(err) + + fileClient, err := dirClient.NewFileClient("%,?/##") + _require.NoError(err) + + response, err := fileClient.Create(context.Background(), nil) + _require.NoError(err) + _require.NotNil(response) + + _, err = fileClient.SetMetadata(context.Background(), testcommon.BasicMetadata, nil) + _require.NoError(err) +} + func (s *RecordedTestSuite) TestFilesystemListPathsWithRecursive() { _require := require.New(s.T()) testName := s.T().Name() diff --git a/sdk/storage/azdatalake/filesystem/utils.go b/sdk/storage/azdatalake/filesystem/utils.go deleted file mode 100644 index d4d48e89b381..000000000000 --- a/sdk/storage/azdatalake/filesystem/utils.go +++ /dev/null @@ -1,23 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -package filesystem - -import ( - "net/url" - "strings" -) - -// escapeSplitPaths is utility function to escape the individual strings by eliminating "/" in the path -func escapeSplitPaths(filePath string) string { - names := strings.Split(filePath, "/") - path := make([]string, len(names)) - for i, name := range names { - path[i] = url.PathEscape(name) - } - escapedPathUrl := strings.Join(path, "/") - return escapedPathUrl -} diff --git a/sdk/storage/azdatalake/internal/shared/shared.go b/sdk/storage/azdatalake/internal/shared/shared.go index d26008a79adb..9c964ee7ae56 100644 --- a/sdk/storage/azdatalake/internal/shared/shared.go +++ b/sdk/storage/azdatalake/internal/shared/shared.go @@ -240,3 +240,14 @@ func IsIPEndpointStyle(host string) bool { } return net.ParseIP(host) != nil } + +// EscapeSplitPaths is utility function to escape the individual strings by eliminating "/" in the path +func EscapeSplitPaths(filePath string) string { + names := strings.Split(filePath, "/") + path := make([]string, len(names)) + for i, name := range names { + path[i] = url.PathEscape(name) + } + escapedPathUrl := strings.Join(path, "/") + return escapedPathUrl +}