func read()

in Sources/Foundation/NSURL.swift [1174:1459]


    func read(_ keys: [URLResourceKey], for url: NSURL) throws -> [URLResourceKey: Any?] {
        var result: [URLResourceKey: Any?] = [:]
        
        let fm = FileManager.default
        let path = url.path ?? ""
        
        // Memoized access to attributes:
        
        var fileAttributesStorage: [FileAttributeKey: Any]? = nil
        func attributes() throws -> [FileAttributeKey: Any] {
            if let storage = fileAttributesStorage {
                return storage
            } else {
                let storage = try fm._attributesOfItem(atPath: path, includingPrivateAttributes: true)
                fileAttributesStorage = storage
                return storage
            }
        }
        func attribute(_ fileAttributeKey: FileAttributeKey) throws -> Any? {
            let attributeValues = try attributes()
            return attributeValues[fileAttributeKey]
        }
        
        // Memoized access to lstat:
        
        var urlStatStorage: stat?
        func urlStat() throws -> stat {
            if let storage = urlStatStorage {
                return storage
            } else {
                let storage = try fm._lstatFile(atPath: path)
                urlStatStorage = storage
                return storage
            }
        }
        
        // Memoized access to volume URLs:
        
        var volumeURLsStorage: [URL]?
        var volumeURLs: [URL] {
            if let storage = volumeURLsStorage {
                return storage
            } else {
                let storage = fm.mountedVolumeURLs(includingResourceValuesForKeys: nil) ?? []
                volumeURLsStorage = storage
                return storage
            }
        }
        
        var volumeAttributesStorage: [FileAttributeKey: Any]?
        var blockSizeStorage: UInt64?
        func volumeAttributes() throws -> [FileAttributeKey: Any] {
            if let storage = volumeAttributesStorage {
                return storage
            } else {
                let (storage, block) = try fm._attributesOfFileSystemIncludingBlockSize(forPath: path)
                volumeAttributesStorage = storage
                blockSizeStorage = block
                return storage
            }
        }
        func blockSize() throws -> UInt64? {
            _ = try volumeAttributes()
            return blockSizeStorage
        }
        func volumeAttribute(_ fileAttributeKey: FileAttributeKey) throws -> Any? {
            let attributeValues = try volumeAttributes()
            return attributeValues[fileAttributeKey]
        }
        
        var volumeURLStorage: (searched: Bool, url: URL?)?
        func volumeURL() throws -> URL? {
            if let url = volumeURLStorage {
                return url.url
            }
            
            var foundURL: URL?
            
            for volumeURL in volumeURLs {
                var relationship: FileManager.URLRelationship = .other
                try fm.getRelationship(&relationship, ofDirectoryAt: volumeURL, toItemAt: url._swiftObject)
                if relationship == .same || relationship == .contains {
                    foundURL = volumeURL
                    break
                }
            }
            
            volumeURLStorage = (searched: true, url: foundURL)
            return foundURL
        }
        
        for key in keys {
            switch key {
            case .nameKey:
                result[key] = url.lastPathComponent
            case .localizedNameKey:
                result[key] = fm.displayName(atPath: path)
            case .isRegularFileKey:
                result[key] = try attribute(.type) as? FileAttributeType == FileAttributeType.typeRegular
            case .isDirectoryKey:
                result[key] = try attribute(.type) as? FileAttributeType == FileAttributeType.typeDirectory
            case .isSymbolicLinkKey:
                result[key] = try attribute(.type) as? FileAttributeType == FileAttributeType.typeSymbolicLink
            case .isVolumeKey:
                result[key] = volumeURLs.contains(url._swiftObject)
            case .isPackageKey:
                result[key] = try attribute(.type) as? FileAttributeType == FileAttributeType.typeDirectory && url.pathExtension != nil && url.pathExtension != ""
            case .isApplicationKey:
                #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
                result[key] = try attribute(.type) as? FileAttributeType == FileAttributeType.typeDirectory && url.pathExtension == "app"
                #else
                result[key] = false
                #endif
            case .applicationIsScriptableKey:
                // Not supported.
                break
            case .isSystemImmutableKey:
                result[key] = try attribute(._systemImmutable) as? Bool == true
            case .isUserImmutableKey:
                result[key] = try attribute(._userImmutable) as? Bool == true
            case .isHiddenKey:
                result[key] = try attribute(._hidden) as? Bool == true
            case .hasHiddenExtensionKey:
                result[key] = false // Most OSes do not have a way to record this.
            case .creationDateKey:
                result[key] = try attribute(.creationDate)
            case .contentAccessDateKey:
                result[key] = try attribute(._accessDate)
            case .contentModificationDateKey:
                result[key] = try attribute(.modificationDate)
            case .attributeModificationDateKey:
                // We do not support this in a cross-platform manner.
                break
            case .linkCountKey:
                result[key] = Int(try urlStat().st_nlink)
            case .parentDirectoryURLKey:
                result[key] = url.deletingLastPathComponent
            case .volumeURLKey:
                result[key] = try volumeURL()
                
            case .fileResourceIdentifierKey:
                result[key] = _URLFileResourceIdentifier(path: path, inode: Int(try urlStat().st_ino), volumeIdentifier: Int(try urlStat().st_dev))
                
            case .volumeIdentifierKey:
                result[key] = try volumeAttribute(.systemNumber)
                
            case .preferredIOBlockSizeKey:
                result[key] = try blockSize()
                
            case .isReadableKey:
                result[key] = fm.isReadableFile(atPath: path)
            case .isWritableKey:
                result[key] = fm.isWritableFile(atPath: path)
            case .isExecutableKey:
                result[key] = fm.isExecutableFile(atPath: path)
            case .pathKey:
                result[key] = url.path
            case .canonicalPathKey:
                result[key] = try fm._canonicalizedPath(toFileAtPath: path)
            case .fileResourceTypeKey:
                result[key] = try attribute(.type)
            case .totalFileSizeKey: fallthrough // FIXME: This should add the size of any metadata.
            case .fileSizeKey:
                result[key] = try attribute(.size)
            case .totalFileAllocatedSizeKey: fallthrough // FIXME: This should add the size of any metadata.
            case .fileAllocatedSizeKey:
#if !os(Windows)
                let stat = try urlStat()
                result[key] = Int(stat.st_blocks) * Int(stat.st_blksize)
#endif
            case .isAliasFileKey:
                // swift-corelibs-foundation does not support aliases and bookmarks.
                break
            case .volumeLocalizedFormatDescriptionKey:
                // FIXME: This should have different names for different kinds of volumes, and be localized.
                result[key] = "Volume"
            case .volumeTotalCapacityKey:
                result[key] = try volumeAttribute(.systemSize)
            case .volumeAvailableCapacityKey:
                result[key] = try volumeAttribute(.systemFreeSize)
            case .volumeResourceCountKey:
                result[key] = try volumeAttribute(.systemFileNumber)

            // FIXME: swift-corelibs-foundation does not currently support querying this kind of filesystem information. We return reasonable assumptions for now, with the understanding that by noting support we are encouraging the application to try performing corresponding I/O operations (and handle those errors, which they already must) instead. Where those keys would inform I/O decisions that are not single operations, we assume conservatively.
            case .volumeSupportsPersistentIDsKey:
                result[key] = false
            case .volumeSupportsSymbolicLinksKey:
                result[key] = true
            case .volumeSupportsHardLinksKey:
                result[key] = true
            case .volumeSupportsJournalingKey:
                result[key] = false
            case .volumeIsJournalingKey:
                result[key] = false
            case .volumeSupportsSparseFilesKey:
                result[key] = false
            case .volumeSupportsZeroRunsKey:
                result[key] = false
            case .volumeSupportsRootDirectoryDatesKey:
                result[key] = true
            case .volumeSupportsVolumeSizesKey:
                result[key] = true
            case .volumeSupportsRenamingKey:
                result[key] = true
            case .volumeSupportsAdvisoryFileLockingKey:
                result[key] = false
            case .volumeSupportsExtendedSecurityKey:
                result[key] = false
            case .volumeIsBrowsableKey:
                result[key] = true
            case .volumeIsReadOnlyKey:
                result[key] = false
            case .volumeCreationDateKey:
                result[key] = try volumeAttribute(.creationDate)
            case .volumeURLForRemountingKey:
                result[key] = nil
            case .volumeMaximumFileSizeKey: fallthrough
            case .volumeIsEjectableKey: fallthrough
            case .volumeIsRemovableKey: fallthrough
            case .volumeIsInternalKey: fallthrough
            case .volumeIsAutomountedKey: fallthrough
            case .volumeIsLocalKey: fallthrough
            case .volumeSupportsCaseSensitiveNamesKey: fallthrough
            case .volumeUUIDStringKey: fallthrough
            case .volumeIsEncryptedKey: fallthrough
            case .volumeSupportsCompressionKey: fallthrough
            case .volumeSupportsFileCloningKey: fallthrough
            case .volumeSupportsSwapRenamingKey: fallthrough
            case .volumeSupportsExclusiveRenamingKey: fallthrough
            case .volumeSupportsCasePreservedNamesKey:
                // Whatever we assume here, we may make problems for the implementation that relies on them; we just don't answer for now.
                break
                
            case .volumeNameKey:
                if let url = try volumeURL() {
                    result[key] = url.lastPathComponent
                }
            case .volumeLocalizedNameKey:
                if let url = try volumeURL() {
                    result[key] = fm.displayName(atPath: url.path)
                }
                
            case .volumeIsRootFileSystemKey:
                #if !os(Windows)
                if let url = try volumeURL() {
                    result[key] = url.path == "/"
                }
                #endif
                
            case .isUbiquitousItemKey: fallthrough
            case .ubiquitousItemHasUnresolvedConflictsKey: fallthrough
            case .ubiquitousItemIsDownloadingKey: fallthrough
            case .ubiquitousItemIsUploadedKey: fallthrough
            case .ubiquitousItemIsUploadingKey: fallthrough
            case .ubiquitousItemDownloadingStatusKey: fallthrough
            case .ubiquitousItemDownloadingErrorKey: fallthrough
            case .ubiquitousItemUploadingErrorKey: fallthrough
            case .ubiquitousItemDownloadRequestedKey: fallthrough
            case .ubiquitousItemContainerDisplayNameKey: fallthrough
            case .fileSecurityKey: fallthrough
            case .isExcludedFromBackupKey: fallthrough
            case .tagNamesKey: fallthrough
            case .typeIdentifierKey: fallthrough
            case .localizedTypeDescriptionKey: fallthrough
            case .labelNumberKey: fallthrough
            case .labelColorKey: fallthrough
            case .localizedLabelKey: fallthrough
            case .effectiveIconKey: fallthrough
            case .isMountTriggerKey: fallthrough
            case .generationIdentifierKey: fallthrough
            case .documentIdentifierKey: fallthrough
            case .addedToDirectoryDateKey: fallthrough
            case .quarantinePropertiesKey: fallthrough
            case .thumbnailDictionaryKey: fallthrough
            case .thumbnailKey: fallthrough
            case .customIconKey:
                // Not supported outside of Apple OSes.
                break
                
            default:
                break
            }
        }
        
        return result
    }