diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index da1c1e7ecd..f32e5aa2c0 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -181,24 +181,6 @@ extension FileManager { return (attributes: result, blockSize: finalBlockSize) #endif // os(WASI) } - - /* destinationOfSymbolicLinkAtPath:error: returns a String containing the path of the item pointed at by the symlink specified by 'path'. If this method returns 'nil', an NSError will be thrown. - - This method replaces pathContentOfSymbolicLinkAtPath: - */ - internal func _destinationOfSymbolicLink(atPath path: String) throws -> String { - let bufferSize = Int(PATH_MAX + 1) - let buffer = try [Int8](unsafeUninitializedCapacity: bufferSize) { buffer, initializedCount in - let len = try _fileSystemRepresentation(withPath: path) { (path) -> Int in - return readlink(path, buffer.baseAddress!, bufferSize) - } - guard len >= 0 else { - throw _NSErrorWithErrno(errno, reading: true, path: path) - } - initializedCount = len - } - return self.string(withFileSystemRepresentation: buffer, length: buffer.count) - } internal func _recursiveDestinationOfSymbolicLink(atPath path: String) throws -> String { #if os(WASI) @@ -207,7 +189,7 @@ extension FileManager { throw _NSErrorWithErrno(ENOTSUP, reading: true, path: path) #else // Throw error if path is not a symbolic link: - let path = try _destinationOfSymbolicLink(atPath: path) + let path = try destinationOfSymbolicLink(atPath: path) let bufSize = Int(PATH_MAX + 1) var buf = [Int8](repeating: 0, count: bufSize) diff --git a/Sources/Foundation/FileManager+Win32.swift b/Sources/Foundation/FileManager+Win32.swift index 0ceedd13fe..f53fe3995b 100644 --- a/Sources/Foundation/FileManager+Win32.swift +++ b/Sources/Foundation/FileManager+Win32.swift @@ -102,21 +102,6 @@ private func walk(directory path: URL, _ body: (String, DWORD) throws -> Void) r } } -internal func joinPath(prefix: String, suffix: String) -> String { - var pszPath: PWSTR? - - guard !prefix.isEmpty else { return suffix } - guard !suffix.isEmpty else { return prefix } - - _ = try! FileManager.default._fileSystemRepresentation(withPath: prefix, andPath: suffix) { - PathAllocCombine($0, $1, ULONG(PATHCCH_ALLOW_LONG_PATHS.rawValue), &pszPath) - } - - let path: String = String(decodingCString: pszPath!, as: UTF16.self) - LocalFree(pszPath) - return path -} - extension FileManager { internal func _mountedVolumeURLs(includingResourceValuesForKeys propertyKeys: [URLResourceKey]?, options: VolumeEnumerationOptions = []) -> [URL]? { var urls: [URL] = [] @@ -168,145 +153,11 @@ extension FileManager { } internal func _attributesOfFileSystemIncludingBlockSize(forPath path: String) throws -> (attributes: [FileAttributeKey : Any], blockSize: UInt64?) { - return (attributes: try _attributesOfFileSystem(forPath: path), blockSize: nil) - } - - internal func _attributesOfFileSystem(forPath path: String) throws -> [FileAttributeKey : Any] { - var result: [FileAttributeKey:Any] = [:] - - try FileManager.default._fileSystemRepresentation(withPath: path) { - let dwLength: DWORD = GetFullPathNameW($0, 0, nil, nil) - guard dwLength > 0 else { - throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path]) - } - - var szVolumePath: [WCHAR] = Array(repeating: 0, count: Int(dwLength + 1)) - guard GetVolumePathNameW($0, &szVolumePath, dwLength) else { - throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path]) - } - - var liTotal: ULARGE_INTEGER = ULARGE_INTEGER() - var liFree: ULARGE_INTEGER = ULARGE_INTEGER() - guard GetDiskFreeSpaceExW(&szVolumePath, nil, &liTotal, &liFree) else { - throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path]) - } - - let hr: HRESULT = PathCchStripToRoot(&szVolumePath, szVolumePath.count) - guard hr == S_OK || hr == S_FALSE else { - throw _NSErrorWithWindowsError(DWORD(hr & 0xffff), reading: true, paths: [path]) - } - - var volumeSerialNumber: DWORD = 0 - guard GetVolumeInformationW(&szVolumePath, nil, 0, &volumeSerialNumber, nil, nil, nil, 0) else { - throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path]) - } - - result[.systemSize] = NSNumber(value: liTotal.QuadPart) - result[.systemFreeSize] = NSNumber(value: liFree.QuadPart) - result[.systemNumber] = NSNumber(value: volumeSerialNumber) - // FIXME(compnerd): what about .systemNodes, .systemFreeNodes? - } - return result - } - - internal func _destinationOfSymbolicLink(atPath path: String) throws -> String { - let faAttributes = try windowsFileAttributes(atPath: path) - guard faAttributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT else { - throw _NSErrorWithWindowsError(DWORD(ERROR_BAD_ARGUMENTS), reading: false) - } - - let handle: HANDLE = try FileManager.default._fileSystemRepresentation(withPath: path) { - CreateFileW($0, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nil, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, - nil) - } - if handle == INVALID_HANDLE_VALUE { - throw _NSErrorWithWindowsError(GetLastError(), reading: true) - } - defer { CloseHandle(handle) } - - // Since REPARSE_DATA_BUFFER ends with an arbitrarily long buffer, we - // have to manually get the path buffer out of it since binding it to a - // type will truncate the path buffer. - // - // 20 is the sum of the offsets of: - // ULONG ReparseTag - // USHORT ReparseDataLength - // USHORT Reserved - // USHORT SubstituteNameOffset - // USHORT SubstituteNameLength - // USHORT PrintNameOffset - // USHORT PrintNameLength - // ULONG Flags (Symlink only) - let symLinkPathBufferOffset = 20 // 4 + 2 + 2 + 2 + 2 + 2 + 2 + 4 - let mountPointPathBufferOffset = 16 // 4 + 2 + 2 + 2 + 2 + 2 + 2 - let buff = UnsafeMutableRawBufferPointer.allocate(byteCount: Int(MAXIMUM_REPARSE_DATA_BUFFER_SIZE), - alignment: 8) - - guard let buffBase = buff.baseAddress else { - throw _NSErrorWithWindowsError(DWORD(ERROR_INVALID_DATA), reading: false) - } - - var bytesWritten: DWORD = 0 - guard DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, nil, 0, - buffBase, DWORD(MAXIMUM_REPARSE_DATA_BUFFER_SIZE), - &bytesWritten, nil) else { - throw _NSErrorWithWindowsError(GetLastError(), reading: true) - } - - guard bytesWritten >= MemoryLayout.size else { - throw _NSErrorWithWindowsError(DWORD(ERROR_INVALID_DATA), reading: false) - } - - let bound = buff.bindMemory(to: REPARSE_DATA_BUFFER.self) - guard let reparseDataBuffer = bound.first else { - throw _NSErrorWithWindowsError(DWORD(ERROR_INVALID_DATA), reading: false) - } - - guard reparseDataBuffer.ReparseTag == IO_REPARSE_TAG_SYMLINK - || reparseDataBuffer.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT else { - throw _NSErrorWithWindowsError(DWORD(ERROR_BAD_ARGUMENTS), reading: false) - } - - let pathBufferPtr: UnsafeMutableRawPointer - let substituteNameBytes: Int - let substituteNameOffset: Int - switch reparseDataBuffer.ReparseTag { - case IO_REPARSE_TAG_SYMLINK: - pathBufferPtr = buffBase + symLinkPathBufferOffset - substituteNameBytes = Int(reparseDataBuffer.SymbolicLinkReparseBuffer.SubstituteNameLength) - substituteNameOffset = Int(reparseDataBuffer.SymbolicLinkReparseBuffer.SubstituteNameOffset) - case IO_REPARSE_TAG_MOUNT_POINT: - pathBufferPtr = buffBase + mountPointPathBufferOffset - substituteNameBytes = Int(reparseDataBuffer.MountPointReparseBuffer.SubstituteNameLength) - substituteNameOffset = Int(reparseDataBuffer.MountPointReparseBuffer.SubstituteNameOffset) - default: - throw _NSErrorWithWindowsError(DWORD(ERROR_BAD_ARGUMENTS), reading: false) - } - - guard substituteNameBytes + substituteNameOffset <= bytesWritten else { - throw _NSErrorWithWindowsError(DWORD(ERROR_INVALID_DATA), reading: false) - } - - let substituteNameBuff = Data(bytes: pathBufferPtr + substituteNameOffset, count: substituteNameBytes) - guard var substitutePath = String(data: substituteNameBuff, encoding: .utf16LittleEndian) else { - throw _NSErrorWithWindowsError(DWORD(ERROR_INVALID_DATA), reading: false) - } - - // Canonicalize the NT Object Manager Path to the DOS style path - // instead. Unfortunately, there is no nice API which can allow us to - // do this in a guranteed way. - let kObjectManagerPrefix = "\\??\\" - if substitutePath.hasPrefix(kObjectManagerPrefix) { - substitutePath = String(substitutePath.dropFirst(kObjectManagerPrefix.count)) - } - return substitutePath + return (attributes: try attributesOfFileSystem(forPath: path), blockSize: nil) } private func _realpath(_ path: String) -> String { - return (try? _destinationOfSymbolicLink(atPath: path)) ?? path + return (try? destinationOfSymbolicLink(atPath: path)) ?? path } internal func _recursiveDestinationOfSymbolicLink(atPath path: String) throws -> String { diff --git a/Sources/Foundation/FileManager.swift b/Sources/Foundation/FileManager.swift index 29c934b90d..64f5da9d76 100644 --- a/Sources/Foundation/FileManager.swift +++ b/Sources/Foundation/FileManager.swift @@ -9,9 +9,7 @@ #if !canImport(Darwin) && !os(FreeBSD) // The values do not matter as long as they are nonzero. -fileprivate let UF_IMMUTABLE: Int32 = 1 fileprivate let SF_IMMUTABLE: Int32 = 1 -fileprivate let UF_APPEND: Int32 = 1 fileprivate let UF_HIDDEN: Int32 = 1 #endif @@ -271,212 +269,87 @@ extension FileManager { try getRelationship(outRelationship, ofDirectoryAt: try self.url(for: directory, in: actualMask, appropriateFor: url, create: false), toItemAt: url) } - internal func _setAttributes(_ attributeValues: [FileAttributeKey : Any], ofItemAtPath path: String, includingPrivateAttributes: Bool = false) throws { - var attributes = Set(attributeValues.keys) - if !includingPrivateAttributes { - attributes.formIntersection(FileAttributeKey.allPublicKeys) - } + internal func _setAttributesIncludingPrivate(_ values: [FileAttributeKey : Any], ofItemAtPath path: String) throws { + // Call through to FoundationEssentials to handle all public attributes + try self.setAttributes(values, ofItemAtPath: path) - try _fileSystemRepresentation(withPath: path) { fsRep in - var flagsToSet: UInt32 = 0 - var flagsToUnset: UInt32 = 0 - - var newModificationDate: Date? - var newAccessDate: Date? - - for attribute in attributes { - - func prepareToSetOrUnsetFlag(_ flag: Int32) { - guard let shouldSet = attributeValues[attribute] as? Bool else { - fatalError("Can't set \(attribute) to \(attributeValues[attribute] as Any?)") - } - - if shouldSet { - flagsToSet |= UInt32(flag) - } else { - flagsToUnset |= UInt32(flag) - } - } - - switch attribute { - case .posixPermissions: -#if os(WASI) - // WASI does not have permission concept - throw _NSErrorWithErrno(ENOTSUP, reading: false, path: path) -#else - guard let number = attributeValues[attribute] as? NSNumber else { - fatalError("Can't set file permissions to \(attributeValues[attribute] as Any?)") - } - #if os(macOS) || os(iOS) - let modeT = number.uint16Value - #elseif os(Linux) || os(Android) || os(Windows) || os(OpenBSD) - let modeT = number.uint32Value - #endif -#if os(Windows) - let result = _wchmod(fsRep, mode_t(modeT)) -#else - let result = chmod(fsRep, mode_t(modeT)) -#endif - guard result == 0 else { - throw _NSErrorWithErrno(errno, reading: false, path: path) - } -#endif // os(WASI) - - case .modificationDate: fallthrough - case ._accessDate: - guard let providedDate = attributeValues[attribute] as? Date else { - fatalError("Can't set \(attribute) to \(attributeValues[attribute] as Any?)") - } - - if attribute == .modificationDate { - newModificationDate = providedDate - } else if attribute == ._accessDate { - newAccessDate = providedDate - } - - case .immutable: fallthrough - case ._userImmutable: - prepareToSetOrUnsetFlag(UF_IMMUTABLE) - - case ._systemImmutable: - prepareToSetOrUnsetFlag(SF_IMMUTABLE) - - case .appendOnly: - prepareToSetOrUnsetFlag(UF_APPEND) - - case ._hidden: + // Handle private attributes + var flagsToSet: UInt32 = 0 + var flagsToUnset: UInt32 = 0 + + if let isHidden = values[._hidden] as? Bool { #if os(Windows) - let attrs = try windowsFileAttributes(atPath: path).dwFileAttributes - guard let isHidden = attributeValues[attribute] as? Bool else { - fatalError("Can't set \(attribute) to \(attributeValues[attribute] as Any?)") - } - - let hiddenAttrs = isHidden - ? attrs | FILE_ATTRIBUTE_HIDDEN - : attrs & ~FILE_ATTRIBUTE_HIDDEN - guard SetFileAttributesW(fsRep, hiddenAttrs) else { - throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [path]) - } + let attrs = try windowsFileAttributes(atPath: path).dwFileAttributes + let hiddenAttrs = isHidden + ? attrs | FILE_ATTRIBUTE_HIDDEN + : attrs & ~FILE_ATTRIBUTE_HIDDEN + guard SetFileAttributesW(fsRep, hiddenAttrs) else { + throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [path]) + } #else - prepareToSetOrUnsetFlag(UF_HIDDEN) + if isHidden { + flagsToSet |= UInt32(UF_HIDDEN) + } else { + flagsToUnset |= UInt32(UF_HIDDEN) + } #endif - - // FIXME: On Darwin, these can be set with setattrlist(); and of course chown/chgrp on other OSes. - case .ownerAccountID: fallthrough - case .ownerAccountName: fallthrough - case .groupOwnerAccountID: fallthrough - case .groupOwnerAccountName: fallthrough - case .creationDate: fallthrough - case .extensionHidden: - // Setting these attributes is unsupported (for now) in swift-corelibs-foundation - throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileWriteUnknown.rawValue) - - default: - break - } + } + + if let isSystemImmutable = values[._systemImmutable] as? Bool { + if isSystemImmutable { + flagsToSet |= UInt32(SF_IMMUTABLE) + } else { + flagsToUnset |= UInt32(SF_IMMUTABLE) } - - if flagsToSet != 0 || flagsToUnset != 0 { - #if !canImport(Darwin) && !os(FreeBSD) - // Setting these attributes is unsupported on these platforms. - throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileWriteUnknown.rawValue) - #else - let stat = try _lstatFile(atPath: path, withFileSystemRepresentation: fsRep) - var flags = stat.st_flags - flags |= flagsToSet - flags &= ~flagsToUnset - - guard chflags(fsRep, flags) == 0 else { - throw _NSErrorWithErrno(errno, reading: false, path: path) - } - #endif + } + + if flagsToSet != 0 || flagsToUnset != 0 { +#if !canImport(Darwin) && !os(FreeBSD) + // Setting these attributes is unsupported on these platforms. + throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileWriteUnknown.rawValue) +#else + let stat = try _lstatFile(atPath: path, withFileSystemRepresentation: fsRep) + var flags = stat.st_flags + flags |= flagsToSet + flags &= ~flagsToUnset + + guard chflags(fsRep, flags) == 0 else { + throw _NSErrorWithErrno(errno, reading: false, path: path) } - - if newModificationDate != nil || newAccessDate != nil { - // Set dates as the very last step, to avoid other operations overwriting these values: - try _updateTimes(atPath: path, withFileSystemRepresentation: fsRep, accessTime: newAccessDate, modificationTime: newModificationDate) +#endif + } + + let accessDate = values[._accessDate] as? Date + let modificationDate = values[.modificationDate] as? Date + + if accessDate != nil || modificationDate != nil { + // Set dates as the very last step, to avoid other operations overwriting these values + // Also re-set modification date here in case setting flags above changed it + try _fileSystemRepresentation(withPath: path) { + try _updateTimes(atPath: path, withFileSystemRepresentation: $0, accessTime: accessDate, modificationTime: modificationDate) } } } - internal func _attributesOfItem(atPath path: String, includingPrivateAttributes: Bool = false) throws -> [FileAttributeKey: Any] { - var result: [FileAttributeKey:Any] = [:] - + internal func _attributesOfItemIncludingPrivate(atPath path: String) throws -> [FileAttributeKey: Any] { + // Call to FoundationEssentials to get all public attributes + var result = try self.attributesOfItem(atPath: path) + #if os(Linux) - let (s, creationDate) = try _statxFile(atPath: path) - result[.creationDate] = creationDate + let (s, _) = try _statxFile(atPath: path) #elseif os(Windows) - let (s, ino) = try _statxFile(atPath: path) - result[.creationDate] = s.creationDate + let (s, _) = try _statxFile(atPath: path) #else let s = try _lstatFile(atPath: path) - result[.creationDate] = s.creationDate #endif - - result[.size] = NSNumber(value: UInt64(s.st_size)) - - result[.modificationDate] = s.lastModificationDate - if includingPrivateAttributes { - result[._accessDate] = s.lastAccessDate - } - - result[.posixPermissions] = NSNumber(value: _filePermissionsMask(mode: UInt32(s.st_mode))) - result[.referenceCount] = NSNumber(value: UInt64(s.st_nlink)) - result[.systemNumber] = NSNumber(value: UInt64(s.st_dev)) -#if os(Windows) - result[.systemFileNumber] = NSNumber(value: UInt64(ino)) -#else - result[.systemFileNumber] = NSNumber(value: UInt64(s.st_ino)) -#endif - -#if os(Windows) - result[.deviceIdentifier] = NSNumber(value: UInt64(s.st_rdev)) - let attributes = try windowsFileAttributes(atPath: path) - let type = FileAttributeType(attributes: attributes, atPath: path) -#elseif os(WASI) - let type = FileAttributeType(statMode: mode_t(s.st_mode)) -#else - if let pwd = getpwuid(s.st_uid), pwd.pointee.pw_name != nil { - let name = String(cString: pwd.pointee.pw_name) - result[.ownerAccountName] = name - } - - if let grd = getgrgid(s.st_gid), grd.pointee.gr_name != nil { - let name = String(cString: grd.pointee.gr_name) - result[.groupOwnerAccountName] = name - } - - let type = FileAttributeType(statMode: mode_t(s.st_mode)) -#endif - result[.type] = type - - if type == .typeBlockSpecial || type == .typeCharacterSpecial { - result[.deviceIdentifier] = NSNumber(value: UInt64(s.st_rdev)) - } - -#if canImport(Darwin) - if (s.st_flags & UInt32(UF_IMMUTABLE | SF_IMMUTABLE)) != 0 { - result[.immutable] = NSNumber(value: true) - } - - if includingPrivateAttributes { - result[._userImmutable] = (s.st_flags & UInt32(UF_IMMUTABLE)) != 0 - result[._systemImmutable] = (s.st_flags & UInt32(SF_IMMUTABLE)) != 0 - result[._hidden] = (s.st_flags & UInt32(UF_HIDDEN)) != 0 - } + result[._accessDate] = s.lastAccessDate - if (s.st_flags & UInt32(UF_APPEND | SF_APPEND)) != 0 { - result[.appendOnly] = NSNumber(value: true) - } -#endif - -#if os(Windows) - let attrs = attributes.dwFileAttributes - result[._hidden] = attrs & FILE_ATTRIBUTE_HIDDEN != 0 +#if canImport(Darwin) + result[._systemImmutable] = (s.st_flags & UInt32(SF_IMMUTABLE)) != 0 + result[._hidden] = (s.st_flags & UInt32(UF_HIDDEN)) != 0 +#elseif os(Windows) + result[._hidden] = try windowsFileAttributes(atPath: path).dwFileAttributes & FILE_ATTRIBUTE_HIDDEN != 0 #endif - result[.ownerAccountID] = NSNumber(value: UInt64(s.st_uid)) - result[.groupOwnerAccountID] = NSNumber(value: UInt64(s.st_gid)) - return result } @@ -493,21 +366,6 @@ extension FileManager { } return self.fileExists(atPath: path, isDirectory: &isDir) } - - internal func _filePermissionsMask(mode : UInt32) -> Int { -#if os(Windows) - return Int(mode & ~UInt32(ucrt.S_IFMT)) -#elseif canImport(Darwin) - return Int(mode & ~UInt32(S_IFMT)) -#else - return Int(mode & ~S_IFMT) -#endif - } - - internal func _permissionsOfItem(atPath path: String) throws -> Int { - let fileInfo = try _lstatFile(atPath: path) - return _filePermissionsMask(mode: UInt32(fileInfo.st_mode)) - } internal func _overridingDisplayNameLanguages(with languages: [String], within body: () throws -> T) rethrows -> T { let old = _overriddenDisplayNameLanguages @@ -742,62 +600,10 @@ extension FileAttributeKey { // They are intended for use by NSURL's resource keys. internal static let _systemImmutable = FileAttributeKey(rawValue: "org.swift.Foundation.FileAttributeKey._systemImmutable") - internal static let _userImmutable = FileAttributeKey(rawValue: "org.swift.Foundation.FileAttributeKey._userImmutable") internal static let _hidden = FileAttributeKey(rawValue: "org.swift.Foundation.FileAttributeKey._hidden") internal static let _accessDate = FileAttributeKey(rawValue: "org.swift.Foundation.FileAttributeKey._accessDate") } -extension FileAttributeType { -#if os(Windows) - internal init(attributes: WIN32_FILE_ATTRIBUTE_DATA, atPath path: String) { - if attributes.dwFileAttributes & FILE_ATTRIBUTE_DEVICE == FILE_ATTRIBUTE_DEVICE { - self = .typeCharacterSpecial - } else if attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT { - // A reparse point may or may not actually be a symbolic link, we need to read the reparse tag - let handle: HANDLE = (try? FileManager.default._fileSystemRepresentation(withPath: path) { - CreateFileW($0, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nil, - OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, - nil) - }) ?? INVALID_HANDLE_VALUE - if handle == INVALID_HANDLE_VALUE { - self = .typeUnknown - return - } - defer { CloseHandle(handle) } - var tagInfo = FILE_ATTRIBUTE_TAG_INFO() - if !GetFileInformationByHandleEx(handle, FileAttributeTagInfo, &tagInfo, - DWORD(MemoryLayout.size)) { - self = .typeUnknown - return - } - self = tagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK ? .typeSymbolicLink : .typeRegular - } else if attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY { - // Note: Since Windows marks directory symlinks as both - // directories and reparse points, having this after the - // reparse point check implicitly encodes Windows - // directory symlinks as not directories, which matches - // POSIX behavior. - self = .typeDirectory - } else { - self = .typeRegular - } - } -#else - internal init(statMode: mode_t) { - switch statMode & S_IFMT { - case S_IFCHR: self = .typeCharacterSpecial - case S_IFDIR: self = .typeDirectory - case S_IFBLK: self = .typeBlockSpecial - case S_IFREG: self = .typeRegular - case S_IFLNK: self = .typeSymbolicLink - case S_IFSOCK: self = .typeSocket - default: self = .typeUnknown - } - } -#endif -} - extension FileManager { open class DirectoryEnumerator : NSEnumerator { diff --git a/Sources/Foundation/NSData.swift b/Sources/Foundation/NSData.swift index b2e4095882..bb0ff92b6a 100644 --- a/Sources/Foundation/NSData.swift +++ b/Sources/Foundation/NSData.swift @@ -457,7 +457,7 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { } let fm = FileManager.default - let permissions = try? fm._permissionsOfItem(atPath: path) + let permissions = try? fm.attributesOfItem(atPath: path)[.posixPermissions] as? Int if writeOptionsMask.contains(.atomic) { let (newFD, auxFilePath) = try _NSCreateTemporaryFile(path) diff --git a/Sources/Foundation/NSURL.swift b/Sources/Foundation/NSURL.swift index 3b0ed15c8a..def389037f 100644 --- a/Sources/Foundation/NSURL.swift +++ b/Sources/Foundation/NSURL.swift @@ -1208,7 +1208,7 @@ fileprivate extension URLResourceValuesStorage { if let storage = fileAttributesStorage { return storage } else { - let storage = try fm._attributesOfItem(atPath: path, includingPrivateAttributes: true) + let storage = try fm._attributesOfItemIncludingPrivate(atPath: path) fileAttributesStorage = storage return storage } @@ -1314,7 +1314,7 @@ fileprivate extension URLResourceValuesStorage { case .isSystemImmutableKey: result[key] = try attribute(._systemImmutable) as? Bool == true case .isUserImmutableKey: - result[key] = try attribute(._userImmutable) as? Bool == true + result[key] = try attribute(.immutable) as? Bool == true case .isHiddenKey: result[key] = try attribute(._hidden) as? Bool == true case .hasHiddenExtensionKey: @@ -1522,7 +1522,7 @@ fileprivate extension URLResourceValuesStorage { switch key { case .isUserImmutableKey: - try prepareToSetFileAttribute(._userImmutable, value: value as? Bool) + try prepareToSetFileAttribute(.immutable, value: value as? Bool) case .isSystemImmutableKey: try prepareToSetFileAttribute(._systemImmutable, value: value as? Bool) @@ -1560,7 +1560,7 @@ fileprivate extension URLResourceValuesStorage { // _setAttributes(…) needs to figure out the correct order to apply these attributes in, so set them all together at the end. if !attributesToSet.isEmpty { - try fm._setAttributes(attributesToSet, ofItemAtPath: path, includingPrivateAttributes: true) + try fm._setAttributesIncludingPrivate(attributesToSet, ofItemAtPath: path) unsuccessfulKeys.formSymmetricDifference(keysThatSucceedBySettingAttributes) } diff --git a/Tests/Foundation/TestFileManager.swift b/Tests/Foundation/TestFileManager.swift index f7d2631641..fc2361c346 100644 --- a/Tests/Foundation/TestFileManager.swift +++ b/Tests/Foundation/TestFileManager.swift @@ -1335,7 +1335,7 @@ class TestFileManager : XCTestCase { } XCTAssertThrowsError(try fm.copyItem(atPath: "/tmp/t", toPath: "")) { let code = ($0 as? CocoaError)?.code - XCTAssertEqual(code, .fileNoSuchFile) + XCTAssertEqual(code, .fileReadNoSuchFile) } #if false @@ -1364,7 +1364,7 @@ class TestFileManager : XCTestCase { } XCTAssertThrowsError(try fm.linkItem(atPath: "/tmp/t", toPath: "")) { let code = ($0 as? CocoaError)?.code - XCTAssertEqual(code, .fileNoSuchFile) + XCTAssertEqual(code, .fileReadNoSuchFile) } XCTAssertThrowsError(try fm.createSymbolicLink(atPath: "", withDestinationPath: "")) { diff --git a/Tests/Foundation/TestNSData.swift b/Tests/Foundation/TestNSData.swift index 26e96c98d9..4ecb4eda2f 100644 --- a/Tests/Foundation/TestNSData.swift +++ b/Tests/Foundation/TestNSData.swift @@ -210,7 +210,7 @@ class TestNSData: XCTestCase { let url = URL(fileURLWithPath: NSTemporaryDirectory() + "meow") try data.write(to: url) let fileManager = FileManager.default - let permission = try fileManager._permissionsOfItem(atPath: url.path) + let permission = try fileManager.attributesOfItem(atPath: url.path)[.posixPermissions] as? Int #if canImport(Darwin) let expected = Int(S_IRUSR) | Int(S_IWUSR) | Int(S_IRGRP) | Int(S_IWGRP) | Int(S_IROTH) | Int(S_IWOTH) #else @@ -233,7 +233,7 @@ class TestNSData: XCTestCase { let url = URL(fileURLWithPath: NSTemporaryDirectory() + "meow") try data.write(to: url, options: .atomic) let fileManager = FileManager.default - let permission = try fileManager._permissionsOfItem(atPath: url.path) + let permission = try fileManager.attributesOfItem(atPath: url.path)[.posixPermissions] as? Int #if canImport(Darwin) let expected = Int(S_IRUSR) | Int(S_IWUSR) | Int(S_IRGRP) | Int(S_IWGRP) | Int(S_IROTH) | Int(S_IWOTH) #else