From 1ea8a457a765ee1db90fc6431029d6b3fec1df42 Mon Sep 17 00:00:00 2001 From: Gunjan Singh Date: Wed, 5 Aug 2026 19:46:58 +0530 Subject: [PATCH 1/4] Storage - STG105 NFS List V2 Files and Directories Restores the NFS List V2 Files and Directories feature (#49246), which was reverted from stg104 in #49770, rebased onto stg105base. Handwritten files match #49246 exactly. Generated code was produced by running autorest against the swagger link from Azure/azure-rest-api-specs#42720 already configured in the swagger README. The only handwritten deviations from #49246 are those forced by this base: - DirectoryListingDeserializationTests uses V2027_03_07; V2026_12_06 does not exist in ShareServiceVersion on stg105base. - Dropped the ArrayList import in the two ShareDirectory clients; it is unused here and fails checkstyle. - ModelHelper omits toShareFileRangeItems and its imports. That helper is STG103 paginated Get Range work, which is not on this base and is unrelated to this feature. Recordings are not included. assets.json stays at the stg105base tag until the feature is enabled in canary and the tests can be re-recorded. --- .../azure-storage-file-share/CHANGELOG.md | 9 + .../file/share/ShareDirectoryAsyncClient.java | 18 +- .../file/share/ShareDirectoryClient.java | 18 +- .../ShareFileItemConstructorProxy.java | 88 ++++++ .../models/BlockDeviceItem.java | 268 ++++++++++++++++++ .../implementation/models/CharDeviceItem.java | 268 ++++++++++++++++++ .../implementation/models/DirectoryItem.java | 31 ++ .../share/implementation/models/FifoItem.java | 205 ++++++++++++++ .../share/implementation/models/FileItem.java | 63 ++++ .../implementation/models/FileProperty.java | 93 ++++++ .../FilesAndDirectoriesListSegment.java | 177 ++++++++++++ .../InternalShareFileItemProperties.java | 49 ++++ .../models/ListFilesIncludeType.java | 22 +- .../implementation/models/SocketItem.java | 205 ++++++++++++++ .../implementation/models/SymLinkItem.java | 237 ++++++++++++++++ .../implementation/util/ModelHelper.java | 134 +++++++-- .../file/share/models/NfsFileType.java | 39 ++- .../file/share/models/ShareFileItem.java | 81 +++++- .../share/models/ShareFileItemProperties.java | 27 ++ .../ShareListFilesAndDirectoriesOptions.java | 84 ++++++ .../storage/file/share/DirectoryApiTests.java | 146 ++++++++++ .../file/share/DirectoryAsyncApiTests.java | 151 ++++++++++ .../DirectoryListingDeserializationTests.java | 169 +++++++++++ .../ListFilesAndDirectoriesResponse.xml | 121 ++++++++ .../swagger/README.md | 2 +- .../main/java/ShareStorageCustomization.java | 7 + 26 files changed, 2652 insertions(+), 60 deletions(-) create mode 100644 sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/accesshelpers/ShareFileItemConstructorProxy.java create mode 100644 sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/BlockDeviceItem.java create mode 100644 sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/CharDeviceItem.java create mode 100644 sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FifoItem.java create mode 100644 sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/SocketItem.java create mode 100644 sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/SymLinkItem.java create mode 100644 sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryListingDeserializationTests.java create mode 100644 sdk/storage/azure-storage-file-share/src/test/resources/testfiles/ListFilesAndDirectoriesResponse.xml diff --git a/sdk/storage/azure-storage-file-share/CHANGELOG.md b/sdk/storage/azure-storage-file-share/CHANGELOG.md index 0b959bbfa5cf..859e6254d38b 100644 --- a/sdk/storage/azure-storage-file-share/CHANGELOG.md +++ b/sdk/storage/azure-storage-file-share/CHANGELOG.md @@ -3,6 +3,15 @@ ## 12.32.0-beta.1 (Unreleased) ### Features Added +- Added support for NFS List Files and Directories V2. `ShareDirectoryClient.listFilesAndDirectories` now returns + symbolic links, block devices, character devices, FIFOs and sockets in addition to files and directories. +- Added `ShareFileItem.getLinkCount()`, `ShareFileItem.getFileType()`, `ShareFileItem.getLinkText()`, + `ShareFileItem.getDeviceMajor()` and `ShareFileItem.getDeviceMinor()`. +- Added `ShareFileItemProperties.getOwner()`, `ShareFileItemProperties.getGroup()` and + `ShareFileItemProperties.getFileMode()`. +- Added `NfsFileType.BLOCK_DEVICE`, `NfsFileType.CHARACTER_DEVICE`, `NfsFileType.SOCKET` and `NfsFileType.FIFO`. +- Added `ShareListFilesAndDirectoriesOptions.setIncludePermissions`, `setIncludeLinkCount`, `setIncludeNfsAttributes` + and `setIncludeAll`. ### Breaking Changes diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryAsyncClient.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryAsyncClient.java index 575d1d9f9b91..da521421629a 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryAsyncClient.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryAsyncClient.java @@ -51,7 +51,6 @@ import reactor.core.publisher.Mono; import java.time.Duration; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -980,22 +979,7 @@ PagedFlux listFilesAndDirectoriesWithOptionalTimeout(ShareListFil final ShareListFilesAndDirectoriesOptions modifiedOptions = options == null ? new ShareListFilesAndDirectoriesOptions() : options; - List includeTypes = new ArrayList<>(); - if (modifiedOptions.includeAttributes()) { - includeTypes.add(ListFilesIncludeType.ATTRIBUTES); - } - if (modifiedOptions.includeETag()) { - includeTypes.add(ListFilesIncludeType.ETAG); - } - if (modifiedOptions.includeTimestamps()) { - includeTypes.add(ListFilesIncludeType.TIMESTAMPS); - } - if (modifiedOptions.includePermissionKey()) { - includeTypes.add(ListFilesIncludeType.PERMISSION_KEY); - } - - // these options must be absent from request if empty or false - final List finalIncludeTypes = includeTypes.isEmpty() ? null : includeTypes; + final List finalIncludeTypes = ModelHelper.getListFilesIncludeTypes(modifiedOptions); BiFunction>> retriever = (marker, pageSize) -> StorageImplUtils diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryClient.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryClient.java index 32c7ceced009..cfa7b7383b81 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryClient.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryClient.java @@ -58,7 +58,6 @@ import com.azure.storage.file.share.sas.ShareServiceSasSignatureValues; import java.time.Duration; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -946,22 +945,7 @@ public PagedIterable listFilesAndDirectories(ShareListFilesAndDir final ShareListFilesAndDirectoriesOptions modifiedOptions = options == null ? new ShareListFilesAndDirectoriesOptions() : options; - List includeTypes = new ArrayList<>(); - if (modifiedOptions.includeAttributes()) { - includeTypes.add(ListFilesIncludeType.ATTRIBUTES); - } - if (modifiedOptions.includeETag()) { - includeTypes.add(ListFilesIncludeType.ETAG); - } - if (modifiedOptions.includeTimestamps()) { - includeTypes.add(ListFilesIncludeType.TIMESTAMPS); - } - if (modifiedOptions.includePermissionKey()) { - includeTypes.add(ListFilesIncludeType.PERMISSION_KEY); - } - - // these options must be absent from request if empty or false - final List finalIncludeTypes = includeTypes.isEmpty() ? null : includeTypes; + final List finalIncludeTypes = ModelHelper.getListFilesIncludeTypes(modifiedOptions); BiFunction> retriever = (marker, pageSize) -> { Callable> operation diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/accesshelpers/ShareFileItemConstructorProxy.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/accesshelpers/ShareFileItemConstructorProxy.java new file mode 100644 index 000000000000..102cfaa712c6 --- /dev/null +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/accesshelpers/ShareFileItemConstructorProxy.java @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.share.implementation.accesshelpers; + +import com.azure.storage.file.share.models.NfsFileType; +import com.azure.storage.file.share.models.NtfsFileAttributes; +import com.azure.storage.file.share.models.ShareFileItem; +import com.azure.storage.file.share.models.ShareFileItemProperties; + +import java.util.EnumSet; + +/** + * Helper class to access private values of {@link ShareFileItem} across package boundaries. + */ +public final class ShareFileItemConstructorProxy { + private static ShareFileItemConstructorAccessor accessor; + + private ShareFileItemConstructorProxy() { + } + + /** + * Type defining the methods to create a {@link ShareFileItem} instance with non-public properties. + */ + public interface ShareFileItemConstructorAccessor { + /** + * Creates a new instance of {@link ShareFileItem}. + * + * @param name Name of the file or the directory. + * @param isDirectory A boolean set to true if the reference is a directory, false if the reference is a file. + * @param id ID of the file or directory. + * @param properties Properties of the file or directory. + * @param fileAttributes NTFS attributes of the file or directory. + * @param permissionKey Permission key of the file or directory. + * @param fileSize Size of a file. + * @param linkCount The number of hard links to the file or directory. + * @param fileType The type of the file or directory. + * @param linkText The target path of the symbolic link. + * @param deviceMajor The major device number. + * @param deviceMinor The minor device number. + * @return A new instance of {@link ShareFileItem}. + */ + ShareFileItem create(String name, boolean isDirectory, String id, ShareFileItemProperties properties, + EnumSet fileAttributes, String permissionKey, Long fileSize, Long linkCount, + NfsFileType fileType, String linkText, Long deviceMajor, Long deviceMinor); + } + + /** + * The method called from {@link ShareFileItem} to set its accessor. + * + * @param accessor The accessor. + */ + public static void setAccessor(final ShareFileItemConstructorAccessor accessor) { + ShareFileItemConstructorProxy.accessor = accessor; + } + + /** + * Creates a new instance of {@link ShareFileItem}. + * + * @param name Name of the file or the directory. + * @param isDirectory A boolean set to true if the reference is a directory, false if the reference is a file. + * @param id ID of the file or directory. + * @param properties Properties of the file or directory. + * @param fileAttributes NTFS attributes of the file or directory. + * @param permissionKey Permission key of the file or directory. + * @param fileSize Size of a file. + * @param linkCount The number of hard links to the file or directory. + * @param fileType The type of the file or directory. + * @param linkText The target path of the symbolic link. + * @param deviceMajor The major device number. + * @param deviceMinor The minor device number. + * @return A new instance of {@link ShareFileItem}. + */ + public static ShareFileItem create(String name, boolean isDirectory, String id, ShareFileItemProperties properties, + EnumSet fileAttributes, String permissionKey, Long fileSize, Long linkCount, + NfsFileType fileType, String linkText, Long deviceMajor, Long deviceMinor) { + // This looks odd but is necessary, it is possible to engage the access helper before anywhere else in the + // application accesses ShareFileItem which triggers the accessor to be configured. So, if the accessor + // is null this effectively pokes the class to set up the accessor. + if (accessor == null) { + new ShareFileItem(null, false, null); + } + + assert accessor != null; + return accessor.create(name, isDirectory, id, properties, fileAttributes, permissionKey, fileSize, linkCount, + fileType, linkText, deviceMajor, deviceMinor); + } +} diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/BlockDeviceItem.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/BlockDeviceItem.java new file mode 100644 index 000000000000..3e9ae98f8d4a --- /dev/null +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/BlockDeviceItem.java @@ -0,0 +1,268 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.share.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.azure.core.annotation.Generated; +import com.azure.xml.XmlReader; +import com.azure.xml.XmlSerializable; +import com.azure.xml.XmlToken; +import com.azure.xml.XmlWriter; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; + +/** + * A listed block device item. + */ +@Fluent +public final class BlockDeviceItem implements XmlSerializable { + /* + * The Name property. + */ + @Generated + private StringEncoded name; + + /* + * The FileId property. + */ + @Generated + private String fileId; + + /* + * File properties. + */ + @Generated + private FileProperty properties; + + /* + * The LinkCount property. + */ + @Generated + private Long linkCount; + + /* + * The DeviceMajor property. + */ + @Generated + private Long deviceMajor; + + /* + * The DeviceMinor property. + */ + @Generated + private Long deviceMinor; + + /** + * Creates an instance of BlockDeviceItem class. + */ + @Generated + public BlockDeviceItem() { + } + + /** + * Get the name property: The Name property. + * + * @return the name value. + */ + @Generated + public StringEncoded getName() { + return this.name; + } + + /** + * Set the name property: The Name property. + * + * @param name the name value to set. + * @return the BlockDeviceItem object itself. + */ + @Generated + public BlockDeviceItem setName(StringEncoded name) { + this.name = name; + return this; + } + + /** + * Get the fileId property: The FileId property. + * + * @return the fileId value. + */ + @Generated + public String getFileId() { + return this.fileId; + } + + /** + * Set the fileId property: The FileId property. + * + * @param fileId the fileId value to set. + * @return the BlockDeviceItem object itself. + */ + @Generated + public BlockDeviceItem setFileId(String fileId) { + this.fileId = fileId; + return this; + } + + /** + * Get the properties property: File properties. + * + * @return the properties value. + */ + @Generated + public FileProperty getProperties() { + return this.properties; + } + + /** + * Set the properties property: File properties. + * + * @param properties the properties value to set. + * @return the BlockDeviceItem object itself. + */ + @Generated + public BlockDeviceItem setProperties(FileProperty properties) { + this.properties = properties; + return this; + } + + /** + * Get the linkCount property: The LinkCount property. + * + * @return the linkCount value. + */ + @Generated + public Long getLinkCount() { + return this.linkCount; + } + + /** + * Set the linkCount property: The LinkCount property. + * + * @param linkCount the linkCount value to set. + * @return the BlockDeviceItem object itself. + */ + @Generated + public BlockDeviceItem setLinkCount(Long linkCount) { + this.linkCount = linkCount; + return this; + } + + /** + * Get the deviceMajor property: The DeviceMajor property. + * + * @return the deviceMajor value. + */ + @Generated + public Long getDeviceMajor() { + return this.deviceMajor; + } + + /** + * Set the deviceMajor property: The DeviceMajor property. + * + * @param deviceMajor the deviceMajor value to set. + * @return the BlockDeviceItem object itself. + */ + @Generated + public BlockDeviceItem setDeviceMajor(Long deviceMajor) { + this.deviceMajor = deviceMajor; + return this; + } + + /** + * Get the deviceMinor property: The DeviceMinor property. + * + * @return the deviceMinor value. + */ + @Generated + public Long getDeviceMinor() { + return this.deviceMinor; + } + + /** + * Set the deviceMinor property: The DeviceMinor property. + * + * @param deviceMinor the deviceMinor value to set. + * @return the BlockDeviceItem object itself. + */ + @Generated + public BlockDeviceItem setDeviceMinor(Long deviceMinor) { + this.deviceMinor = deviceMinor; + return this; + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { + return toXml(xmlWriter, null); + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException { + rootElementName = rootElementName == null || rootElementName.isEmpty() ? "BlockDevice" : rootElementName; + xmlWriter.writeStartElement(rootElementName); + xmlWriter.writeXml(this.name, "Name"); + xmlWriter.writeStringElement("FileId", this.fileId); + xmlWriter.writeXml(this.properties, "Properties"); + xmlWriter.writeNumberElement("LinkCount", this.linkCount); + xmlWriter.writeNumberElement("DeviceMajor", this.deviceMajor); + xmlWriter.writeNumberElement("DeviceMinor", this.deviceMinor); + return xmlWriter.writeEndElement(); + } + + /** + * Reads an instance of BlockDeviceItem from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @return An instance of BlockDeviceItem if the XmlReader was pointing to an instance of it, or null if it was + * pointing to XML null. + * @throws XMLStreamException If an error occurs while reading the BlockDeviceItem. + */ + @Generated + public static BlockDeviceItem fromXml(XmlReader xmlReader) throws XMLStreamException { + return fromXml(xmlReader, null); + } + + /** + * Reads an instance of BlockDeviceItem from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @param rootElementName Optional root element name to override the default defined by the model. Used to support + * cases where the model can deserialize from different root element names. + * @return An instance of BlockDeviceItem if the XmlReader was pointing to an instance of it, or null if it was + * pointing to XML null. + * @throws XMLStreamException If an error occurs while reading the BlockDeviceItem. + */ + @Generated + public static BlockDeviceItem fromXml(XmlReader xmlReader, String rootElementName) throws XMLStreamException { + String finalRootElementName + = rootElementName == null || rootElementName.isEmpty() ? "BlockDevice" : rootElementName; + return xmlReader.readObject(finalRootElementName, reader -> { + BlockDeviceItem deserializedBlockDeviceItem = new BlockDeviceItem(); + while (reader.nextElement() != XmlToken.END_ELEMENT) { + QName elementName = reader.getElementName(); + + if ("Name".equals(elementName.getLocalPart())) { + deserializedBlockDeviceItem.name = StringEncoded.fromXml(reader, "Name"); + } else if ("FileId".equals(elementName.getLocalPart())) { + deserializedBlockDeviceItem.fileId = reader.getStringElement(); + } else if ("Properties".equals(elementName.getLocalPart())) { + deserializedBlockDeviceItem.properties = FileProperty.fromXml(reader, "Properties"); + } else if ("LinkCount".equals(elementName.getLocalPart())) { + deserializedBlockDeviceItem.linkCount = reader.getNullableElement(Long::parseLong); + } else if ("DeviceMajor".equals(elementName.getLocalPart())) { + deserializedBlockDeviceItem.deviceMajor = reader.getNullableElement(Long::parseLong); + } else if ("DeviceMinor".equals(elementName.getLocalPart())) { + deserializedBlockDeviceItem.deviceMinor = reader.getNullableElement(Long::parseLong); + } else { + reader.skipElement(); + } + } + + return deserializedBlockDeviceItem; + }); + } +} diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/CharDeviceItem.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/CharDeviceItem.java new file mode 100644 index 000000000000..a77395bcaa28 --- /dev/null +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/CharDeviceItem.java @@ -0,0 +1,268 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.share.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.azure.core.annotation.Generated; +import com.azure.xml.XmlReader; +import com.azure.xml.XmlSerializable; +import com.azure.xml.XmlToken; +import com.azure.xml.XmlWriter; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; + +/** + * A listed character device item. + */ +@Fluent +public final class CharDeviceItem implements XmlSerializable { + /* + * The Name property. + */ + @Generated + private StringEncoded name; + + /* + * The FileId property. + */ + @Generated + private String fileId; + + /* + * File properties. + */ + @Generated + private FileProperty properties; + + /* + * The LinkCount property. + */ + @Generated + private Long linkCount; + + /* + * The DeviceMajor property. + */ + @Generated + private Long deviceMajor; + + /* + * The DeviceMinor property. + */ + @Generated + private Long deviceMinor; + + /** + * Creates an instance of CharDeviceItem class. + */ + @Generated + public CharDeviceItem() { + } + + /** + * Get the name property: The Name property. + * + * @return the name value. + */ + @Generated + public StringEncoded getName() { + return this.name; + } + + /** + * Set the name property: The Name property. + * + * @param name the name value to set. + * @return the CharDeviceItem object itself. + */ + @Generated + public CharDeviceItem setName(StringEncoded name) { + this.name = name; + return this; + } + + /** + * Get the fileId property: The FileId property. + * + * @return the fileId value. + */ + @Generated + public String getFileId() { + return this.fileId; + } + + /** + * Set the fileId property: The FileId property. + * + * @param fileId the fileId value to set. + * @return the CharDeviceItem object itself. + */ + @Generated + public CharDeviceItem setFileId(String fileId) { + this.fileId = fileId; + return this; + } + + /** + * Get the properties property: File properties. + * + * @return the properties value. + */ + @Generated + public FileProperty getProperties() { + return this.properties; + } + + /** + * Set the properties property: File properties. + * + * @param properties the properties value to set. + * @return the CharDeviceItem object itself. + */ + @Generated + public CharDeviceItem setProperties(FileProperty properties) { + this.properties = properties; + return this; + } + + /** + * Get the linkCount property: The LinkCount property. + * + * @return the linkCount value. + */ + @Generated + public Long getLinkCount() { + return this.linkCount; + } + + /** + * Set the linkCount property: The LinkCount property. + * + * @param linkCount the linkCount value to set. + * @return the CharDeviceItem object itself. + */ + @Generated + public CharDeviceItem setLinkCount(Long linkCount) { + this.linkCount = linkCount; + return this; + } + + /** + * Get the deviceMajor property: The DeviceMajor property. + * + * @return the deviceMajor value. + */ + @Generated + public Long getDeviceMajor() { + return this.deviceMajor; + } + + /** + * Set the deviceMajor property: The DeviceMajor property. + * + * @param deviceMajor the deviceMajor value to set. + * @return the CharDeviceItem object itself. + */ + @Generated + public CharDeviceItem setDeviceMajor(Long deviceMajor) { + this.deviceMajor = deviceMajor; + return this; + } + + /** + * Get the deviceMinor property: The DeviceMinor property. + * + * @return the deviceMinor value. + */ + @Generated + public Long getDeviceMinor() { + return this.deviceMinor; + } + + /** + * Set the deviceMinor property: The DeviceMinor property. + * + * @param deviceMinor the deviceMinor value to set. + * @return the CharDeviceItem object itself. + */ + @Generated + public CharDeviceItem setDeviceMinor(Long deviceMinor) { + this.deviceMinor = deviceMinor; + return this; + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { + return toXml(xmlWriter, null); + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException { + rootElementName = rootElementName == null || rootElementName.isEmpty() ? "CharDevice" : rootElementName; + xmlWriter.writeStartElement(rootElementName); + xmlWriter.writeXml(this.name, "Name"); + xmlWriter.writeStringElement("FileId", this.fileId); + xmlWriter.writeXml(this.properties, "Properties"); + xmlWriter.writeNumberElement("LinkCount", this.linkCount); + xmlWriter.writeNumberElement("DeviceMajor", this.deviceMajor); + xmlWriter.writeNumberElement("DeviceMinor", this.deviceMinor); + return xmlWriter.writeEndElement(); + } + + /** + * Reads an instance of CharDeviceItem from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @return An instance of CharDeviceItem if the XmlReader was pointing to an instance of it, or null if it was + * pointing to XML null. + * @throws XMLStreamException If an error occurs while reading the CharDeviceItem. + */ + @Generated + public static CharDeviceItem fromXml(XmlReader xmlReader) throws XMLStreamException { + return fromXml(xmlReader, null); + } + + /** + * Reads an instance of CharDeviceItem from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @param rootElementName Optional root element name to override the default defined by the model. Used to support + * cases where the model can deserialize from different root element names. + * @return An instance of CharDeviceItem if the XmlReader was pointing to an instance of it, or null if it was + * pointing to XML null. + * @throws XMLStreamException If an error occurs while reading the CharDeviceItem. + */ + @Generated + public static CharDeviceItem fromXml(XmlReader xmlReader, String rootElementName) throws XMLStreamException { + String finalRootElementName + = rootElementName == null || rootElementName.isEmpty() ? "CharDevice" : rootElementName; + return xmlReader.readObject(finalRootElementName, reader -> { + CharDeviceItem deserializedCharDeviceItem = new CharDeviceItem(); + while (reader.nextElement() != XmlToken.END_ELEMENT) { + QName elementName = reader.getElementName(); + + if ("Name".equals(elementName.getLocalPart())) { + deserializedCharDeviceItem.name = StringEncoded.fromXml(reader, "Name"); + } else if ("FileId".equals(elementName.getLocalPart())) { + deserializedCharDeviceItem.fileId = reader.getStringElement(); + } else if ("Properties".equals(elementName.getLocalPart())) { + deserializedCharDeviceItem.properties = FileProperty.fromXml(reader, "Properties"); + } else if ("LinkCount".equals(elementName.getLocalPart())) { + deserializedCharDeviceItem.linkCount = reader.getNullableElement(Long::parseLong); + } else if ("DeviceMajor".equals(elementName.getLocalPart())) { + deserializedCharDeviceItem.deviceMajor = reader.getNullableElement(Long::parseLong); + } else if ("DeviceMinor".equals(elementName.getLocalPart())) { + deserializedCharDeviceItem.deviceMinor = reader.getNullableElement(Long::parseLong); + } else { + reader.skipElement(); + } + } + + return deserializedCharDeviceItem; + }); + } +} diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/DirectoryItem.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/DirectoryItem.java index 5b72c5ea86d4..d5f7362025eb 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/DirectoryItem.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/DirectoryItem.java @@ -48,6 +48,12 @@ public final class DirectoryItem implements XmlSerializable { @Generated private String permissionKey; + /* + * The LinkCount property. + */ + @Generated + private Long linkCount; + /** * Creates an instance of DirectoryItem class. */ @@ -165,6 +171,28 @@ public DirectoryItem setPermissionKey(String permissionKey) { return this; } + /** + * Get the linkCount property: The LinkCount property. + * + * @return the linkCount value. + */ + @Generated + public Long getLinkCount() { + return this.linkCount; + } + + /** + * Set the linkCount property: The LinkCount property. + * + * @param linkCount the linkCount value to set. + * @return the DirectoryItem object itself. + */ + @Generated + public DirectoryItem setLinkCount(Long linkCount) { + this.linkCount = linkCount; + return this; + } + @Generated @Override public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { @@ -181,6 +209,7 @@ public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLSt xmlWriter.writeXml(this.properties, "Properties"); xmlWriter.writeStringElement("Attributes", this.attributes); xmlWriter.writeStringElement("PermissionKey", this.permissionKey); + xmlWriter.writeNumberElement("LinkCount", this.linkCount); return xmlWriter.writeEndElement(); } @@ -226,6 +255,8 @@ public static DirectoryItem fromXml(XmlReader xmlReader, String rootElementName) deserializedDirectoryItem.attributes = reader.getStringElement(); } else if ("PermissionKey".equals(elementName.getLocalPart())) { deserializedDirectoryItem.permissionKey = reader.getStringElement(); + } else if ("LinkCount".equals(elementName.getLocalPart())) { + deserializedDirectoryItem.linkCount = reader.getNullableElement(Long::parseLong); } else { reader.skipElement(); } diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FifoItem.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FifoItem.java new file mode 100644 index 000000000000..e5c65219909e --- /dev/null +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FifoItem.java @@ -0,0 +1,205 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.share.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.azure.core.annotation.Generated; +import com.azure.xml.XmlReader; +import com.azure.xml.XmlSerializable; +import com.azure.xml.XmlToken; +import com.azure.xml.XmlWriter; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; + +/** + * A listed FIFO item. + */ +@Fluent +public final class FifoItem implements XmlSerializable { + /* + * The Name property. + */ + @Generated + private StringEncoded name; + + /* + * The FileId property. + */ + @Generated + private String fileId; + + /* + * File properties. + */ + @Generated + private FileProperty properties; + + /* + * The LinkCount property. + */ + @Generated + private Long linkCount; + + /** + * Creates an instance of FifoItem class. + */ + @Generated + public FifoItem() { + } + + /** + * Get the name property: The Name property. + * + * @return the name value. + */ + @Generated + public StringEncoded getName() { + return this.name; + } + + /** + * Set the name property: The Name property. + * + * @param name the name value to set. + * @return the FifoItem object itself. + */ + @Generated + public FifoItem setName(StringEncoded name) { + this.name = name; + return this; + } + + /** + * Get the fileId property: The FileId property. + * + * @return the fileId value. + */ + @Generated + public String getFileId() { + return this.fileId; + } + + /** + * Set the fileId property: The FileId property. + * + * @param fileId the fileId value to set. + * @return the FifoItem object itself. + */ + @Generated + public FifoItem setFileId(String fileId) { + this.fileId = fileId; + return this; + } + + /** + * Get the properties property: File properties. + * + * @return the properties value. + */ + @Generated + public FileProperty getProperties() { + return this.properties; + } + + /** + * Set the properties property: File properties. + * + * @param properties the properties value to set. + * @return the FifoItem object itself. + */ + @Generated + public FifoItem setProperties(FileProperty properties) { + this.properties = properties; + return this; + } + + /** + * Get the linkCount property: The LinkCount property. + * + * @return the linkCount value. + */ + @Generated + public Long getLinkCount() { + return this.linkCount; + } + + /** + * Set the linkCount property: The LinkCount property. + * + * @param linkCount the linkCount value to set. + * @return the FifoItem object itself. + */ + @Generated + public FifoItem setLinkCount(Long linkCount) { + this.linkCount = linkCount; + return this; + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { + return toXml(xmlWriter, null); + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException { + rootElementName = rootElementName == null || rootElementName.isEmpty() ? "Fifo" : rootElementName; + xmlWriter.writeStartElement(rootElementName); + xmlWriter.writeXml(this.name, "Name"); + xmlWriter.writeStringElement("FileId", this.fileId); + xmlWriter.writeXml(this.properties, "Properties"); + xmlWriter.writeNumberElement("LinkCount", this.linkCount); + return xmlWriter.writeEndElement(); + } + + /** + * Reads an instance of FifoItem from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @return An instance of FifoItem if the XmlReader was pointing to an instance of it, or null if it was pointing to + * XML null. + * @throws XMLStreamException If an error occurs while reading the FifoItem. + */ + @Generated + public static FifoItem fromXml(XmlReader xmlReader) throws XMLStreamException { + return fromXml(xmlReader, null); + } + + /** + * Reads an instance of FifoItem from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @param rootElementName Optional root element name to override the default defined by the model. Used to support + * cases where the model can deserialize from different root element names. + * @return An instance of FifoItem if the XmlReader was pointing to an instance of it, or null if it was pointing to + * XML null. + * @throws XMLStreamException If an error occurs while reading the FifoItem. + */ + @Generated + public static FifoItem fromXml(XmlReader xmlReader, String rootElementName) throws XMLStreamException { + String finalRootElementName = rootElementName == null || rootElementName.isEmpty() ? "Fifo" : rootElementName; + return xmlReader.readObject(finalRootElementName, reader -> { + FifoItem deserializedFifoItem = new FifoItem(); + while (reader.nextElement() != XmlToken.END_ELEMENT) { + QName elementName = reader.getElementName(); + + if ("Name".equals(elementName.getLocalPart())) { + deserializedFifoItem.name = StringEncoded.fromXml(reader, "Name"); + } else if ("FileId".equals(elementName.getLocalPart())) { + deserializedFifoItem.fileId = reader.getStringElement(); + } else if ("Properties".equals(elementName.getLocalPart())) { + deserializedFifoItem.properties = FileProperty.fromXml(reader, "Properties"); + } else if ("LinkCount".equals(elementName.getLocalPart())) { + deserializedFifoItem.linkCount = reader.getNullableElement(Long::parseLong); + } else { + reader.skipElement(); + } + } + + return deserializedFifoItem; + }); + } +} diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FileItem.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FileItem.java index c8338e96372d..7b81cef5460c 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FileItem.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FileItem.java @@ -6,6 +6,7 @@ import com.azure.core.annotation.Fluent; import com.azure.core.annotation.Generated; +import com.azure.storage.file.share.models.NfsFileType; import com.azure.xml.XmlReader; import com.azure.xml.XmlSerializable; import com.azure.xml.XmlToken; @@ -48,6 +49,18 @@ public final class FileItem implements XmlSerializable { @Generated private String permissionKey; + /* + * The LinkCount property. + */ + @Generated + private Long linkCount; + + /* + * Type of the file. + */ + @Generated + private NfsFileType fileType; + /** * Creates an instance of FileItem class. */ @@ -165,6 +178,50 @@ public FileItem setPermissionKey(String permissionKey) { return this; } + /** + * Get the linkCount property: The LinkCount property. + * + * @return the linkCount value. + */ + @Generated + public Long getLinkCount() { + return this.linkCount; + } + + /** + * Set the linkCount property: The LinkCount property. + * + * @param linkCount the linkCount value to set. + * @return the FileItem object itself. + */ + @Generated + public FileItem setLinkCount(Long linkCount) { + this.linkCount = linkCount; + return this; + } + + /** + * Get the fileType property: Type of the file. + * + * @return the fileType value. + */ + @Generated + public NfsFileType getFileType() { + return this.fileType; + } + + /** + * Set the fileType property: Type of the file. + * + * @param fileType the fileType value to set. + * @return the FileItem object itself. + */ + @Generated + public FileItem setFileType(NfsFileType fileType) { + this.fileType = fileType; + return this; + } + @Generated @Override public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { @@ -181,6 +238,8 @@ public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLSt xmlWriter.writeXml(this.properties, "Properties"); xmlWriter.writeStringElement("Attributes", this.attributes); xmlWriter.writeStringElement("PermissionKey", this.permissionKey); + xmlWriter.writeNumberElement("LinkCount", this.linkCount); + xmlWriter.writeStringElement("FileType", this.fileType == null ? null : this.fileType.toString()); return xmlWriter.writeEndElement(); } @@ -225,6 +284,10 @@ public static FileItem fromXml(XmlReader xmlReader, String rootElementName) thro deserializedFileItem.attributes = reader.getStringElement(); } else if ("PermissionKey".equals(elementName.getLocalPart())) { deserializedFileItem.permissionKey = reader.getStringElement(); + } else if ("LinkCount".equals(elementName.getLocalPart())) { + deserializedFileItem.linkCount = reader.getNullableElement(Long::parseLong); + } else if ("FileType".equals(elementName.getLocalPart())) { + deserializedFileItem.fileType = NfsFileType.fromString(reader.getStringElement()); } else { reader.skipElement(); } diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FileProperty.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FileProperty.java index 7bf07bbc0a4d..1ab9a4d68a6c 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FileProperty.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FileProperty.java @@ -67,6 +67,24 @@ public final class FileProperty implements XmlSerializable { @Generated private String etag; + /* + * The Uid property. + */ + @Generated + private String uid; + + /* + * The Gid property. + */ + @Generated + private String gid; + + /* + * The Mode property. + */ + @Generated + private String mode; + /** * Creates an instance of FileProperty class. */ @@ -239,6 +257,72 @@ public FileProperty setEtag(String etag) { return this; } + /** + * Get the uid property: The Uid property. + * + * @return the uid value. + */ + @Generated + public String getUid() { + return this.uid; + } + + /** + * Set the uid property: The Uid property. + * + * @param uid the uid value to set. + * @return the FileProperty object itself. + */ + @Generated + public FileProperty setUid(String uid) { + this.uid = uid; + return this; + } + + /** + * Get the gid property: The Gid property. + * + * @return the gid value. + */ + @Generated + public String getGid() { + return this.gid; + } + + /** + * Set the gid property: The Gid property. + * + * @param gid the gid value to set. + * @return the FileProperty object itself. + */ + @Generated + public FileProperty setGid(String gid) { + this.gid = gid; + return this; + } + + /** + * Get the mode property: The Mode property. + * + * @return the mode value. + */ + @Generated + public String getMode() { + return this.mode; + } + + /** + * Set the mode property: The Mode property. + * + * @param mode the mode value to set. + * @return the FileProperty object itself. + */ + @Generated + public FileProperty setMode(String mode) { + this.mode = mode; + return this; + } + @Generated @Override public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { @@ -261,6 +345,9 @@ public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLSt this.changeTime == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(this.changeTime)); xmlWriter.writeStringElement("Last-Modified", Objects.toString(this.lastModified, null)); xmlWriter.writeStringElement("Etag", this.etag); + xmlWriter.writeStringElement("Uid", this.uid); + xmlWriter.writeStringElement("Gid", this.gid); + xmlWriter.writeStringElement("Mode", this.mode); return xmlWriter.writeEndElement(); } @@ -314,6 +401,12 @@ public static FileProperty fromXml(XmlReader xmlReader, String rootElementName) deserializedFileProperty.lastModified = reader.getNullableElement(DateTimeRfc1123::new); } else if ("Etag".equals(elementName.getLocalPart())) { deserializedFileProperty.etag = reader.getStringElement(); + } else if ("Uid".equals(elementName.getLocalPart())) { + deserializedFileProperty.uid = reader.getStringElement(); + } else if ("Gid".equals(elementName.getLocalPart())) { + deserializedFileProperty.gid = reader.getStringElement(); + } else if ("Mode".equals(elementName.getLocalPart())) { + deserializedFileProperty.mode = reader.getStringElement(); } else { reader.skipElement(); } diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FilesAndDirectoriesListSegment.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FilesAndDirectoriesListSegment.java index db47d0b499b2..7c7d7ba082d9 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FilesAndDirectoriesListSegment.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/FilesAndDirectoriesListSegment.java @@ -32,6 +32,36 @@ public final class FilesAndDirectoriesListSegment implements XmlSerializable fileItems = new ArrayList<>(); + /* + * The SymLinkItems property. + */ + @Generated + private List symLinkItems = new ArrayList<>(); + + /* + * The BlockDeviceItems property. + */ + @Generated + private List blockDeviceItems = new ArrayList<>(); + + /* + * The CharDeviceItems property. + */ + @Generated + private List charDeviceItems = new ArrayList<>(); + + /* + * The FifoItems property. + */ + @Generated + private List fifoItems = new ArrayList<>(); + + /* + * The SocketItems property. + */ + @Generated + private List socketItems = new ArrayList<>(); + /** * Creates an instance of FilesAndDirectoriesListSegment class. */ @@ -83,6 +113,116 @@ public FilesAndDirectoriesListSegment setFileItems(List fileItems) { return this; } + /** + * Get the symLinkItems property: The SymLinkItems property. + * + * @return the symLinkItems value. + */ + @Generated + public List getSymLinkItems() { + return this.symLinkItems; + } + + /** + * Set the symLinkItems property: The SymLinkItems property. + * + * @param symLinkItems the symLinkItems value to set. + * @return the FilesAndDirectoriesListSegment object itself. + */ + @Generated + public FilesAndDirectoriesListSegment setSymLinkItems(List symLinkItems) { + this.symLinkItems = symLinkItems; + return this; + } + + /** + * Get the blockDeviceItems property: The BlockDeviceItems property. + * + * @return the blockDeviceItems value. + */ + @Generated + public List getBlockDeviceItems() { + return this.blockDeviceItems; + } + + /** + * Set the blockDeviceItems property: The BlockDeviceItems property. + * + * @param blockDeviceItems the blockDeviceItems value to set. + * @return the FilesAndDirectoriesListSegment object itself. + */ + @Generated + public FilesAndDirectoriesListSegment setBlockDeviceItems(List blockDeviceItems) { + this.blockDeviceItems = blockDeviceItems; + return this; + } + + /** + * Get the charDeviceItems property: The CharDeviceItems property. + * + * @return the charDeviceItems value. + */ + @Generated + public List getCharDeviceItems() { + return this.charDeviceItems; + } + + /** + * Set the charDeviceItems property: The CharDeviceItems property. + * + * @param charDeviceItems the charDeviceItems value to set. + * @return the FilesAndDirectoriesListSegment object itself. + */ + @Generated + public FilesAndDirectoriesListSegment setCharDeviceItems(List charDeviceItems) { + this.charDeviceItems = charDeviceItems; + return this; + } + + /** + * Get the fifoItems property: The FifoItems property. + * + * @return the fifoItems value. + */ + @Generated + public List getFifoItems() { + return this.fifoItems; + } + + /** + * Set the fifoItems property: The FifoItems property. + * + * @param fifoItems the fifoItems value to set. + * @return the FilesAndDirectoriesListSegment object itself. + */ + @Generated + public FilesAndDirectoriesListSegment setFifoItems(List fifoItems) { + this.fifoItems = fifoItems; + return this; + } + + /** + * Get the socketItems property: The SocketItems property. + * + * @return the socketItems value. + */ + @Generated + public List getSocketItems() { + return this.socketItems; + } + + /** + * Set the socketItems property: The SocketItems property. + * + * @param socketItems the socketItems value to set. + * @return the FilesAndDirectoriesListSegment object itself. + */ + @Generated + public FilesAndDirectoriesListSegment setSocketItems(List socketItems) { + this.socketItems = socketItems; + return this; + } + @Generated @Override public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { @@ -104,6 +244,31 @@ public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLSt xmlWriter.writeXml(element, "File"); } } + if (this.symLinkItems != null) { + for (SymLinkItem element : this.symLinkItems) { + xmlWriter.writeXml(element, "SymLink"); + } + } + if (this.blockDeviceItems != null) { + for (BlockDeviceItem element : this.blockDeviceItems) { + xmlWriter.writeXml(element, "BlockDevice"); + } + } + if (this.charDeviceItems != null) { + for (CharDeviceItem element : this.charDeviceItems) { + xmlWriter.writeXml(element, "CharDevice"); + } + } + if (this.fifoItems != null) { + for (FifoItem element : this.fifoItems) { + xmlWriter.writeXml(element, "Fifo"); + } + } + if (this.socketItems != null) { + for (SocketItem element : this.socketItems) { + xmlWriter.writeXml(element, "Socket"); + } + } return xmlWriter.writeEndElement(); } @@ -146,6 +311,18 @@ public static FilesAndDirectoriesListSegment fromXml(XmlReader xmlReader, String .add(DirectoryItem.fromXml(reader, "Directory")); } else if ("File".equals(elementName.getLocalPart())) { deserializedFilesAndDirectoriesListSegment.fileItems.add(FileItem.fromXml(reader, "File")); + } else if ("SymLink".equals(elementName.getLocalPart())) { + deserializedFilesAndDirectoriesListSegment.symLinkItems.add(SymLinkItem.fromXml(reader, "SymLink")); + } else if ("BlockDevice".equals(elementName.getLocalPart())) { + deserializedFilesAndDirectoriesListSegment.blockDeviceItems + .add(BlockDeviceItem.fromXml(reader, "BlockDevice")); + } else if ("CharDevice".equals(elementName.getLocalPart())) { + deserializedFilesAndDirectoriesListSegment.charDeviceItems + .add(CharDeviceItem.fromXml(reader, "CharDevice")); + } else if ("Fifo".equals(elementName.getLocalPart())) { + deserializedFilesAndDirectoriesListSegment.fifoItems.add(FifoItem.fromXml(reader, "Fifo")); + } else if ("Socket".equals(elementName.getLocalPart())) { + deserializedFilesAndDirectoriesListSegment.socketItems.add(SocketItem.fromXml(reader, "Socket")); } else { reader.skipElement(); } diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/InternalShareFileItemProperties.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/InternalShareFileItemProperties.java index bf3520e8f088..cd22b208c175 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/InternalShareFileItemProperties.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/InternalShareFileItemProperties.java @@ -14,6 +14,9 @@ public class InternalShareFileItemProperties implements ShareFileItemProperties private final OffsetDateTime changedOn; private final OffsetDateTime lastModified; private final String eTag; + private final String owner; + private final String group; + private final String fileMode; /** * Creates an instance of share item properties. @@ -27,12 +30,34 @@ public class InternalShareFileItemProperties implements ShareFileItemProperties */ public InternalShareFileItemProperties(OffsetDateTime createdOn, OffsetDateTime lastAccessedOn, OffsetDateTime lastWrittenOn, OffsetDateTime changedOn, OffsetDateTime lastModified, String eTag) { + this(createdOn, lastAccessedOn, lastWrittenOn, changedOn, lastModified, eTag, null, null, null); + } + + /** + * Creates an instance of share item properties. + * + * @param createdOn Datetime the item was created. + * @param lastAccessedOn Datetime the item was last accessed. + * @param lastWrittenOn Datetime the item was last written. + * @param changedOn Datetime the item was last changed. + * @param lastModified Datetime the item was last modified. + * @param eTag ETag of the item. + * @param owner Owner user identifier (UID) of the item. + * @param group Owning group identifier (GID) of the item. + * @param fileMode POSIX file mode of the item. + */ + public InternalShareFileItemProperties(OffsetDateTime createdOn, OffsetDateTime lastAccessedOn, + OffsetDateTime lastWrittenOn, OffsetDateTime changedOn, OffsetDateTime lastModified, String eTag, String owner, + String group, String fileMode) { this.createdOn = createdOn; this.lastAccessedOn = lastAccessedOn; this.lastWrittenOn = lastWrittenOn; this.changedOn = changedOn; this.lastModified = lastModified; this.eTag = eTag; + this.owner = owner; + this.group = group; + this.fileMode = fileMode; } /** @@ -76,4 +101,28 @@ public OffsetDateTime getLastModified() { public String getETag() { return eTag; } + + /** + * @return Owner user identifier (UID) of this item. + */ + @Override + public String getOwner() { + return owner; + } + + /** + * @return Owning group identifier (GID) of this item. + */ + @Override + public String getGroup() { + return group; + } + + /** + * @return POSIX file mode of this item. + */ + @Override + public String getFileMode() { + return fileMode; + } } diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/ListFilesIncludeType.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/ListFilesIncludeType.java index 183e5958cebb..ae0fc295e925 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/ListFilesIncludeType.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/ListFilesIncludeType.java @@ -26,7 +26,27 @@ public enum ListFilesIncludeType { /** * Enum value PermissionKey. */ - PERMISSION_KEY("PermissionKey"); + PERMISSION_KEY("PermissionKey"), + + /** + * Enum value Permissions. + */ + PERMISSIONS("Permissions"), + + /** + * Enum value LinkCount. + */ + LINK_COUNT("LinkCount"), + + /** + * Enum value NfsAttributes. + */ + NFS_ATTRIBUTES("NfsAttributes"), + + /** + * Enum value All. + */ + ALL("All"); /** * The actual serialized value for a ListFilesIncludeType instance. diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/SocketItem.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/SocketItem.java new file mode 100644 index 000000000000..823076df0e8f --- /dev/null +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/SocketItem.java @@ -0,0 +1,205 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.share.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.azure.core.annotation.Generated; +import com.azure.xml.XmlReader; +import com.azure.xml.XmlSerializable; +import com.azure.xml.XmlToken; +import com.azure.xml.XmlWriter; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; + +/** + * A listed socket item. + */ +@Fluent +public final class SocketItem implements XmlSerializable { + /* + * The Name property. + */ + @Generated + private StringEncoded name; + + /* + * The FileId property. + */ + @Generated + private String fileId; + + /* + * File properties. + */ + @Generated + private FileProperty properties; + + /* + * The LinkCount property. + */ + @Generated + private Long linkCount; + + /** + * Creates an instance of SocketItem class. + */ + @Generated + public SocketItem() { + } + + /** + * Get the name property: The Name property. + * + * @return the name value. + */ + @Generated + public StringEncoded getName() { + return this.name; + } + + /** + * Set the name property: The Name property. + * + * @param name the name value to set. + * @return the SocketItem object itself. + */ + @Generated + public SocketItem setName(StringEncoded name) { + this.name = name; + return this; + } + + /** + * Get the fileId property: The FileId property. + * + * @return the fileId value. + */ + @Generated + public String getFileId() { + return this.fileId; + } + + /** + * Set the fileId property: The FileId property. + * + * @param fileId the fileId value to set. + * @return the SocketItem object itself. + */ + @Generated + public SocketItem setFileId(String fileId) { + this.fileId = fileId; + return this; + } + + /** + * Get the properties property: File properties. + * + * @return the properties value. + */ + @Generated + public FileProperty getProperties() { + return this.properties; + } + + /** + * Set the properties property: File properties. + * + * @param properties the properties value to set. + * @return the SocketItem object itself. + */ + @Generated + public SocketItem setProperties(FileProperty properties) { + this.properties = properties; + return this; + } + + /** + * Get the linkCount property: The LinkCount property. + * + * @return the linkCount value. + */ + @Generated + public Long getLinkCount() { + return this.linkCount; + } + + /** + * Set the linkCount property: The LinkCount property. + * + * @param linkCount the linkCount value to set. + * @return the SocketItem object itself. + */ + @Generated + public SocketItem setLinkCount(Long linkCount) { + this.linkCount = linkCount; + return this; + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { + return toXml(xmlWriter, null); + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException { + rootElementName = rootElementName == null || rootElementName.isEmpty() ? "Socket" : rootElementName; + xmlWriter.writeStartElement(rootElementName); + xmlWriter.writeXml(this.name, "Name"); + xmlWriter.writeStringElement("FileId", this.fileId); + xmlWriter.writeXml(this.properties, "Properties"); + xmlWriter.writeNumberElement("LinkCount", this.linkCount); + return xmlWriter.writeEndElement(); + } + + /** + * Reads an instance of SocketItem from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @return An instance of SocketItem if the XmlReader was pointing to an instance of it, or null if it was pointing + * to XML null. + * @throws XMLStreamException If an error occurs while reading the SocketItem. + */ + @Generated + public static SocketItem fromXml(XmlReader xmlReader) throws XMLStreamException { + return fromXml(xmlReader, null); + } + + /** + * Reads an instance of SocketItem from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @param rootElementName Optional root element name to override the default defined by the model. Used to support + * cases where the model can deserialize from different root element names. + * @return An instance of SocketItem if the XmlReader was pointing to an instance of it, or null if it was pointing + * to XML null. + * @throws XMLStreamException If an error occurs while reading the SocketItem. + */ + @Generated + public static SocketItem fromXml(XmlReader xmlReader, String rootElementName) throws XMLStreamException { + String finalRootElementName = rootElementName == null || rootElementName.isEmpty() ? "Socket" : rootElementName; + return xmlReader.readObject(finalRootElementName, reader -> { + SocketItem deserializedSocketItem = new SocketItem(); + while (reader.nextElement() != XmlToken.END_ELEMENT) { + QName elementName = reader.getElementName(); + + if ("Name".equals(elementName.getLocalPart())) { + deserializedSocketItem.name = StringEncoded.fromXml(reader, "Name"); + } else if ("FileId".equals(elementName.getLocalPart())) { + deserializedSocketItem.fileId = reader.getStringElement(); + } else if ("Properties".equals(elementName.getLocalPart())) { + deserializedSocketItem.properties = FileProperty.fromXml(reader, "Properties"); + } else if ("LinkCount".equals(elementName.getLocalPart())) { + deserializedSocketItem.linkCount = reader.getNullableElement(Long::parseLong); + } else { + reader.skipElement(); + } + } + + return deserializedSocketItem; + }); + } +} diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/SymLinkItem.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/SymLinkItem.java new file mode 100644 index 000000000000..5b0b95ed93e4 --- /dev/null +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/models/SymLinkItem.java @@ -0,0 +1,237 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.share.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.azure.core.annotation.Generated; +import com.azure.xml.XmlReader; +import com.azure.xml.XmlSerializable; +import com.azure.xml.XmlToken; +import com.azure.xml.XmlWriter; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; + +/** + * A listed symbolic link item. + */ +@Fluent +public final class SymLinkItem implements XmlSerializable { + /* + * The Name property. + */ + @Generated + private StringEncoded name; + + /* + * The FileId property. + */ + @Generated + private String fileId; + + /* + * File properties. + */ + @Generated + private FileProperty properties; + + /* + * The LinkCount property. + */ + @Generated + private Long linkCount; + + /* + * The LinkText property. + */ + @Generated + private String linkText; + + /** + * Creates an instance of SymLinkItem class. + */ + @Generated + public SymLinkItem() { + } + + /** + * Get the name property: The Name property. + * + * @return the name value. + */ + @Generated + public StringEncoded getName() { + return this.name; + } + + /** + * Set the name property: The Name property. + * + * @param name the name value to set. + * @return the SymLinkItem object itself. + */ + @Generated + public SymLinkItem setName(StringEncoded name) { + this.name = name; + return this; + } + + /** + * Get the fileId property: The FileId property. + * + * @return the fileId value. + */ + @Generated + public String getFileId() { + return this.fileId; + } + + /** + * Set the fileId property: The FileId property. + * + * @param fileId the fileId value to set. + * @return the SymLinkItem object itself. + */ + @Generated + public SymLinkItem setFileId(String fileId) { + this.fileId = fileId; + return this; + } + + /** + * Get the properties property: File properties. + * + * @return the properties value. + */ + @Generated + public FileProperty getProperties() { + return this.properties; + } + + /** + * Set the properties property: File properties. + * + * @param properties the properties value to set. + * @return the SymLinkItem object itself. + */ + @Generated + public SymLinkItem setProperties(FileProperty properties) { + this.properties = properties; + return this; + } + + /** + * Get the linkCount property: The LinkCount property. + * + * @return the linkCount value. + */ + @Generated + public Long getLinkCount() { + return this.linkCount; + } + + /** + * Set the linkCount property: The LinkCount property. + * + * @param linkCount the linkCount value to set. + * @return the SymLinkItem object itself. + */ + @Generated + public SymLinkItem setLinkCount(Long linkCount) { + this.linkCount = linkCount; + return this; + } + + /** + * Get the linkText property: The LinkText property. + * + * @return the linkText value. + */ + @Generated + public String getLinkText() { + return this.linkText; + } + + /** + * Set the linkText property: The LinkText property. + * + * @param linkText the linkText value to set. + * @return the SymLinkItem object itself. + */ + @Generated + public SymLinkItem setLinkText(String linkText) { + this.linkText = linkText; + return this; + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { + return toXml(xmlWriter, null); + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException { + rootElementName = rootElementName == null || rootElementName.isEmpty() ? "SymLink" : rootElementName; + xmlWriter.writeStartElement(rootElementName); + xmlWriter.writeXml(this.name, "Name"); + xmlWriter.writeStringElement("FileId", this.fileId); + xmlWriter.writeXml(this.properties, "Properties"); + xmlWriter.writeNumberElement("LinkCount", this.linkCount); + xmlWriter.writeStringElement("LinkText", this.linkText); + return xmlWriter.writeEndElement(); + } + + /** + * Reads an instance of SymLinkItem from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @return An instance of SymLinkItem if the XmlReader was pointing to an instance of it, or null if it was pointing + * to XML null. + * @throws XMLStreamException If an error occurs while reading the SymLinkItem. + */ + @Generated + public static SymLinkItem fromXml(XmlReader xmlReader) throws XMLStreamException { + return fromXml(xmlReader, null); + } + + /** + * Reads an instance of SymLinkItem from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @param rootElementName Optional root element name to override the default defined by the model. Used to support + * cases where the model can deserialize from different root element names. + * @return An instance of SymLinkItem if the XmlReader was pointing to an instance of it, or null if it was pointing + * to XML null. + * @throws XMLStreamException If an error occurs while reading the SymLinkItem. + */ + @Generated + public static SymLinkItem fromXml(XmlReader xmlReader, String rootElementName) throws XMLStreamException { + String finalRootElementName + = rootElementName == null || rootElementName.isEmpty() ? "SymLink" : rootElementName; + return xmlReader.readObject(finalRootElementName, reader -> { + SymLinkItem deserializedSymLinkItem = new SymLinkItem(); + while (reader.nextElement() != XmlToken.END_ELEMENT) { + QName elementName = reader.getElementName(); + + if ("Name".equals(elementName.getLocalPart())) { + deserializedSymLinkItem.name = StringEncoded.fromXml(reader, "Name"); + } else if ("FileId".equals(elementName.getLocalPart())) { + deserializedSymLinkItem.fileId = reader.getStringElement(); + } else if ("Properties".equals(elementName.getLocalPart())) { + deserializedSymLinkItem.properties = FileProperty.fromXml(reader, "Properties"); + } else if ("LinkCount".equals(elementName.getLocalPart())) { + deserializedSymLinkItem.linkCount = reader.getNullableElement(Long::parseLong); + } else if ("LinkText".equals(elementName.getLocalPart())) { + deserializedSymLinkItem.linkText = reader.getStringElement(); + } else { + reader.skipElement(); + } + } + + return deserializedSymLinkItem; + }); + } +} diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/util/ModelHelper.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/util/ModelHelper.java index 8652bbdb4dcd..ea378447d905 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/util/ModelHelper.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/implementation/util/ModelHelper.java @@ -23,14 +23,21 @@ import com.azure.storage.file.share.implementation.accesshelpers.ShareDirectoryPropertiesHelper; import com.azure.storage.file.share.implementation.accesshelpers.ShareFileDownloadHeadersConstructorProxy; import com.azure.storage.file.share.implementation.accesshelpers.ShareFileInfoHelper; +import com.azure.storage.file.share.implementation.accesshelpers.ShareFileItemConstructorProxy; import com.azure.storage.file.share.implementation.accesshelpers.ShareFilePropertiesHelper; import com.azure.storage.file.share.implementation.accesshelpers.ShareFileSymbolicLinkInfoHelper; +import com.azure.storage.file.share.implementation.models.BlockDeviceItem; +import com.azure.storage.file.share.implementation.models.CharDeviceItem; import com.azure.storage.file.share.implementation.models.DeleteSnapshotsOptionType; import com.azure.storage.file.share.implementation.models.DirectoriesCreateHeaders; import com.azure.storage.file.share.implementation.models.DirectoriesGetPropertiesHeaders; import com.azure.storage.file.share.implementation.models.DirectoriesSetMetadataHeaders; import com.azure.storage.file.share.implementation.models.DirectoriesSetPropertiesHeaders; +import com.azure.storage.file.share.implementation.models.DirectoryItem; +import com.azure.storage.file.share.implementation.models.FifoItem; import com.azure.storage.file.share.implementation.models.FileProperty; +import com.azure.storage.file.share.implementation.models.FileItem; +import com.azure.storage.file.share.implementation.models.FilesAndDirectoriesListSegment; import com.azure.storage.file.share.implementation.models.FilesCreateHardLinkHeaders; import com.azure.storage.file.share.implementation.models.FilesCreateHeaders; import com.azure.storage.file.share.implementation.models.FilesCreateSymbolicLinkHeaders; @@ -43,6 +50,7 @@ import com.azure.storage.file.share.implementation.models.FilesUploadRangeHeaders; import com.azure.storage.file.share.implementation.models.InternalShareFileItemProperties; import com.azure.storage.file.share.implementation.models.ListFilesAndDirectoriesSegmentResponse; +import com.azure.storage.file.share.implementation.models.ListFilesIncludeType; import com.azure.storage.file.share.implementation.models.ServicesListSharesSegmentHeaders; import com.azure.storage.file.share.implementation.models.ShareItemInternal; import com.azure.storage.file.share.implementation.models.SharePropertiesInternal; @@ -50,7 +58,9 @@ import com.azure.storage.file.share.implementation.models.ShareStorageExceptionInternal; import com.azure.storage.file.share.implementation.models.SharesCreateSnapshotHeaders; import com.azure.storage.file.share.implementation.models.SharesGetPropertiesHeaders; +import com.azure.storage.file.share.implementation.models.SocketItem; import com.azure.storage.file.share.implementation.models.StringEncoded; +import com.azure.storage.file.share.implementation.models.SymLinkItem; import com.azure.storage.file.share.models.CopyStatusType; import com.azure.storage.file.share.models.CopyableFileSmbPropertiesList; import com.azure.storage.file.share.models.FilePosixProperties; @@ -58,6 +68,7 @@ import com.azure.storage.file.share.models.LeaseDurationType; import com.azure.storage.file.share.models.LeaseStateType; import com.azure.storage.file.share.models.LeaseStatusType; +import com.azure.storage.file.share.models.NfsFileType; import com.azure.storage.file.share.models.NtfsFileAttributes; import com.azure.storage.file.share.models.ShareDirectoryInfo; import com.azure.storage.file.share.models.ShareDirectoryProperties; @@ -82,6 +93,7 @@ import com.azure.storage.file.share.models.ShareStatistics; import com.azure.storage.file.share.models.ShareStorageException; import com.azure.storage.file.share.options.ShareFileCopyOptions; +import com.azure.storage.file.share.options.ShareListFilesAndDirectoriesOptions; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; @@ -96,6 +108,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.function.Function; import static com.azure.core.http.HttpHeaderName.LAST_MODIFIED; @@ -298,7 +311,8 @@ public static ShareFileItemProperties transformFileProperty(FileProperty propert return null; } return new InternalShareFileItemProperties(property.getCreationTime(), property.getLastAccessTime(), - property.getLastWriteTime(), property.getChangeTime(), property.getLastModified(), property.getEtag()); + property.getLastWriteTime(), property.getChangeTime(), property.getLastModified(), property.getEtag(), + property.getUid(), property.getGid(), property.getMode()); } public static HandleItem @@ -611,28 +625,112 @@ public static Response mapGetStatisticsResponse(Response res) { Set shareFileItems = new TreeSet<>(Comparator.comparing(ShareFileItem::getName)); if (res.getValue().getSegment() != null) { - - res.getValue() - .getSegment() - .getDirectoryItems() - .forEach(directoryItem -> shareFileItems - .add(new ShareFileItem(ModelHelper.decodeName(directoryItem.getName()), true, - directoryItem.getFileId(), ModelHelper.transformFileProperty(directoryItem.getProperties()), - NtfsFileAttributes.toAttributes(directoryItem.getAttributes()), - directoryItem.getPermissionKey(), null))); - - res.getValue() - .getSegment() - .getFileItems() - .forEach(fileItem -> shareFileItems.add(new ShareFileItem(ModelHelper.decodeName(fileItem.getName()), - false, fileItem.getFileId(), ModelHelper.transformFileProperty(fileItem.getProperties()), - NtfsFileAttributes.toAttributes(fileItem.getAttributes()), fileItem.getPermissionKey(), - fileItem.getProperties().getContentLength()))); + FilesAndDirectoriesListSegment segment = res.getValue().getSegment(); + + addShareFileItems(shareFileItems, segment.getDirectoryItems(), ModelHelper::createDirectoryShareItem); + addShareFileItems(shareFileItems, segment.getFileItems(), ModelHelper::createFileShareItem); + addShareFileItems(shareFileItems, segment.getSymLinkItems(), ModelHelper::createSymLinkShareItem); + addShareFileItems(shareFileItems, segment.getBlockDeviceItems(), ModelHelper::createBlockDeviceShareItem); + addShareFileItems(shareFileItems, segment.getCharDeviceItems(), ModelHelper::createCharDeviceShareItem); + addShareFileItems(shareFileItems, segment.getFifoItems(), ModelHelper::createFifoShareItem); + addShareFileItems(shareFileItems, segment.getSocketItems(), ModelHelper::createSocketShareItem); } return new ArrayList<>(shareFileItems); } + private static void addShareFileItems(Set shareFileItems, List items, + Function mapper) { + if (items != null) { + items.forEach(item -> shareFileItems.add(mapper.apply(item))); + } + } + + public static void addOptionToList(List includeTypes, boolean isInOptionsBag, T type) { + if (isInOptionsBag) { + includeTypes.add(type); + } + } + + private static ShareFileItem toShareFileItem(StringEncoded name, boolean isDirectory, String fileId, + FileProperty properties, String attributes, String permissionKey, Long fileSize, Long linkCount, + NfsFileType fileType, String linkText, Long deviceMajor, Long deviceMinor) { + return ShareFileItemConstructorProxy.create(ModelHelper.decodeName(name), isDirectory, fileId, + ModelHelper.transformFileProperty(properties), NtfsFileAttributes.toAttributes(attributes), permissionKey, + fileSize, linkCount, fileType, linkText, deviceMajor, deviceMinor); + } + + private static Long getContentLength(FileProperty properties) { + return properties == null ? null : properties.getContentLength(); + } + + private static NfsFileType getDirectoryFileType() { + return NfsFileType.DIRECTORY; + } + + public static List getListFilesIncludeTypes(ShareListFilesAndDirectoriesOptions options) { + if (options == null) { + return null; + } + + List includeTypes = new ArrayList<>(); + + if (options.includeAll()) { + includeTypes.add(ListFilesIncludeType.ALL); + } else { + addOptionToList(includeTypes, options.includeAttributes(), ListFilesIncludeType.ATTRIBUTES); + addOptionToList(includeTypes, options.includeETag(), ListFilesIncludeType.ETAG); + addOptionToList(includeTypes, options.includeTimestamps(), ListFilesIncludeType.TIMESTAMPS); + addOptionToList(includeTypes, options.includePermissionKey(), ListFilesIncludeType.PERMISSION_KEY); + addOptionToList(includeTypes, options.includeLinkCount(), ListFilesIncludeType.LINK_COUNT); + addOptionToList(includeTypes, options.includePermissions(), ListFilesIncludeType.PERMISSIONS); + addOptionToList(includeTypes, options.includeNfsAttributes(), ListFilesIncludeType.NFS_ATTRIBUTES); + } + + return includeTypes.isEmpty() ? null : includeTypes; + } + + private static boolean hasPosixProperties(FileProperty properties) { + return properties != null + && (properties.getUid() != null || properties.getGid() != null || properties.getMode() != null); + } + + private static ShareFileItem createDirectoryShareItem(DirectoryItem item) { + return toShareFileItem(item.getName(), true, item.getFileId(), item.getProperties(), item.getAttributes(), + item.getPermissionKey(), null, item.getLinkCount(), getDirectoryFileType(), null, null, null); + } + + private static ShareFileItem createFileShareItem(FileItem item) { + return toShareFileItem(item.getName(), false, item.getFileId(), item.getProperties(), item.getAttributes(), + item.getPermissionKey(), getContentLength(item.getProperties()), item.getLinkCount(), + item.getFileType() == null ? NfsFileType.REGULAR : item.getFileType(), null, null, null); + } + + private static ShareFileItem createSymLinkShareItem(SymLinkItem item) { + return toShareFileItem(item.getName(), false, item.getFileId(), item.getProperties(), null, null, null, + item.getLinkCount(), NfsFileType.SYM_LINK, item.getLinkText(), null, null); + } + + private static ShareFileItem createBlockDeviceShareItem(BlockDeviceItem item) { + return toShareFileItem(item.getName(), false, item.getFileId(), item.getProperties(), null, null, null, + item.getLinkCount(), NfsFileType.BLOCK_DEVICE, null, item.getDeviceMajor(), item.getDeviceMinor()); + } + + private static ShareFileItem createCharDeviceShareItem(CharDeviceItem item) { + return toShareFileItem(item.getName(), false, item.getFileId(), item.getProperties(), null, null, null, + item.getLinkCount(), NfsFileType.CHARACTER_DEVICE, null, item.getDeviceMajor(), item.getDeviceMinor()); + } + + private static ShareFileItem createFifoShareItem(FifoItem item) { + return toShareFileItem(item.getName(), false, item.getFileId(), item.getProperties(), null, null, null, + item.getLinkCount(), NfsFileType.FIFO, null, null, null); + } + + private static ShareFileItem createSocketShareItem(SocketItem item) { + return toShareFileItem(item.getName(), false, item.getFileId(), item.getProperties(), null, null, null, + item.getLinkCount(), NfsFileType.SOCKET, null, null, null); + } + public static Response createHardLinkResponse(final ResponseBase response) { String eTag = response.getDeserializedHeaders().getETag(); diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java index c252495b5def..5b9bb48b884e 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. - package com.azure.storage.file.share.models; import com.azure.core.annotation.Generated; @@ -9,9 +8,15 @@ import java.util.Collection; /** - * Defines values for NfsFileType. + * Type of the file. + * + * This enumeration represents the type of a file item in Azure Files shares. The file type is populated for all item + * types in both SMB and NFS-enabled shares. + * + * @see ShareFileItem#getFileType() */ public final class NfsFileType extends ExpandableStringEnum { + /** * Static value Regular for NfsFileType. */ @@ -30,9 +35,33 @@ public final class NfsFileType extends ExpandableStringEnum { @Generated public static final NfsFileType SYM_LINK = fromString("SymLink"); + /** + * Static value BlockDevice for NfsFileType. + */ + @Generated + public static final NfsFileType BLOCK_DEVICE = fromString("BlockDevice"); + + /** + * Static value CharacterDevice for NfsFileType. + */ + @Generated + public static final NfsFileType CHARACTER_DEVICE = fromString("CharacterDevice"); + + /** + * Static value Socket for NfsFileType. + */ + @Generated + public static final NfsFileType SOCKET = fromString("Socket"); + + /** + * Static value Fifo for NfsFileType. + */ + @Generated + public static final NfsFileType FIFO = fromString("Fifo"); + /** * Creates a new instance of NfsFileType value. - * + * * @deprecated Use the {@link #fromString(String)} factory method. */ @Generated @@ -42,7 +71,7 @@ public NfsFileType() { /** * Creates or finds a NfsFileType from its string representation. - * + * * @param name a name to look for. * @return the corresponding NfsFileType. */ @@ -53,7 +82,7 @@ public static NfsFileType fromString(String name) { /** * Gets known NfsFileType values. - * + * * @return known NfsFileType values. */ @Generated diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/ShareFileItem.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/ShareFileItem.java index 991cdf61f3e8..db04361e6ea5 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/ShareFileItem.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/ShareFileItem.java @@ -4,6 +4,7 @@ package com.azure.storage.file.share.models; import com.azure.core.annotation.Immutable; +import com.azure.storage.file.share.implementation.accesshelpers.ShareFileItemConstructorProxy; import java.util.EnumSet; @@ -19,6 +20,15 @@ public final class ShareFileItem { private final EnumSet fileAttributes; private final String permissionKey; private final Long fileSize; + private final Long linkCount; + private final NfsFileType fileType; + private final String linkText; + private final Long deviceMajor; + private final Long deviceMinor; + + static { + ShareFileItemConstructorProxy.setAccessor(ShareFileItem::new); + } /** * Creates an instance of file or directory reference information about a specific Share. @@ -28,7 +38,7 @@ public final class ShareFileItem { * @param fileSize Size of a file. Pass {@code null} if the reference is a directory. */ public ShareFileItem(String name, boolean isDirectory, Long fileSize) { - this(name, isDirectory, null, null, null, null, fileSize); + this(name, isDirectory, null, null, null, null, fileSize, null, null, null, null, null); } /** @@ -44,6 +54,12 @@ public ShareFileItem(String name, boolean isDirectory, Long fileSize) { */ public ShareFileItem(String name, boolean isDirectory, String id, ShareFileItemProperties properties, EnumSet fileAttributes, String permissionKey, Long fileSize) { + this(name, isDirectory, id, properties, fileAttributes, permissionKey, fileSize, null, null, null, null, null); + } + + private ShareFileItem(String name, boolean isDirectory, String id, ShareFileItemProperties properties, + EnumSet fileAttributes, String permissionKey, Long fileSize, Long linkCount, + NfsFileType fileType, String linkText, Long deviceMajor, Long deviceMinor) { this.name = name; this.isDirectory = isDirectory; this.id = id; @@ -51,6 +67,11 @@ public ShareFileItem(String name, boolean isDirectory, String id, ShareFileItemP this.fileAttributes = fileAttributes; this.permissionKey = permissionKey; this.fileSize = fileSize; + this.linkCount = linkCount; + this.fileType = fileType; + this.linkText = linkText; + this.deviceMajor = deviceMajor; + this.deviceMinor = deviceMinor; } /** @@ -115,4 +136,62 @@ public EnumSet getFileAttributes() { public String getPermissionKey() { return permissionKey; } + + /** + * Gets the count of hard links for this item. + * Applicable to all item types in NFS shares: files, directories, symbolic links, block devices, character + * devices, FIFOs, and sockets. + * Supported in version 2026-12-06 and above. + * + * @return The count of hard links for this item. + */ + public Long getLinkCount() { + return linkCount; + } + + /** + * Gets the file type for this item. + * In SMB shares, this field is populated for files and directories. + * In NFS-enabled shares, this field is populated for files, directories, symbolic links, block devices, + * character devices, FIFOs, and sockets. + * Supported in version 2026-12-06 and above. + * + * @return The file type for this item. + */ + public NfsFileType getFileType() { + return fileType; + } + + /** + * Gets the link text for this item. + * Only applicable to symbolic links in NFS shares. + * Supported in version 2026-12-06 and above. + * + * @return The link text for this item. + */ + public String getLinkText() { + return linkText; + } + + /** + * Gets the major device number for this item. + * Only applicable to block devices and character devices in NFS shares. + * Supported in version 2026-12-06 and above. + * + * @return The major device number for this item. + */ + public Long getDeviceMajor() { + return deviceMajor; + } + + /** + * Gets the minor device number for this item. + * Only applicable to block devices and character devices in NFS shares. + * Supported in version 2026-12-06 and above. + * + * @return The minor device number for this item. + */ + public Long getDeviceMinor() { + return deviceMinor; + } } diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/ShareFileItemProperties.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/ShareFileItemProperties.java index 5a817fe23ff9..cbff26d7baa3 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/ShareFileItemProperties.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/ShareFileItemProperties.java @@ -51,4 +51,31 @@ public interface ShareFileItemProperties { * @return ETag of this item. */ String getETag(); + + /** + * Gets the owner user identifier (UID) for this item. + * + * @return The owner user identifier (UID), or {@code null} if not returned by the service. + */ + default String getOwner() { + return null; + } + + /** + * Gets the owning group identifier (GID) for this item. + * + * @return The owning group identifier (GID), or {@code null} if not returned by the service. + */ + default String getGroup() { + return null; + } + + /** + * Gets the POSIX file mode for this item. + * + * @return The POSIX file mode, or {@code null} if not returned by the service. + */ + default String getFileMode() { + return null; + } } diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/options/ShareListFilesAndDirectoriesOptions.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/options/ShareListFilesAndDirectoriesOptions.java index 0b5138331c40..0c063ab0aab9 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/options/ShareListFilesAndDirectoriesOptions.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/options/ShareListFilesAndDirectoriesOptions.java @@ -14,6 +14,10 @@ public final class ShareListFilesAndDirectoriesOptions { private boolean includeAttributes; private boolean includePermissionKey; private Boolean includeExtendedInfo; + private boolean includePermissions; + private boolean includeLinkCount; + private boolean includeNfsAttributes; + private boolean includeAll; /** * Creates a new instance of {@link ShareListFilesAndDirectoriesOptions}. @@ -171,4 +175,84 @@ public ShareListFilesAndDirectoriesOptions setIncludePermissionKey(boolean inclu this.includePermissionKey = includePermissionKey; return this; } + + /** + * Gets whether to include the permissions on a listing operation. + * + * @return Whether to include the permissions on this listing operation. + */ + public boolean includePermissions() { + return includePermissions; + } + + /** + * Sets whether to include the permissions on a listing operation. + * + * @param includePermissions Whether to include the permissions on this listing operation. + * @return Updated options. + */ + public ShareListFilesAndDirectoriesOptions setIncludePermissions(boolean includePermissions) { + this.includePermissions = includePermissions; + return this; + } + + /** + * Gets whether to include NFS attributes on a listing operation. + * + * @return Whether to include NFS attributes on this listing operation. + */ + public boolean includeNfsAttributes() { + return includeNfsAttributes; + } + + /** + * Sets whether to include NFS attributes on a listing operation. + * + * @param includeNfsAttributes Whether to include NFS attributes on this listing operation. + * @return Updated options. + */ + public ShareListFilesAndDirectoriesOptions setIncludeNfsAttributes(boolean includeNfsAttributes) { + this.includeNfsAttributes = includeNfsAttributes; + return this; + } + + /** + * Gets whether to include the link count on a listing operation. + * + * @return Whether to include the link count on this listing operation. + */ + public boolean includeLinkCount() { + return includeLinkCount; + } + + /** + * Sets whether to include the link count on a listing operation. + * + * @param includeLinkCount Whether to include the link count on this listing operation. + * @return Updated options. + */ + public ShareListFilesAndDirectoriesOptions setIncludeLinkCount(boolean includeLinkCount) { + this.includeLinkCount = includeLinkCount; + return this; + } + + /** + * Gets whether to include all optional values on a listing operation. + * + * @return Whether to include all optional values on this listing operation. + */ + public boolean includeAll() { + return includeAll; + } + + /** + * Sets whether to include all optional values on a listing operation. + * + * @param includeAll Whether to include all optional values on this listing operation. + * @return Updated options. + */ + public ShareListFilesAndDirectoriesOptions setIncludeAll(boolean includeAll) { + this.includeAll = includeAll; + return this; + } } diff --git a/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryApiTests.java b/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryApiTests.java index 6f3ff54d53ee..19944f3fbb34 100644 --- a/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryApiTests.java +++ b/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryApiTests.java @@ -36,6 +36,8 @@ import com.azure.storage.file.share.models.ShareTokenIntent; import com.azure.storage.file.share.options.ShareDirectoryCreateOptions; import com.azure.storage.file.share.options.ShareDirectorySetPropertiesOptions; +import com.azure.storage.file.share.options.ShareFileCreateOptions; +import com.azure.storage.file.share.options.ShareFileCreateSymbolicLinkOptions; import com.azure.storage.file.share.options.ShareFileRenameOptions; import com.azure.storage.file.share.options.ShareListFilesAndDirectoriesOptions; import com.azure.storage.file.share.sas.ShareFileSasPermission; @@ -915,6 +917,150 @@ public void listFilesAndDirectoriesExtendedInfoResults() { assertFalse(FileShareTestHelper.isAllWhitespace(fileListItem.getProperties().getETag())); } + @Test + @RequiredServiceVersion(clazz = ShareServiceVersion.class, min = "2026-12-06") + public void listFilesAndDirectoriesAllTraitsSmb() { + ShareDirectoryClient parentDir = primaryDirectoryClient; + parentDir.create(); + ShareFileClient file = parentDir.createFile(generatePathName(), Constants.KB); + ShareDirectoryClient subDir = parentDir.createSubdirectory(generatePathName()); + ShareListFilesAndDirectoriesOptions allOptions + = new ShareListFilesAndDirectoriesOptions().setIncludeExtendedInfo(true).setIncludeAll(true); + + List listResults + = parentDir.listFilesAndDirectories(allOptions, null, null).stream().collect(Collectors.toList()); + + String expectedFileName = new File(file.getFilePath()).getName(); + ShareFileItem fileItem = listResults.stream() + .filter(item -> expectedFileName.equals(item.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found: " + expectedFileName)); + + assertEquals(2, listResults.size()); + assertFalse(fileItem.isDirectory()); + assertNotNull(fileItem.getId()); + assertEquals(EnumSet.of(NtfsFileAttributes.ARCHIVE), fileItem.getFileAttributes()); + assertNotNull(fileItem.getPermissionKey()); + assertNotNull(fileItem.getProperties()); + assertNotNull(fileItem.getProperties().getCreatedOn()); + assertNotNull(fileItem.getProperties().getLastAccessedOn()); + assertNotNull(fileItem.getProperties().getLastWrittenOn()); + assertNotNull(fileItem.getProperties().getChangedOn()); + assertNotNull(fileItem.getProperties().getLastModified()); + assertNotNull(fileItem.getProperties().getETag()); + + assertNull(fileItem.getLinkCount()); + assertEquals(NfsFileType.REGULAR, fileItem.getFileType()); + assertNull(fileItem.getProperties().getOwner()); + assertNull(fileItem.getProperties().getGroup()); + assertNull(fileItem.getProperties().getFileMode()); + + String expectedDirectoryName = new File(subDir.getDirectoryPath()).getName(); + ShareFileItem dirItem = listResults.stream() + .filter(item -> expectedDirectoryName.equals(item.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found: " + expectedDirectoryName)); + assertTrue(dirItem.isDirectory()); + assertNotNull(dirItem.getId()); + assertEquals(EnumSet.of(NtfsFileAttributes.DIRECTORY), dirItem.getFileAttributes()); + assertNotNull(dirItem.getPermissionKey()); + assertNotNull(dirItem.getProperties()); + assertNotNull(dirItem.getProperties().getCreatedOn()); + assertNotNull(dirItem.getProperties().getLastAccessedOn()); + assertNotNull(dirItem.getProperties().getLastWrittenOn()); + assertNotNull(dirItem.getProperties().getChangedOn()); + assertNotNull(dirItem.getProperties().getLastModified()); + assertNotNull(dirItem.getProperties().getETag()); + + assertNull(dirItem.getLinkCount()); + assertNull(dirItem.getProperties().getOwner()); + assertNull(dirItem.getProperties().getGroup()); + assertNull(dirItem.getProperties().getFileMode()); + } + + @RequiredServiceVersion(clazz = ShareServiceVersion.class, min = "2026-12-06") + @Test + public void listFilesAndDirectoriesNfs() { + ShareClient premiumShareClient = getPremiumNFSShareClient(generateShareName()); + + try { + ShareDirectoryClient parent = premiumShareClient.getDirectoryClient(generatePathName()); + parent.create(); + + String owner = "345"; + String group = "123"; + String fileMode = "7777"; + FilePosixProperties posixProperties + = new FilePosixProperties().setOwner(owner).setGroup(group).setFileMode(fileMode); + + String fileName = generatePathName(); + ShareFileClient file = parent.getFileClient(fileName); + file.createWithResponse(new ShareFileCreateOptions(Constants.MB).setPosixProperties(posixProperties), null, + null); + + String subdirName = generatePathName(); + ShareDirectoryClient subdir = parent.getSubdirectoryClient(subdirName); + subdir.createWithResponse(new ShareDirectoryCreateOptions().setPosixProperties(posixProperties), null, + null); + + String symlinkName = generatePathName(); + ShareFileClient symlink = parent.getFileClient(symlinkName); + symlink.createSymbolicLinkWithResponse( + new ShareFileCreateSymbolicLinkOptions(file.getFileUrl()).setOwner(owner).setGroup(group), null, null); + + ShareListFilesAndDirectoriesOptions options + = new ShareListFilesAndDirectoriesOptions().setIncludeExtendedInfo(true) + .setIncludeTimestamps(true) + .setIncludeETag(true) + .setIncludePermissions(true) + .setIncludeLinkCount(true) + .setIncludeNfsAttributes(true); + List items + = parent.listFilesAndDirectories(options, null, null).stream().collect(Collectors.toList()); + + assertEquals(3, items.size()); + + ShareFileItem fileItem = items.stream() + .filter(item -> fileName.equals(item.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found: " + fileName)); + assertFalse(fileItem.isDirectory()); + assertEquals(NfsFileType.REGULAR, fileItem.getFileType()); + assertNotNull(fileItem.getLinkCount()); + assertNotNull(fileItem.getProperties()); + assertEquals(owner, fileItem.getProperties().getOwner()); + assertEquals(group, fileItem.getProperties().getGroup()); + assertEquals(fileMode, fileItem.getProperties().getFileMode()); + + ShareFileItem dirItem = items.stream() + .filter(item -> subdirName.equals(item.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found: " + subdirName)); + assertTrue(dirItem.isDirectory()); + assertEquals(NfsFileType.DIRECTORY, dirItem.getFileType()); + assertNotNull(dirItem.getLinkCount()); + assertNotNull(dirItem.getProperties()); + assertEquals(owner, dirItem.getProperties().getOwner()); + assertEquals(group, dirItem.getProperties().getGroup()); + assertEquals(fileMode, dirItem.getProperties().getFileMode()); + + ShareFileItem symlinkItem = items.stream() + .filter(item -> symlinkName.equals(item.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found: " + symlinkName)); + assertFalse(symlinkItem.isDirectory()); + assertEquals(NfsFileType.SYM_LINK, symlinkItem.getFileType()); + assertNotNull(symlinkItem.getLinkCount()); + assertNotNull(symlinkItem.getLinkText()); + assertFalse(FileShareTestHelper.isAllWhitespace(symlinkItem.getLinkText())); + assertNotNull(symlinkItem.getProperties()); + assertEquals(owner, symlinkItem.getProperties().getOwner()); + assertEquals(group, symlinkItem.getProperties().getGroup()); + } finally { + premiumShareClient.delete(); + } + } + @Test @RequiredServiceVersion(clazz = ShareServiceVersion.class, min = "2021-12-02") public void listFilesAndDirectoriesEncoded() { diff --git a/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryAsyncApiTests.java b/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryAsyncApiTests.java index e4329f218fca..749addc8e4b4 100644 --- a/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryAsyncApiTests.java +++ b/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryAsyncApiTests.java @@ -27,7 +27,10 @@ import com.azure.storage.file.share.models.ShareTokenIntent; import com.azure.storage.file.share.options.ShareDirectoryCreateOptions; import com.azure.storage.file.share.options.ShareDirectorySetPropertiesOptions; +import com.azure.storage.file.share.options.ShareFileCreateOptions; +import com.azure.storage.file.share.options.ShareFileCreateSymbolicLinkOptions; import com.azure.storage.file.share.options.ShareFileRenameOptions; +import com.azure.storage.file.share.options.ShareListFilesAndDirectoriesOptions; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -536,6 +539,154 @@ private static Stream listFilesAndDirectoriesArgsSupplier() { return Stream.of(Arguments.of("", null, 3), Arguments.of("", 1, 3), Arguments.of("noops", 3, 0)); } + @RequiredServiceVersion(clazz = ShareServiceVersion.class, min = "2026-12-06") + @Test + public void listFilesAndDirectoriesAllTraitsSmb() { + String fileName = generatePathName(); + String subdirName = generatePathName(); + Mono> listResults = primaryDirectoryAsyncClient.create() + .then(primaryDirectoryAsyncClient.createFile(fileName, Constants.KB)) + .then(primaryDirectoryAsyncClient.createSubdirectory(subdirName)) + .thenMany(primaryDirectoryAsyncClient.listFilesAndDirectories( + new ShareListFilesAndDirectoriesOptions().setIncludeExtendedInfo(true).setIncludeAll(true))) + .collectList(); + + StepVerifier.create(listResults).assertNext(items -> { + assertEquals(2, items.size()); + + ShareFileItem fileItem = items.stream() + .filter(item -> fileName.equals(item.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found: " + fileName)); + assertFalse(fileItem.isDirectory()); + assertNotNull(fileItem.getId()); + assertEquals(EnumSet.of(NtfsFileAttributes.ARCHIVE), fileItem.getFileAttributes()); + assertNotNull(fileItem.getPermissionKey()); + assertNotNull(fileItem.getProperties()); + assertNotNull(fileItem.getProperties().getCreatedOn()); + assertNotNull(fileItem.getProperties().getLastAccessedOn()); + assertNotNull(fileItem.getProperties().getLastWrittenOn()); + assertNotNull(fileItem.getProperties().getChangedOn()); + assertNotNull(fileItem.getProperties().getLastModified()); + assertNotNull(fileItem.getProperties().getETag()); + assertNull(fileItem.getLinkCount()); + assertEquals(NfsFileType.REGULAR, fileItem.getFileType()); + assertNull(fileItem.getProperties().getOwner()); + assertNull(fileItem.getProperties().getGroup()); + assertNull(fileItem.getProperties().getFileMode()); + + ShareFileItem dirItem = items.stream() + .filter(item -> subdirName.equals(item.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found: " + subdirName)); + assertTrue(dirItem.isDirectory()); + assertNotNull(dirItem.getId()); + assertEquals(EnumSet.of(NtfsFileAttributes.DIRECTORY), dirItem.getFileAttributes()); + assertNotNull(dirItem.getPermissionKey()); + assertNotNull(dirItem.getProperties()); + assertNotNull(dirItem.getProperties().getCreatedOn()); + assertNotNull(dirItem.getProperties().getLastAccessedOn()); + assertNotNull(dirItem.getProperties().getLastWrittenOn()); + assertNotNull(dirItem.getProperties().getChangedOn()); + assertNotNull(dirItem.getProperties().getLastModified()); + assertNotNull(dirItem.getProperties().getETag()); + assertNull(dirItem.getLinkCount()); + + assertNull(dirItem.getProperties().getOwner()); + assertNull(dirItem.getProperties().getGroup()); + assertNull(dirItem.getProperties().getFileMode()); + }).verifyComplete(); + } + + @RequiredServiceVersion(clazz = ShareServiceVersion.class, min = "2026-12-06") + @Test + public void listFilesAndDirectoriesNfs() { + String premiumShareName = generateShareName(); + String fileName = generatePathName(); + String subdirName = generatePathName(); + String symlinkName = generatePathName(); + String owner = "345"; + String group = "123"; + String fileMode = "7777"; + + Mono> createAndList + = getPremiumNFSShareAsyncClient(premiumShareName).flatMap(premiumShareClient -> { + ShareDirectoryAsyncClient parent = premiumShareClient.getDirectoryClient(generatePathName()); + FilePosixProperties posixProperties + = new FilePosixProperties().setOwner(owner).setGroup(group).setFileMode(fileMode); + + ShareFileAsyncClient file = parent.getFileClient(fileName); + ShareDirectoryAsyncClient subdir = parent.getSubdirectoryClient(subdirName); + ShareFileAsyncClient symlink = parent.getFileClient(symlinkName); + + ShareFileCreateOptions fileOptions + = new ShareFileCreateOptions(Constants.MB).setPosixProperties(posixProperties); + ShareDirectoryCreateOptions subdirOptions + = new ShareDirectoryCreateOptions().setPosixProperties(posixProperties); + ShareFileCreateSymbolicLinkOptions symlinkOptions + = new ShareFileCreateSymbolicLinkOptions(file.getFileUrl()).setOwner(owner).setGroup(group); + ShareListFilesAndDirectoriesOptions listOptions + = new ShareListFilesAndDirectoriesOptions().setIncludeExtendedInfo(true) + .setIncludeTimestamps(true) + .setIncludeETag(true) + .setIncludePermissions(true) + .setIncludeLinkCount(true) + .setIncludeNfsAttributes(true); + + return parent.create() + .then(file.createWithResponse(fileOptions)) + .then(subdir.createWithResponse(subdirOptions)) + .then(symlink.createSymbolicLinkWithResponse(symlinkOptions)) + .thenMany(parent.listFilesAndDirectories(listOptions)) + .collectList(); + }); + + try { + StepVerifier.create(createAndList).assertNext(items -> { + assertEquals(3, items.size()); + + ShareFileItem fileItem = items.stream() + .filter(item -> fileName.equals(item.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found: " + fileName)); + assertFalse(fileItem.isDirectory()); + assertEquals(NfsFileType.REGULAR, fileItem.getFileType()); + assertNotNull(fileItem.getLinkCount()); + assertNotNull(fileItem.getProperties()); + assertEquals(owner, fileItem.getProperties().getOwner()); + assertEquals(group, fileItem.getProperties().getGroup()); + assertEquals(fileMode, fileItem.getProperties().getFileMode()); + + ShareFileItem dirItem = items.stream() + .filter(item -> subdirName.equals(item.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found: " + subdirName)); + assertTrue(dirItem.isDirectory()); + assertEquals(NfsFileType.DIRECTORY, dirItem.getFileType()); + assertNotNull(dirItem.getLinkCount()); + assertNotNull(dirItem.getProperties()); + assertEquals(owner, dirItem.getProperties().getOwner()); + assertEquals(group, dirItem.getProperties().getGroup()); + assertEquals(fileMode, dirItem.getProperties().getFileMode()); + + ShareFileItem symlinkItem = items.stream() + .filter(item -> symlinkName.equals(item.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found: " + symlinkName)); + assertFalse(symlinkItem.isDirectory()); + assertEquals(NfsFileType.SYM_LINK, symlinkItem.getFileType()); + assertNotNull(symlinkItem.getLinkCount()); + assertNotNull(symlinkItem.getLinkText()); + assertFalse(FileShareTestHelper.isAllWhitespace(symlinkItem.getLinkText())); + assertNotNull(symlinkItem.getProperties()); + assertEquals(owner, symlinkItem.getProperties().getOwner()); + assertEquals(group, symlinkItem.getProperties().getGroup()); + }).verifyComplete(); + } finally { + premiumFileServiceAsyncClient.getShareAsyncClient(premiumShareName).delete().block(); + } + } + @ParameterizedTest @MethodSource("listHandlesSupplier") public void listHandles(Integer maxResults, boolean recursive) { diff --git a/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryListingDeserializationTests.java b/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryListingDeserializationTests.java new file mode 100644 index 000000000000..a1e2e8df330e --- /dev/null +++ b/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/DirectoryListingDeserializationTests.java @@ -0,0 +1,169 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.share; + +import com.azure.core.http.HttpHeaderName; +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.test.http.MockHttpResponse; +import com.azure.storage.file.share.models.NfsFileType; +import com.azure.storage.file.share.models.ShareFileItem; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class DirectoryListingDeserializationTests { + private static final String LIST_FILES_AND_DIRECTORIES_RESPONSE = "testfiles/ListFilesAndDirectoriesResponse.xml"; + + @Test + public void listFilesAndDirectoriesNfsAllItemTypes() throws Exception { + String xml = readResource(LIST_FILES_AND_DIRECTORIES_RESPONSE); + HttpPipeline httpPipeline = new HttpPipelineBuilder().httpClient(request -> Mono.just( + new MockHttpResponse(request, 200, new HttpHeaders().set(HttpHeaderName.CONTENT_TYPE, "application/xml"), + xml.getBytes(StandardCharsets.UTF_8)))) + .build(); + + ShareDirectoryClient directory = new ShareFileClientBuilder().endpoint("https://account.file.core.windows.net") + .shareName("myshare") + .resourcePath("mydir") + .serviceVersion(ShareServiceVersion.V2027_03_07) + .pipeline(httpPipeline) + .buildDirectoryClient(); + + List items = directory.listFilesAndDirectories().stream().collect(Collectors.toList()); + + assertAllNfsItemTypes(items); + } + + @Test + public void listFilesAndDirectoriesNfsAllItemTypesAsync() throws Exception { + String xml = readResource(LIST_FILES_AND_DIRECTORIES_RESPONSE); + HttpPipeline httpPipeline = new HttpPipelineBuilder().httpClient(request -> Mono.just( + new MockHttpResponse(request, 200, new HttpHeaders().set(HttpHeaderName.CONTENT_TYPE, "application/xml"), + xml.getBytes(StandardCharsets.UTF_8)))) + .build(); + + ShareDirectoryAsyncClient directory + = new ShareFileClientBuilder().endpoint("https://account.file.core.windows.net") + .shareName("myshare") + .resourcePath("mydir") + .serviceVersion(ShareServiceVersion.V2027_03_07) + .pipeline(httpPipeline) + .buildDirectoryAsyncClient(); + + List items = directory.listFilesAndDirectories().collectList().block(); + + assertAllNfsItemTypes(items); + } + + private static void assertAllNfsItemTypes(List items) { + assertEquals(10, items.size()); + + ShareFileItem dir = getItemByFileType(items, NfsFileType.DIRECTORY); + assertTrue(dir.isDirectory()); + assertEquals("subdir", dir.getName()); + assertEquals("12682206919419625485", dir.getId()); + assertEquals(Long.valueOf(2), dir.getLinkCount()); + assertNull(dir.getFileSize()); + assertPosixProperties(dir, "1000", "1000", "0755"); + assertEquals("\"0x8DEAF1479E1C087\"", dir.getProperties().getETag()); + + List files = items.stream() + .filter(item -> !item.isDirectory() && item.getFileType() == NfsFileType.REGULAR) + .collect(Collectors.toList()); + assertEquals(4, files.size()); + files.forEach(file -> { + assertFalse(file.isDirectory()); + assertPosixProperties(file, "1000", "1000", "0644"); + }); + + assertListedFileItem(files.get(0), "hardlink.txt", "13835128424026472451", 80L, 2L); + assertListedFileItem(files.get(1), "regular.txt", "13835128424026472451", 80L, 2L); + assertListedFileItem(files.get(2), "regularClose.txt", "9799903157902508049", 14L, 1L); + assertListedFileItem(files.get(3), "regularOpen.txt", "17293892937847013391", 14L, 1L); + + ShareFileItem symlink = getItemByFileType(items, NfsFileType.SYM_LINK); + assertFalse(symlink.isDirectory()); + assertEquals("symlink.txt", symlink.getName()); + assertEquals("10376363910205931529", symlink.getId()); + assertEquals(Long.valueOf(1), symlink.getLinkCount()); + assertEquals("/mnt/s2/dir2/regular.txt", symlink.getLinkText()); + assertPosixProperties(symlink, "1000", "1000", "0777"); + + ShareFileItem block = getItemByFileType(items, NfsFileType.BLOCK_DEVICE); + assertEquals("block_device", block.getName()); + assertEquals("10952824662509355033", block.getId()); + assertEquals(Long.valueOf(1), block.getLinkCount()); + assertEquals(Long.valueOf(8), block.getDeviceMajor()); + assertEquals(Long.valueOf(0), block.getDeviceMinor()); + assertPosixProperties(block, "0", "0", "0640"); + + ShareFileItem charDev = getItemByFileType(items, NfsFileType.CHARACTER_DEVICE); + assertEquals("char_device", charDev.getName()); + assertEquals("16717432185543589911", charDev.getId()); + assertEquals(Long.valueOf(1), charDev.getLinkCount()); + assertEquals(Long.valueOf(1), charDev.getDeviceMajor()); + assertEquals(Long.valueOf(7), charDev.getDeviceMinor()); + assertPosixProperties(charDev, "0", "0", "0644"); + + ShareFileItem fifo = getItemByFileType(items, NfsFileType.FIFO); + assertEquals("fifo_pipe", fifo.getName()); + assertEquals("14988049928633319435", fifo.getId()); + assertEquals(Long.valueOf(1), fifo.getLinkCount()); + assertNull(fifo.getDeviceMajor()); + assertNull(fifo.getDeviceMinor()); + assertNull(fifo.getLinkText()); + assertPosixProperties(fifo, "1000", "1000", "0644"); + + ShareFileItem socket = getItemByFileType(items, NfsFileType.SOCKET); + assertEquals("unix_socket", socket.getName()); + assertEquals("16429201809391878183", socket.getId()); + assertEquals(Long.valueOf(1), socket.getLinkCount()); + assertNull(socket.getDeviceMajor()); + assertNull(socket.getDeviceMinor()); + assertNull(socket.getLinkText()); + assertPosixProperties(socket, "0", "0", "0755"); + } + + private static ShareFileItem getItemByFileType(List items, NfsFileType fileType) { + return items.stream() + .filter(item -> fileType.equals(item.getFileType())) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected listed item not found for type: " + fileType)); + } + + private static void assertListedFileItem(ShareFileItem item, String name, String id, long fileSize, + long linkCount) { + assertEquals(name, item.getName()); + assertEquals(id, item.getId()); + assertEquals(Long.valueOf(fileSize), item.getFileSize()); + assertEquals(Long.valueOf(linkCount), item.getLinkCount()); + } + + private static void assertPosixProperties(ShareFileItem item, String owner, String group, String fileMode) { + assertNotNull(item.getProperties()); + assertEquals(owner, item.getProperties().getOwner()); + assertEquals(group, item.getProperties().getGroup()); + assertEquals(fileMode, item.getProperties().getFileMode()); + } + + private static String readResource(String resourceName) throws Exception { + URL resource = DirectoryListingDeserializationTests.class.getClassLoader().getResource(resourceName); + assertNotNull(resource); + return new String(Files.readAllBytes(Paths.get(resource.toURI())), StandardCharsets.UTF_8); + } +} diff --git a/sdk/storage/azure-storage-file-share/src/test/resources/testfiles/ListFilesAndDirectoriesResponse.xml b/sdk/storage/azure-storage-file-share/src/test/resources/testfiles/ListFilesAndDirectoriesResponse.xml new file mode 100644 index 000000000000..df6e051b2063 --- /dev/null +++ b/sdk/storage/azure-storage-file-share/src/test/resources/testfiles/ListFilesAndDirectoriesResponse.xml @@ -0,0 +1,121 @@ + + + + + subdir + 12682206919419625485 + + 2025-10-01T00:00:00Z + 2025-10-01T00:00:00Z + 2025-10-01T00:00:00Z + 2025-10-01T00:00:00Z + Wed, 01 Oct 2025 00:00:00 GMT + "0x8DEAF1479E1C087" + 1000 + 1000 + 0755 + + 2 + + + hardlink.txt + 13835128424026472451 + + 80 + 1000 + 1000 + 0644 + + 2 + + + regular.txt + 13835128424026472451 + + 80 + 1000 + 1000 + 0644 + + 2 + + + regularClose.txt + 9799903157902508049 + + 14 + 1000 + 1000 + 0644 + + 1 + + + regularOpen.txt + 17293892937847013391 + + 14 + 1000 + 1000 + 0644 + + 1 + + + symlink.txt + 10376363910205931529 + + 1000 + 1000 + 0777 + + 1 + /mnt/s2/dir2/regular.txt + + + block_device + 10952824662509355033 + + 0 + 0 + 0640 + + 1 + 8 + 0 + + + char_device + 16717432185543589911 + + 0 + 0 + 0644 + + 1 + 1 + 7 + + + fifo_pipe + 14988049928633319435 + + 1000 + 1000 + 0644 + + 1 + + + unix_socket + 16429201809391878183 + + 0 + 0 + 0755 + + 1 + + + + diff --git a/sdk/storage/azure-storage-file-share/swagger/README.md b/sdk/storage/azure-storage-file-share/swagger/README.md index 41515fb4e938..0358021c86dd 100644 --- a/sdk/storage/azure-storage-file-share/swagger/README.md +++ b/sdk/storage/azure-storage-file-share/swagger/README.md @@ -16,7 +16,7 @@ autorest ### Code generation settings ``` yaml use: '@autorest/java@4.1.63' -input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/15d7f54a5389d5906ffb4e56bb2f38fe5525c0d3/specification/storage/data-plane/Microsoft.FileStorage/stable/2026-06-06/file.json +input-file: https://raw.githubusercontent.com/seanmcc-msft/azure-rest-api-specs/e38b4c39072e9c00e3607cde729cea2e8d237b92/specification/storage/data-plane/Microsoft.FileStorage/stable/2026-12-06/file.json java: true output-folder: ../ namespace: com.azure.storage.file.share diff --git a/sdk/storage/azure-storage-file-share/swagger/src/main/java/ShareStorageCustomization.java b/sdk/storage/azure-storage-file-share/swagger/src/main/java/ShareStorageCustomization.java index 74f8922fbf89..62739fbb9905 100644 --- a/sdk/storage/azure-storage-file-share/swagger/src/main/java/ShareStorageCustomization.java +++ b/sdk/storage/azure-storage-file-share/swagger/src/main/java/ShareStorageCustomization.java @@ -32,6 +32,13 @@ public void customize(LibraryCustomization customization, Logger logger) { + "that all file/directory ACLs are bypassed and full permissions are granted. User must also have " + "required RBAC permission."))); + customization.getClass("com.azure.storage.file.share.models", "NfsFileType") + .customizeAst(ast -> ast.getClassByName("NfsFileType").ifPresent(clazz -> clazz.setJavadocComment( + "Type of the file.\n\n" + + "This enumeration represents the type of a file item in Azure Files shares. " + + "The file type is populated for all item types in both SMB and NFS-enabled shares.\n\n" + + "@see ShareFileItem#getFileType()"))); + updateImplToMapInternalException(customization.getPackage("com.azure.storage.file.share.implementation")); } From 960ae5fee0e9eb4344c7f1fcfacc4406984a4373 Mon Sep 17 00:00:00 2001 From: browndav Date: Fri, 7 Aug 2026 12:33:01 -0400 Subject: [PATCH 2/4] revert revert of nfsv2 --- .../com/azure/storage/file/share/models/NfsFileType.java | 4 ++-- .../swagger/src/main/java/ShareStorageCustomization.java | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java index 5b9bb48b884e..75051b75a5bd 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java @@ -9,8 +9,8 @@ /** * Type of the file. - * - * This enumeration represents the type of a file item in Azure Files shares. The file type is populated for all item + *

+ * This enumeration represents the type of file item in Azure Files shares. The file type is populated for all item * types in both SMB and NFS-enabled shares. * * @see ShareFileItem#getFileType() diff --git a/sdk/storage/azure-storage-file-share/swagger/src/main/java/ShareStorageCustomization.java b/sdk/storage/azure-storage-file-share/swagger/src/main/java/ShareStorageCustomization.java index 62739fbb9905..e106aa49f068 100644 --- a/sdk/storage/azure-storage-file-share/swagger/src/main/java/ShareStorageCustomization.java +++ b/sdk/storage/azure-storage-file-share/swagger/src/main/java/ShareStorageCustomization.java @@ -34,8 +34,9 @@ public void customize(LibraryCustomization customization, Logger logger) { customization.getClass("com.azure.storage.file.share.models", "NfsFileType") .customizeAst(ast -> ast.getClassByName("NfsFileType").ifPresent(clazz -> clazz.setJavadocComment( - "Type of the file.\n\n" - + "This enumeration represents the type of a file item in Azure Files shares. " + + "Type of the file.\n

\n" + + "This enumeration represents the type of file item in Azure Files shares. " + "The file type is populated for all item types in both SMB and NFS-enabled shares.\n\n" + "@see ShareFileItem#getFileType()"))); From 2d3f16803a617e45195328c6516029f1b1dc0c94 Mon Sep 17 00:00:00 2001 From: browndav Date: Fri, 7 Aug 2026 23:41:42 -0400 Subject: [PATCH 3/4] add recordings --- sdk/storage/azure-storage-file-share/assets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-file-share/assets.json b/sdk/storage/azure-storage-file-share/assets.json index 2096399e6a76..eabc0bb2c022 100644 --- a/sdk/storage/azure-storage-file-share/assets.json +++ b/sdk/storage/azure-storage-file-share/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-file-share", - "Tag": "java/storage/azure-storage-file-share_1e9eb49640" + "Tag": "java/storage/azure-storage-file-share_741d1f4fbd" } From 739fe201c88fd80f9b6c9090a2c5fe20811a722a Mon Sep 17 00:00:00 2001 From: browndav Date: Fri, 7 Aug 2026 23:58:15 -0400 Subject: [PATCH 4/4] fix javadoc tag --- .../java/com/azure/storage/file/share/models/NfsFileType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java index 75051b75a5bd..407f7e3f9271 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/models/NfsFileType.java @@ -9,7 +9,7 @@ /** * Type of the file. - *

+ *

* This enumeration represents the type of file item in Azure Files shares. The file type is populated for all item * types in both SMB and NFS-enabled shares. *