@azure/storage-file-share
Version:
Microsoft Azure Storage SDK for JavaScript - File
1,111 lines • 147 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { isTokenCredential } from "@azure/core-auth";
import { isNodeLike } from "@azure/core-util";
import { isPipelineLike, newPipeline } from "./Pipeline.js";
import { DEFAULT_MAX_DOWNLOAD_RETRY_REQUESTS, DEFAULT_HIGH_LEVEL_CONCURRENCY, FILE_MAX_SIZE_BYTES, FILE_RANGE_MAX_SIZE_BYTES, URLConstants, } from "./utils/constants.js";
import { appendToURLPath, setURLParameter, truncatedISO8061Date, extractConnectionStringParts, getShareNameAndPathFromUrl, appendToURLQuery, httpAuthorizationToString, setURLPath, setURLQueries, EscapePath, ConvertInternalResponseOfListFiles, ConvertInternalResponseOfListHandles, assertResponse, removeEmptyString, asSharePermission, parseOctalFileMode, toOctalFileMode, } from "./utils/utils.common.js";
import { Credential } from "@azure/storage-common";
import { StorageSharedKeyCredential } from "@azure/storage-common";
import { AnonymousCredential } from "@azure/storage-common";
import { tracingClient } from "./utils/tracing.js";
import { StorageClient } from "./StorageClient.js";
import { FileDownloadResponse } from "./FileDownloadResponse.js";
import { rangeToString } from "./Range.js";
import { fileAttributesToString, fileCreationTimeToString, fileLastWriteTimeToString, validateAndSetDefaultsForFileAndDirectoryCreateCommonOptions, validateAndSetDefaultsForFileAndDirectorySetPropertiesCommonOptions, toShareProtocolsString, toShareProtocols, fileChangeTimeToString, } from "./models.js";
import { Batch } from "./utils/Batch.js";
import { BufferScheduler } from "./utils/BufferScheduler.js";
import { fsStat, fsCreateReadStream, readStreamToLocalFile, streamToBuffer, } from "./utils/utils.js";
import { randomUUID } from "@azure/core-util";
import { generateFileSASQueryParameters, generateFileSASQueryParametersInternal, } from "./FileSASSignatureValues.js";
/**
* A ShareClient represents a URL to the Azure Storage share allowing you to manipulate its directories and files.
*/
export class ShareClient extends StorageClient {
/**
* Share operation context provided by protocol layer.
*/
context;
_name;
shareClientConfig;
/**
* The name of the share
*/
get name() {
return this._name;
}
constructor(urlOrConnectionString, credentialOrPipelineOrShareName,
// Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.
options) {
let pipeline;
let url;
if (isPipelineLike(credentialOrPipelineOrShareName)) {
// (url: string, pipeline: Pipeline)
url = urlOrConnectionString;
pipeline = credentialOrPipelineOrShareName;
}
else if (credentialOrPipelineOrShareName instanceof Credential ||
isTokenCredential(credentialOrPipelineOrShareName)) {
// (url: string, credential?: Credential, options?: ShareClientOptions)
url = urlOrConnectionString;
pipeline = newPipeline(credentialOrPipelineOrShareName, options);
}
else if (!credentialOrPipelineOrShareName &&
typeof credentialOrPipelineOrShareName !== "string") {
// (url: string, credential?: Credential, options?: ShareClientOptions)
// The second parameter is undefined. Use anonymous credential.
url = urlOrConnectionString;
pipeline = newPipeline(new AnonymousCredential(), options);
}
else if (credentialOrPipelineOrShareName &&
typeof credentialOrPipelineOrShareName === "string") {
// (connectionString: string, name: string, options?: ShareClientOptions)
const extractedCreds = extractConnectionStringParts(urlOrConnectionString);
const name = credentialOrPipelineOrShareName;
if (extractedCreds.kind === "AccountConnString") {
if (isNodeLike) {
const sharedKeyCredential = new StorageSharedKeyCredential(extractedCreds.accountName, extractedCreds.accountKey);
url = appendToURLPath(extractedCreds.url, name);
pipeline = newPipeline(sharedKeyCredential, options);
}
else {
throw new Error("Account connection string is only supported in Node.js environment");
}
}
else if (extractedCreds.kind === "SASConnString") {
url = appendToURLPath(extractedCreds.url, name) + "?" + extractedCreds.accountSas;
pipeline = newPipeline(new AnonymousCredential(), options);
}
else {
throw new Error("Connection string must be either an Account connection string or a SAS connection string");
}
}
else {
throw new Error("Expecting non-empty strings for name parameter");
}
super(url, pipeline);
this._name = getShareNameAndPathFromUrl(this.url).shareName;
this.shareClientConfig = options;
this.context = this.storageClientContext.share;
}
/**
* Creates a new ShareClient object identical to the source but with the specified snapshot timestamp.
* Provide "" will remove the snapshot and return a URL to the base share.
*
* @param snapshot - The snapshot timestamp.
* @returns A new ShareClient object identical to the source but with the specified snapshot timestamp
*/
withSnapshot(snapshot) {
return new ShareClient(setURLParameter(this.url, URLConstants.Parameters.SHARE_SNAPSHOT, snapshot.length === 0 ? undefined : snapshot), this.pipeline, this.shareClientConfig);
}
/**
* Creates a new share under the specified account. If the share with
* the same name already exists, the operation fails.
* @see https://learn.microsoft.com/rest/api/storageservices/create-share
*
* @param options - Options to Share Create operation.
* @returns Response data for the Share Create operation.
*/
async create(options = {}) {
return tracingClient.withSpan("ShareClient-create", options, async (updatedOptions) => {
return assertResponse(await this.context.create({
...updatedOptions,
...this.shareClientConfig,
enabledProtocols: toShareProtocolsString(updatedOptions.protocols),
}));
});
}
/**
* Creates a new share under the specified account. If the share with
* the same name already exists, it is not changed.
* @see https://learn.microsoft.com/rest/api/storageservices/create-share
*
* @param options -
*/
async createIfNotExists(options = {}) {
return tracingClient.withSpan("ShareClient-createIfNotExists", options, async (updatedOptions) => {
try {
const res = await this.create(updatedOptions);
return {
succeeded: true,
...res,
};
}
catch (e) {
if (e.details?.errorCode === "ShareAlreadyExists") {
return {
succeeded: false,
...e.response?.parsedHeaders,
_response: e.response,
};
}
throw e;
}
});
}
/**
* Creates a {@link ShareDirectoryClient} object.
*
* @param directoryName - A directory name
* @returns The ShareDirectoryClient object for the given directory name.
*/
// Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.
/* eslint-disable-next-line @azure/azure-sdk/ts-naming-subclients */
getDirectoryClient(directoryName) {
return new ShareDirectoryClient(appendToURLPath(this.url, EscapePath(directoryName)), this.pipeline, this.shareClientConfig);
}
/**
* Gets the directory client for the root directory of this share.
* Note that the root directory always exists and cannot be deleted.
*
* @readonly A new ShareDirectoryClient object for the root directory.
*/
// Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.
/* eslint-disable-next-line @azure/azure-sdk/ts-naming-subclients */
get rootDirectoryClient() {
return this.getDirectoryClient("");
}
/**
* Creates a new subdirectory under this share.
* @see https://learn.microsoft.com/rest/api/storageservices/create-directory
*
* @param directoryName -
* @param options - Options to Directory Create operation.
* @returns Directory creation response data and the corresponding directory client.
*/
async createDirectory(directoryName, options = {}) {
return tracingClient.withSpan("ShareClient-createDirectory", options, async (updatedOptions) => {
const directoryClient = this.getDirectoryClient(directoryName);
const directoryCreateResponse = await directoryClient.create(updatedOptions);
return {
directoryClient,
directoryCreateResponse,
};
});
}
/**
* Removes the specified empty sub directory under this share.
* Note that the directory must be empty before it can be deleted.
* @see https://learn.microsoft.com/rest/api/storageservices/delete-directory
*
* @param directoryName -
* @param options - Options to Directory Delete operation.
* @returns Directory deletion response data.
*/
async deleteDirectory(directoryName, options = {}) {
return tracingClient.withSpan("ShareClient-deleteDirectory", options, async (updatedOptions) => {
const directoryClient = this.getDirectoryClient(directoryName);
return directoryClient.delete(updatedOptions);
});
}
/**
* Creates a new file or replaces a file under the root directory of this share.
* Note it only initializes the file with no content.
* @see https://learn.microsoft.com/rest/api/storageservices/create-file
*
* @param fileName -
* @param size - Specifies the maximum size in bytes for the file, up to 4 TB.
* @param options - Options to File Create operation.
* @returns File creation response data and the corresponding file client.
*/
async createFile(fileName, size, options = {}) {
return tracingClient.withSpan("ShareClient-createFile", options, async (updatedOptions) => {
const directoryClient = this.rootDirectoryClient;
const fileClient = directoryClient.getFileClient(fileName);
const fileCreateResponse = await fileClient.create(size, updatedOptions);
return {
fileClient,
fileCreateResponse,
};
});
}
/**
* Removes a file under the root directory of this share from the storage account.
* When a file is successfully deleted, it is immediately removed from the storage
* account's index and is no longer accessible to clients. The file's data is later
* removed from the service during garbage collection.
*
* Delete File will fail with status code 409 (Conflict) and error code `SharingViolation`
* if the file is open on an SMB client.
*
* Delete File is not supported on a share snapshot, which is a read-only copy of
* a share. An attempt to perform this operation on a share snapshot will fail with 400
* (`InvalidQueryParameterValue`)
*
* @see https://learn.microsoft.com/rest/api/storageservices/delete-file2
*
* @param directoryName -
* @param fileName -
* @param options - Options to File Delete operation.
* @returns Promise<FileDeleteResponse> File Delete response data.
*/
async deleteFile(fileName, options = {}) {
return tracingClient.withSpan("ShareClient-deleteFile", options, async (updatedOptions) => {
const directoryClient = this.rootDirectoryClient;
const fileClient = directoryClient.getFileClient(fileName);
return fileClient.delete(updatedOptions);
});
}
/**
* Returns true if the Azrue share resource represented by this client exists; false otherwise.
*
* NOTE: use this function with care since an existing share might be deleted by other clients or
* applications. Vice versa new shares might be added by other clients or applications after this
* function completes.
*
* @param options - options to Exists operation.
*/
async exists(options = {}) {
return tracingClient.withSpan("ShareClient-exists", options, async (updatedOptions) => {
try {
await this.getProperties(updatedOptions);
return true;
}
catch (e) {
if (e.statusCode === 404) {
return false;
}
throw e;
}
});
}
/**
* Returns all user-defined metadata and system properties for the specified
* share.
* @see https://learn.microsoft.com/rest/api/storageservices/get-share-properties
*
* WARNING: The `metadata` object returned in the response will have its keys in lowercase, even if
* they originally contained uppercase characters. This differs from the metadata keys returned by
* the `listShares` method of {@link ShareServiceClient} using the `includeMetadata` option, which
* will retain their original casing.
*
* @returns Response data for the Share Get Properties operation.
*/
async getProperties(options = {}) {
return tracingClient.withSpan("ShareClient-getProperties", options, async (updatedOptions) => {
const res = assertResponse(await this.context.getProperties(updatedOptions));
return {
...res,
...this.shareClientConfig,
protocols: toShareProtocols(res.enabledProtocols),
};
});
}
/**
* Marks the specified share for deletion. The share and any directories or files
* contained within it are later deleted during garbage collection.
* @see https://learn.microsoft.com/rest/api/storageservices/delete-share
*
* @param options - Options to Share Delete operation.
* @returns Response data for the Share Delete operation.
*/
async delete(options = {}) {
return tracingClient.withSpan("ShareClient-delete", options, async (updatedOptions) => {
return assertResponse(await this.context.delete({
...updatedOptions,
...this.shareClientConfig,
}));
});
}
/**
* Marks the specified share for deletion if it exists. The share and any directories or files
* contained within it are later deleted during garbage collection.
* @see https://learn.microsoft.com/rest/api/storageservices/delete-share
*
* @param options -
*/
async deleteIfExists(options = {}) {
return tracingClient.withSpan("ShareClient-deleteIfExists", options, async (updatedOptions) => {
try {
const res = await this.delete(updatedOptions);
return {
succeeded: true,
...res,
};
}
catch (e) {
if (e.details?.errorCode === "ShareNotFound" ||
e.details?.errorCode === "ShareSnapshotNotFound") {
return {
succeeded: false,
...e.response?.parsedHeaders,
_response: e.response,
};
}
throw e;
}
});
}
/**
* Sets one or more user-defined name-value pairs for the specified share.
*
* If no option provided, or no metadata defined in the option parameter, the share
* metadata will be removed.
* @see https://learn.microsoft.com/rest/api/storageservices/set-share-metadata
*
* @param metadata - If no metadata provided, all existing directory metadata will be removed.
* @param option - Options to Share Set Metadata operation.
* @returns Response data for the Share Set Metadata operation.
*/
async setMetadata(metadata, options = {}) {
return tracingClient.withSpan("ShareClient-setMetadata", options, async (updatedOptions) => {
return assertResponse(await this.context.setMetadata({
...updatedOptions,
...this.shareClientConfig,
metadata,
}));
});
}
/**
* Gets the permissions for the specified share. The permissions indicate
* whether share data may be accessed publicly.
*
* WARNING: JavaScript Date will potential lost precision when parsing start and expiry string.
* For example, new Date("2018-12-31T03:44:23.8827891Z").toISOString() will get "2018-12-31T03:44:23.882Z".
*
* @see https://learn.microsoft.com/rest/api/storageservices/get-share-acl
*
* @param option - Options to Share Get Access Policy operation.
* @returns Response data for the Share Get Access Policy operation.
*/
async getAccessPolicy(options = {}) {
return tracingClient.withSpan("ShareClient-getAccessPolicy", options, async (updatedOptions) => {
const response = assertResponse(await this.context.getAccessPolicy({
...updatedOptions,
...this.shareClientConfig,
}));
const res = {
_response: response._response,
date: response.date,
etag: response.etag,
lastModified: response.lastModified,
requestId: response.requestId,
signedIdentifiers: [],
version: response.version,
};
for (const identifier of response) {
let accessPolicy = undefined;
if (identifier.accessPolicy) {
accessPolicy = {
permissions: identifier.accessPolicy.permissions,
};
if (identifier.accessPolicy.expiresOn) {
accessPolicy.expiresOn = new Date(identifier.accessPolicy.expiresOn);
}
if (identifier.accessPolicy.startsOn) {
accessPolicy.startsOn = new Date(identifier.accessPolicy.startsOn);
}
}
res.signedIdentifiers.push({
accessPolicy,
id: identifier.id,
});
}
return res;
});
}
/**
* Sets the permissions for the specified share. The permissions indicate
* whether directories or files in a share may be accessed publicly.
*
* When you set permissions for a share, the existing permissions are replaced.
* If no shareAcl provided, the existing share ACL will be
* removed.
*
* When you establish a stored access policy on a share, it may take up to 30 seconds to take effect.
* During this interval, a shared access signature that is associated with the stored access policy will
* fail with status code 403 (Forbidden), until the access policy becomes active.
* @see https://learn.microsoft.com/rest/api/storageservices/set-share-acl
*
* @param shareAcl - Array of signed identifiers, each having a unique Id and details of access policy.
* @param option - Options to Share Set Access Policy operation.
* @returns Response data for the Share Set Access Policy operation.
*/
async setAccessPolicy(shareAcl, options = {}) {
return tracingClient.withSpan("ShareClient-setAccessPolicy", options, async (updatedOptions) => {
const acl = [];
for (const identifier of shareAcl || []) {
acl.push({
accessPolicy: {
expiresOn: identifier.accessPolicy?.expiresOn
? truncatedISO8061Date(identifier.accessPolicy.expiresOn)
: undefined,
permissions: identifier.accessPolicy?.permissions,
startsOn: identifier.accessPolicy?.startsOn
? truncatedISO8061Date(identifier.accessPolicy.startsOn)
: undefined,
},
id: identifier.id,
});
}
return assertResponse(await this.context.setAccessPolicy({
...updatedOptions,
...this.shareClientConfig,
shareAcl: acl,
}));
});
}
/**
* Creates a read-only snapshot of a share.
*
* @param options - Options to Share Create Snapshot operation.
* @returns Response data for the Share Create Snapshot operation.
*/
async createSnapshot(options = {}) {
return tracingClient.withSpan("ShareClient-createSnapshot", options, async (updatedOptions) => {
return assertResponse(await this.context.createSnapshot({
...updatedOptions,
...this.shareClientConfig,
}));
});
}
/**
* Sets quota for the specified share.
*
* @deprecated Use {@link ShareClient.setProperties} instead.
*
* @param quotaInGB - Specifies the maximum size of the share in gigabytes
* @param option - Options to Share Set Quota operation.
* @returns Response data for the Share Get Quota operation.
*/
async setQuota(quotaInGB, options = {}) {
return tracingClient.withSpan("ShareClient-setQuota", options, async (updatedOptions) => {
return assertResponse(await this.context.setProperties({
...updatedOptions,
...this.shareClientConfig,
quota: quotaInGB,
}));
});
}
/**
* Sets properties of the share.
*
* @param option - Options to Share Set Properties operation.
* @returns Response data for the Share Set Properties operation.
*/
async setProperties(options = {}) {
return tracingClient.withSpan("ShareClient-setProperties", options, async (updatedOptions) => {
return assertResponse(await this.context.setProperties({
...options,
...this.shareClientConfig,
quota: options.quotaInGB,
tracingOptions: updatedOptions.tracingOptions,
}));
});
}
/**
* Retrieves statistics related to the share.
*
* @param option - Options to Share Get Statistics operation.
* @returns Response data for the Share Get Statistics operation.
*/
async getStatistics(options = {}) {
return tracingClient.withSpan("ShareClient-getStatistics", options, async (updatedOptions) => {
const response = assertResponse(await this.context.getStatistics({
...updatedOptions,
...this.shareClientConfig,
}));
const GBBytes = 1024 * 1024 * 1024;
return { ...response, shareUsage: Math.ceil(response.shareUsageBytes / GBBytes) };
});
}
/**
* Creates a file permission (a security descriptor) at the share level.
* The created security descriptor can be used for the files/directories in the share.
* @see https://learn.microsoft.com/rest/api/storageservices/create-permission
*
* @param options - Options to Share Create Permission operation.
* @param filePermission - File permission described in the SDDL
*/
async createPermission(filePermission, options = {}) {
return tracingClient.withSpan("ShareClient-createPermission", options, async (updatedOptions) => {
return assertResponse(await this.context.createPermission(asSharePermission(filePermission), {
...updatedOptions,
...this.shareClientConfig,
}));
});
}
/**
* Gets the Security Descriptor Definition Language (SDDL) for a given file permission key
* which indicates a security descriptor.
* @see https://learn.microsoft.com/rest/api/storageservices/get-permission
*
* @param options - Options to Share Create Permission operation.
* @param filePermissionKey - File permission key which indicates the security descriptor of the permission.
*/
async getPermission(filePermissionKey, options = {}) {
return tracingClient.withSpan("ShareClient-getPermission", options, async (updatedOptions) => {
return assertResponse(await this.context.getPermission(filePermissionKey, {
...updatedOptions,
...this.shareClientConfig,
}));
});
}
/**
* Get a {@link ShareLeaseClient} that manages leases on the file.
*
* @param proposeLeaseId - Initial proposed lease Id.
* @returns A new ShareLeaseClient object for managing leases on the file.
*/
getShareLeaseClient(proposeLeaseId) {
return new ShareLeaseClient(this, proposeLeaseId);
}
/**
* Only available for ShareClient constructed with a shared key credential.
*
* Generates a Service Shared Access Signature (SAS) URI based on the client properties
* and parameters passed in. The SAS is signed by the shared key credential of the client.
*
* @see https://learn.microsoft.com/rest/api/storageservices/constructing-a-service-sas
*
* @param options - Optional parameters.
* @returns The SAS URI consisting of the URI to the resource represented by this client, followed by the generated SAS token.
*/
generateSasUrl(options) {
if (!(this.credential instanceof StorageSharedKeyCredential)) {
throw RangeError("Can only generate the SAS when the client is initialized with a shared key credential");
}
const sas = generateFileSASQueryParameters({
shareName: this.name,
...options,
}, this.credential).toString();
return appendToURLQuery(this.url, sas);
}
/**
* Only available for ShareClient constructed with a shared key credential.
*
* Generates string to sign for a Service Shared Access Signature (SAS) URI based on the client properties
* and parameters passed in. The SAS is signed by the shared key credential of the client.
*
* @see https://learn.microsoft.com/rest/api/storageservices/constructing-a-service-sas
*
* @param options - Optional parameters.
* @returns The SAS URI consisting of the URI to the resource represented by this client, followed by the generated SAS token.
*/
/* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
generateSasStringToSign(options) {
if (!(this.credential instanceof StorageSharedKeyCredential)) {
throw RangeError("Can only generate the SAS when the client is initialized with a shared key credential");
}
return generateFileSASQueryParametersInternal({
shareName: this.name,
...options,
}, this.credential).stringToSign;
}
/**
*
* Generates a Service Shared Access Signature (SAS) URI based on the client properties
* and parameters passed in. The SAS is signed by the user delegation key credential input.
*
* @see https://learn.microsoft.com/rest/api/storageservices/constructing-a-service-sas
*
* @param options - Optional parameters.
* @param userDelegationKey - user delegation key used to sign the SAS URI
* @returns The SAS URI consisting of the URI to the resource represented by this client, followed by the generated SAS token.
*/
generateUserDelegationSasUrl(options, userDelegationKey) {
const sas = generateFileSASQueryParameters({
shareName: this.name,
...options,
}, userDelegationKey, this.accountName).toString();
return appendToURLQuery(this.url, sas);
}
/**
*
* Generates a Service Shared Access Signature (SAS) URI based on the client properties
* and parameters passed in. The SAS is signed by the user delegation key credential input.
*
* @see https://learn.microsoft.com/rest/api/storageservices/constructing-a-service-sas
*
* @param options - Optional parameters.
* @param userDelegationKey - user delegation key used to sign the SAS URI
* @returns The SAS URI consisting of the URI to the resource represented by this client, followed by the generated SAS token.
*/
generateUserDelegationStringToSign(options, userDelegationKey) {
return generateFileSASQueryParametersInternal({
shareName: this.name,
...options,
}, userDelegationKey, this.accountName).stringToSign;
}
}
/**
* A ShareDirectoryClient represents a URL to the Azure Storage directory allowing you to manipulate its files and directories.
*/
export class ShareDirectoryClient extends StorageClient {
/**
* context provided by protocol layer.
*/
context;
_shareName;
_path;
_name;
shareClientConfig;
/**
* The share name corresponding to this directory client
*/
get shareName() {
return this._shareName;
}
/**
* The full path of the directory
*/
get path() {
return this._path;
}
/**
* The name of the directory
*/
get name() {
return this._name;
}
constructor(url, credentialOrPipeline,
// Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.
/* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */
options = {}) {
let pipeline;
if (isPipelineLike(credentialOrPipeline)) {
pipeline = credentialOrPipeline;
}
else if (credentialOrPipeline instanceof Credential ||
isTokenCredential(credentialOrPipeline)) {
pipeline = newPipeline(credentialOrPipeline, options);
}
else {
// The second parameter is undefined. Use anonymous credential.
pipeline = newPipeline(new AnonymousCredential(), options);
}
super(url, pipeline);
({
baseName: this._name,
shareName: this._shareName,
path: this._path,
} = getShareNameAndPathFromUrl(this.url));
this.shareClientConfig = options;
this.context = this.storageClientContext.directory;
}
/**
* Creates a new directory under the specified share or parent directory.
* @see https://learn.microsoft.com/rest/api/storageservices/create-directory
*
* @param options - Options to Directory Create operation.
* @returns Response data for the Directory operation.
*/
async create(options = {}) {
if (!options.fileAttributes) {
options = validateAndSetDefaultsForFileAndDirectoryCreateCommonOptions(options);
}
return tracingClient.withSpan("ShareDirectoryClient-create", options, async (updatedOptions) => {
const rawResponse = await this.context.create({
...updatedOptions,
fileChangeOn: fileChangeTimeToString(updatedOptions.changeTime),
fileCreatedOn: fileCreationTimeToString(updatedOptions.creationTime),
fileLastWriteOn: fileLastWriteTimeToString(updatedOptions.lastWriteTime),
fileAttributes: updatedOptions.fileAttributes
? fileAttributesToString(updatedOptions.fileAttributes)
: undefined,
owner: updatedOptions.posixProperties?.owner,
group: updatedOptions.posixProperties?.group,
fileMode: toOctalFileMode(updatedOptions.posixProperties?.fileMode),
...this.shareClientConfig,
});
const wrappedRes = {
...rawResponse,
_response: rawResponse._response, // _response is made non-enumerable,
posixProperties: {
fileMode: parseOctalFileMode(rawResponse.fileMode),
fileType: rawResponse.nfsFileType,
owner: rawResponse.owner,
group: rawResponse.group,
},
};
return assertResponse(wrappedRes);
});
}
/**
* Creates a new directory under the specified share or parent directory if it does not already exists.
* If the directory already exists, it is not modified.
* @see https://learn.microsoft.com/rest/api/storageservices/create-directory
*
* @param options -
*/
async createIfNotExists(options = {}) {
return tracingClient.withSpan("ShareDirectoryClient-createIfNotExists", options, async (updatedOptions) => {
try {
const res = await this.create(updatedOptions);
return {
succeeded: true,
...res,
};
}
catch (e) {
if (e.details?.errorCode === "ResourceAlreadyExists") {
return {
succeeded: false,
...e.response?.parsedHeaders,
_response: e.response,
};
}
throw e;
}
});
}
/**
* Sets properties on the directory.
* @see https://learn.microsoft.com/rest/api/storageservices/set-directory-properties
*
* @param DirectoryProperties - Directory properties. If no values are provided,
* existing values will be preserved.
*/
async setProperties(properties = {}) {
properties = validateAndSetDefaultsForFileAndDirectorySetPropertiesCommonOptions(properties);
return tracingClient.withSpan("ShareDirectoryClient-setProperties", properties, async (updatedOptions) => {
const rawResponse = await this.context.setProperties({
...updatedOptions,
fileChangeOn: fileChangeTimeToString(updatedOptions.changeTime),
fileCreatedOn: fileCreationTimeToString(updatedOptions.creationTime),
fileLastWriteOn: fileLastWriteTimeToString(updatedOptions.lastWriteTime),
fileAttributes: updatedOptions.fileAttributes
? fileAttributesToString(updatedOptions.fileAttributes)
: undefined,
owner: updatedOptions.posixProperties?.owner,
group: updatedOptions.posixProperties?.group,
fileMode: toOctalFileMode(updatedOptions.posixProperties?.fileMode),
...this.shareClientConfig,
});
return assertResponse({
...rawResponse,
_response: rawResponse._response,
posixProperties: {
fileMode: parseOctalFileMode(rawResponse.fileMode),
owner: rawResponse.owner,
group: rawResponse.group,
},
});
});
}
/**
* Creates a ShareDirectoryClient object for a sub directory.
*
* @param subDirectoryName - A subdirectory name
* @returns The ShareDirectoryClient object for the given subdirectory name.
*
* Example usage:
*
* ```ts snippet:ReadmeSampleGetDirectoryClient
* import { StorageSharedKeyCredential, ShareServiceClient } from "@azure/storage-file-share";
*
* const account = "<account>";
* const accountKey = "<accountkey>";
*
* const credential = new StorageSharedKeyCredential(account, accountKey);
* const serviceClient = new ShareServiceClient(
* `https://${account}.file.core.windows.net`,
* credential,
* );
*
* const shareName = "<share name>";
* const directoryName = "<directory name>";
* const shareClient = serviceClient.getShareClient(shareName);
* const directoryClient = shareClient.getDirectoryClient(directoryName);
* await directoryClient.create();
* ```
*/
getDirectoryClient(subDirectoryName) {
return new ShareDirectoryClient(appendToURLPath(this.url, EscapePath(subDirectoryName)), this.pipeline, this.shareClientConfig);
}
/**
* Creates a new subdirectory under this directory.
* @see https://learn.microsoft.com/rest/api/storageservices/create-directory
*
* @param directoryName -
* @param options - Options to Directory Create operation.
* @returns Directory create response data and the corresponding DirectoryClient instance.
*/
async createSubdirectory(directoryName, options = {}) {
return tracingClient.withSpan("ShareDirectoryClient-createSubdirectory", options, async (updatedOptions) => {
const directoryClient = this.getDirectoryClient(directoryName);
const directoryCreateResponse = await directoryClient.create(updatedOptions);
return {
directoryClient,
directoryCreateResponse,
};
});
}
/**
* Removes the specified empty sub directory under this directory.
* Note that the directory must be empty before it can be deleted.
* @see https://learn.microsoft.com/rest/api/storageservices/delete-directory
*
* @param directoryName -
* @param options - Options to Directory Delete operation.
* @returns Directory deletion response data.
*/
async deleteSubdirectory(directoryName, options = {}) {
return tracingClient.withSpan("ShareDirectoryClient-deleteSubdirectory", options, async (updatedOptions) => {
const directoryClient = this.getDirectoryClient(directoryName);
return directoryClient.delete(updatedOptions);
});
}
/**
* Creates a new file or replaces a file under this directory. Note it only initializes the file with no content.
* @see https://learn.microsoft.com/rest/api/storageservices/create-file
*
* @param fileName -
* @param size - Specifies the maximum size in bytes for the file, up to 4 TB.
* @param options - Options to File Create operation.
* @returns File creation response data and the corresponding file client.
*/
async createFile(fileName, size, options = {}) {
return tracingClient.withSpan("ShareDirectoryClient-createFile", options, async (updatedOptions) => {
const fileClient = this.getFileClient(fileName);
const fileCreateResponse = await fileClient.create(size, updatedOptions);
return {
fileClient,
fileCreateResponse,
};
});
}
/**
* Removes the specified file under this directory from the storage account.
* When a file is successfully deleted, it is immediately removed from the storage
* account's index and is no longer accessible to clients. The file's data is later
* removed from the service during garbage collection.
*
* Delete File will fail with status code 409 (Conflict) and error code SharingViolation
* if the file is open on an SMB client.
*
* Delete File is not supported on a share snapshot, which is a read-only copy of
* a share. An attempt to perform this operation on a share snapshot will fail with 400 (InvalidQueryParameterValue)
*
* @see https://learn.microsoft.com/rest/api/storageservices/delete-file2
*
* @param fileName - Name of the file to delete
* @param options - Options to File Delete operation.
* @returns File deletion response data.
*/
async deleteFile(fileName, options = {}) {
return tracingClient.withSpan("ShareDirectoryClient-deleteFile", options, async (updatedOptions) => {
const fileClient = this.getFileClient(fileName);
return fileClient.delete(updatedOptions);
});
}
/**
* Creates a {@link ShareFileClient} object.
*
* @param fileName - A file name.
* @returns A new ShareFileClient object for the given file name.
*
* Example usage:
*
* ```ts snippet:ReadmeSampleCreateFileAndUpload
* import { StorageSharedKeyCredential, ShareServiceClient } from "@azure/storage-file-share";
*
* const account = "<account>";
* const accountKey = "<accountkey>";
*
* const credential = new StorageSharedKeyCredential(account, accountKey);
* const serviceClient = new ShareServiceClient(
* `https://${account}.file.core.windows.net`,
* credential,
* );
*
* const shareName = "<share name>";
* const directoryName = "<directory name>";
* const directoryClient = serviceClient.getShareClient(shareName).getDirectoryClient(directoryName);
*
* const content = "Hello World!";
* const fileName = `newdirectory${+new Date()}`;
* const fileClient = directoryClient.getFileClient(fileName);
* await fileClient.create(content.length);
* console.log(`Create file ${fileName} successfully`);
*
* // Upload file range
* await fileClient.uploadRange(content, 0, content.length);
* console.log(`Upload file range "${content}" to ${fileName} successfully`);
* ```
*/
// Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.
/* eslint-disable-next-line @azure/azure-sdk/ts-naming-subclients */
getFileClient(fileName) {
return new ShareFileClient(appendToURLPath(this.url, EscapePath(fileName)), this.pipeline, this.shareClientConfig);
}
/**
* Returns true if the specified directory exists; false otherwise.
*
* NOTE: use this function with care since an existing directory might be deleted by other clients or
* applications. Vice versa new directories might be added by other clients or applications after this
* function completes.
*
* @param options - options to Exists operation.
*/
async exists(options = {}) {
return tracingClient.withSpan("ShareDirectoryClient-exists", options, async (updatedOptions) => {
try {
await this.getProperties({ ...updatedOptions, ...this.shareClientConfig });
return true;
}
catch (e) {
if (e.statusCode === 404) {
return false;
}
throw e;
}
});
}
/**
* Returns all system properties for the specified directory, and can also be used to check the
* existence of a directory. The data returned does not include the files in the directory or any
* subdirectories.
* @see https://learn.microsoft.com/rest/api/storageservices/get-directory-properties
*
* @param options - Options to Directory Get Properties operation.
* @returns Response data for the Directory Get Properties operation.
*/
async getProperties(options = {}) {
return tracingClient.withSpan("ShareDirectoryClient-getProperties", options, async (updatedOptions) => {
const rawResponse = await this.context.getProperties({
...updatedOptions,
...this.shareClientConfig,
});
return assertResponse({
...rawResponse,
_response: rawResponse._response,
posixProperties: {
fileMode: parseOctalFileMode(rawResponse.fileMode),
owner: rawResponse.owner,
group: rawResponse.group,
fileType: rawResponse.nfsFileType,
},
});
});
}
/**
* Removes the specified empty directory. Note that the directory must be empty before it can be
* deleted.
* @see https://learn.microsoft.com/rest/api/storageservices/delete-directory
*
* @param options - Options to Directory Delete operation.
* @returns Response data for the Directory Delete operation.
*/
async delete(options = {}) {
return tracingClient.withSpan("ShareDirectoryClient-delete", options, async (updatedOptions) => {
return assertResponse(await this.context.delete({ ...updatedOptions, ...this.shareClientConfig }));
});
}
/**
* Removes the specified empty directory if it exists. Note that the directory must be empty before it can be
* deleted.
* @see https://learn.microsoft.com/rest/api/storageservices/delete-directory
*
* @param options -
*/
async deleteIfExists(options = {}) {
return tracingClient.withSpan("ShareDirectoryClient-deleteIfExists", options, async (updatedOptions) => {
try {
const res = await this.delete(updatedOptions);
return {
succeeded: true,
...res,
};
}
catch (e) {
if (e.details?.errorCode === "ResourceNotFound" ||
e.details?.errorCode === "ParentNotFound") {
return {
succeeded: false,
...e.response?.parsedHeaders,
_response: e.response,
};
}
throw e;
}
});
}
/**
* Updates user defined metadata for the specified directory.
* @see https://learn.microsoft.com/rest/api/storageservices/set-directory-metadata
*
* @param metadata - If no metadata provided, all existing directory metadata will be removed
* @param options - Options to Directory Set Metadata operation.
* @returns Response data for the Directory Set Metadata operation.
*/
async setMetadata(metadata, options = {}) {
return tracingClient.withSpan("ShareDirectoryClient-setMetadata", options, async (updatedOptions) => {
return assertResponse(await this.context.setMetadata({
...updatedOptions,
metadata,
...this.shareClientConfig,
}));
});
}
/**
* Returns an AsyncIterableIterator for {@link DirectoryListFilesAndDirectoriesSegmentResponse} objects
*
* @param marker - A string value that identifies the portion of
* the list of files and directories to be returned with the next listing operation. The
* operation returns the ContinuationToken value within the response body if the
* listing operation did not return all files and directories remaining to be listed
* with the current page. The ContinuationToken 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.
* @param options - Options to list files and directories operation.
*/
async *iterateFilesAndDirectoriesSegments(marker, options = {}) {
if (options.prefix === "") {
options.prefix = undefined;
}
let listFilesAndDirectoriesResponse;
do {
listFilesAndDirectoriesResponse = await this.listFilesAndDirectoriesSegment(marker, options);
marker = listFilesAndDirectoriesResponse.continuationToken;
yield await listFilesAndDirectoriesResponse;
} while (marker);
}
/**
* Returns an AsyncIterableIterator for file and directory items
*
* @param options - Options to list files and directories operation.
*/
async *listFilesAndDirectoriesItems(options = {}) {
if (options.prefix === "") {
options.prefix = undefined;
}
let marker;
for await (const listFilesAndDirectoriesResponse of this.iterateFilesAndDirectoriesSegments(marker, options)) {
for (const file of listFilesAndDirectoriesResponse.segment.fileItems) {
yield { kind: "file", ...file };
}
for (const directory of listFilesAndDirectoriesResponse.segment.directoryItems) {
yield { kind: "directory", ...directory };
}
}
}
/**
* Returns an async iterable iterator to list all the files and directories
* under the specified account.
*
* .byPage() returns an async iterable iterator to list the files and directories in pages.
*
* Example using `for await` syntax:
*
* ```ts snippet:ReadmeSampleListFilesAndDirectories
* import { StorageSharedKeyCredential, ShareServiceClient } from "@azure/storage-file-share";
*
* const account = "<account>";
* const accountKey = "<accountkey>";
*
* const credential = new StorageSharedKeyCredential(account, accountKey);
* const serviceClient = new ShareServiceClient(
* `https://${account}.file.core.windows.net`,
* credential,
* );
*
* const shareName = "<share name>";
* const directoryName = "<directory name>";
* const directoryClient = serviceClient.getShareClient(shareName).getDirectoryClient(directoryName);
*
* let i = 1;
* for await (const item of directoryClient.listFilesAndDirectories()) {
* if (item.kind === "directory") {
* console.log(`${i} - directory\t: ${item.name}`);
* } else {