From 359f03ce9559f1bc6ff8c5be1bed3ea1f54c8cea Mon Sep 17 00:00:00 2001 From: Amir Abbas Mousavian Date: Thu, 17 Oct 2024 23:47:42 +0330 Subject: [PATCH] fix: Error code and description in some async methods chore: Use Swift OptionSet instead of C constants --- AMSMB2/AMSMB2.swift | 2 +- AMSMB2/Context.swift | 87 ++++++++---- AMSMB2/Directory.swift | 27 ++-- AMSMB2/Extensions.swift | 2 +- AMSMB2/FileHandle.swift | 285 +++++++++++++++++++++++++++------------- AMSMB2/Parsers.swift | 2 +- Dependencies/libsmb2 | 2 +- 7 files changed, 273 insertions(+), 134 deletions(-) diff --git a/AMSMB2/AMSMB2.swift b/AMSMB2/AMSMB2.swift index f02d8e2..90a3c0a 100644 --- a/AMSMB2/AMSMB2.swift +++ b/AMSMB2/AMSMB2.swift @@ -733,7 +733,7 @@ public class SMB2Manager: NSObject, NSSecureCoding, Codable, NSCopying, CustomRe with(completionHandler: completionHandler) { context in do { try context.unlink(path) - } catch POSIXError.ENOLINK { + } catch POSIXError.ENOLINK, POSIXError.ENETRESET { // Try to remove file as a symbolic link. try context.unlink(path, flags: O_SYMLINK) } diff --git a/AMSMB2/Context.swift b/AMSMB2/Context.swift index b9f218a..a343116 100644 --- a/AMSMB2/Context.swift +++ b/AMSMB2/Context.swift @@ -12,13 +12,13 @@ import SMB2 /// Provides synchronous operation on SMB2 final class SMB2Context: CustomDebugStringConvertible, CustomReflectable, @unchecked Sendable { - var unsafe: UnsafeMutablePointer? + var unsafeContext: UnsafeMutablePointer? private var _context_lock = NSRecursiveLock() var timeout: TimeInterval init(timeout: TimeInterval) throws { let _context = try smb2_init_context().unwrap() - self.unsafe = _context + self.unsafeContext = _context self.timeout = timeout } @@ -27,7 +27,7 @@ final class SMB2Context: CustomDebugStringConvertible, CustomReflectable, @unche try? self.disconnect() } try? withThreadSafeContext { context in - self.unsafe = nil + self.unsafeContext = nil smb2_destroy_context(context) } } @@ -39,7 +39,7 @@ final class SMB2Context: CustomDebugStringConvertible, CustomReflectable, @unche defer { _context_lock.unlock() } - return try handler(unsafe.unwrap()) + return try handler(unsafeContext.unwrap()) } public var debugDescription: String { @@ -48,7 +48,7 @@ final class SMB2Context: CustomDebugStringConvertible, CustomReflectable, @unche public var customMirror: Mirror { var c: [(label: String?, value: Any)] = [] - if unsafe != nil { + if unsafeContext != nil { c.append((label: "server", value: server!)) c.append((label: "securityMode", value: securityMode)) c.append((label: "authentication", value: authentication)) @@ -69,7 +69,7 @@ final class SMB2Context: CustomDebugStringConvertible, CustomReflectable, @unche extension SMB2Context { var workstation: String { get { - (unsafe?.pointee.workstation).map(String.init(cString:)) ?? "" + (unsafeContext?.pointee.workstation).map(String.init(cString:)) ?? "" } set { try? withThreadSafeContext { context in @@ -80,7 +80,7 @@ extension SMB2Context { var domain: String { get { - (unsafe?.pointee.domain).map(String.init(cString:)) ?? "" + (unsafeContext?.pointee.domain).map(String.init(cString:)) ?? "" } set { try? withThreadSafeContext { context in @@ -91,7 +91,7 @@ extension SMB2Context { var user: String { get { - (unsafe?.pointee.user).map(String.init(cString:)) ?? "" + (unsafeContext?.pointee.user).map(String.init(cString:)) ?? "" } set { try? withThreadSafeContext { context in @@ -102,7 +102,7 @@ extension SMB2Context { var password: String { get { - (unsafe?.pointee.password).map(String.init(cString:)) ?? "" + (unsafeContext?.pointee.password).map(String.init(cString:)) ?? "" } set { try? withThreadSafeContext { context in @@ -113,7 +113,7 @@ extension SMB2Context { var securityMode: NegotiateSigning { get { - (unsafe?.pointee.security_mode).flatMap(NegotiateSigning.init(rawValue:)) ?? [] + (unsafeContext?.pointee.security_mode).flatMap(NegotiateSigning.init(rawValue:)) ?? [] } set { try? withThreadSafeContext { context in @@ -124,7 +124,7 @@ extension SMB2Context { var seal: Bool { get { - unsafe?.pointee.seal ?? 0 != 0 + unsafeContext?.pointee.seal ?? 0 != 0 } set { try? withThreadSafeContext { context in @@ -135,7 +135,7 @@ extension SMB2Context { var authentication: Security { get { - unsafe?.pointee.sec ?? SMB2_SEC_UNDEFINED + unsafeContext?.pointee.sec ?? SMB2_SEC_UNDEFINED } set { try? withThreadSafeContext { context in @@ -145,7 +145,7 @@ extension SMB2Context { } var clientGuid: UUID? { - guard let guid = try? smb2_get_client_guid(unsafe.unwrap()) else { + guard let guid = try? smb2_get_client_guid(unsafeContext.unwrap()) else { return nil } let uuid = UnsafeRawPointer(guid).assumingMemoryBound(to: uuid_t.self).pointee @@ -153,15 +153,15 @@ extension SMB2Context { } var server: String? { - unsafe?.pointee.server.map(String.init(cString:)) + unsafeContext?.pointee.server.map(String.init(cString:)) } var share: String? { - unsafe?.pointee.share.map(String.init(cString:)) + unsafeContext?.pointee.share.map(String.init(cString:)) } var version: Version { - (unsafe?.pointee.dialect).map { Version(rawValue: UInt32($0)) } ?? .any + (unsafeContext?.pointee.dialect).map { Version(rawValue: UInt32($0)) } ?? .any } var isConnected: Bool { @@ -170,28 +170,39 @@ extension SMB2Context { var fileDescriptor: Int32 { do { - return try smb2_get_fd(unsafe.unwrap()) + return try smb2_get_fd(unsafeContext.unwrap()) } catch { return -1 } } var error: String? { - let errorStr = smb2_get_error(unsafe) - return errorStr.map(String.init(cString:)) + smb2_get_error(unsafeContext).map(String.init(cString:)) + } + + var ntError: NTStatus { + .init(rawValue: smb2_get_nterror(unsafeContext)) + } + + var errno: Int32 { + ntError.posixErrorCode.rawValue + } + + var maximumTransactionSize: Int { + (unsafeContext?.pointee.max_transact_size).map(Int.init) ?? 65535 } func whichEvents() throws -> Int16 { - try Int16(truncatingIfNeeded: smb2_which_events(unsafe.unwrap())) + try Int16(truncatingIfNeeded: smb2_which_events(unsafeContext.unwrap())) } func service(revents: Int32) throws { - let result = smb2_service(unsafe, revents) + let result = smb2_service(unsafeContext, revents) if result < 0 { - unsafe = nil - smb2_destroy_context(unsafe) + smb2_destroy_context(unsafeContext) + unsafeContext = nil + try POSIXError.throwIfError(result, description: error) } - try POSIXError.throwIfError(result, description: error) } } @@ -474,15 +485,15 @@ extension SMB2Context { struct NegotiateSigning: OptionSet { var rawValue: UInt16 - static let enabled = NegotiateSigning(.init(SMB2_NEGOTIATE_SIGNING_ENABLED)) - static let required = NegotiateSigning(.init(SMB2_NEGOTIATE_SIGNING_REQUIRED)) + static let enabled = NegotiateSigning(rawValue: SMB2_NEGOTIATE_SIGNING_ENABLED) + static let required = NegotiateSigning(rawValue: SMB2_NEGOTIATE_SIGNING_REQUIRED) } typealias Version = smb2_negotiate_version typealias Security = smb2_sec } -extension smb2_negotiate_version: Swift.Hashable { +extension SMB2.smb2_negotiate_version: Swift.Hashable { static let any = SMB2_VERSION_ANY static let v2 = SMB2_VERSION_ANY2 static let v3 = SMB2_VERSION_ANY3 @@ -501,7 +512,7 @@ extension smb2_negotiate_version: Swift.Hashable { } } -extension smb2_sec { +extension SMB2.smb2_sec: Swift.Hashable { static let undefined = SMB2_SEC_UNDEFINED static let ntlmSsp = SMB2_SEC_NTLMSSP static let kerberos5 = SMB2_SEC_KRB5 @@ -539,3 +550,23 @@ struct ShareProperties: RawRepresentable { rawValue & SHARE_TYPE_HIDDEN != 0 } } + +struct NTStatus: LocalizedError { + let rawValue: UInt32 + + init(rawValue: UInt32) { + self.rawValue = rawValue + } + + init(rawValue: Int32) { + self.rawValue = .init(bitPattern: rawValue) + } + + var errorDescription: String? { + nterror_to_str(rawValue).map(String.init(cString:)) + } + + var posixErrorCode: POSIXErrorCode { + .init(nterror_to_errno(rawValue)) + } +} diff --git a/AMSMB2/Directory.swift b/AMSMB2/Directory.swift index 38747f7..28a5521 100644 --- a/AMSMB2/Directory.swift +++ b/AMSMB2/Directory.swift @@ -14,17 +14,20 @@ typealias smb2dir = OpaquePointer /// - Note: This class is NOT thread-safe. final class SMB2Directory: Collection { - private var context: SMB2Context - private var handle: smb2dir + private let context: SMB2Context + private let handle: smb2dir init(_ path: String, on context: SMB2Context) throws { - let (_, handle) = try context.async_await(dataHandler: OpaquePointer.init) { - context, cbPtr -> Int32 in - smb2_opendir_async(context, path, SMB2Context.generic_handler, cbPtr) + // Due to a unexpected free in closedir, async version is not usable. + let handle = try context.withThreadSafeContext { context in + smb2_opendir(context, path) } - - self.context = context + guard let handle = handle, unsafeBitCast(handle, to: UInt.self) & 0xffffff00 != 0 else { + throw POSIXError(context.ntError.posixErrorCode, description: context.error) + } + self.handle = handle + self.context = context } deinit { @@ -35,11 +38,11 @@ final class SMB2Directory: Collection { } func makeIterator() -> AnyIterator { - let context = context.unsafe + let context = context.unsafeContext let handle = handle smb2_rewinddir(context, handle) return AnyIterator { - smb2_readdir(context, self.handle)?.pointee + smb2_readdir(context, handle)?.pointee } } @@ -52,7 +55,7 @@ final class SMB2Directory: Collection { } var count: Int { - let context = context.unsafe + let context = context.unsafeContext let handle = handle let currentPos = smb2_telldir(context, handle) defer { @@ -68,14 +71,14 @@ final class SMB2Directory: Collection { } subscript(_: Int) -> smb2dirent { - let context = context.unsafe + let context = context.unsafeContext let handle = handle let currentPos = smb2_telldir(context, handle) smb2_seekdir(context, handle, 0) defer { smb2_seekdir(context, handle, currentPos) } - return smb2_readdir(context, handle).move() + return smb2_readdir(context, handle).pointee } func index(after i: Int) -> Int { diff --git a/AMSMB2/Extensions.swift b/AMSMB2/Extensions.swift index 2b9274e..d1fa07a 100644 --- a/AMSMB2/Extensions.swift +++ b/AMSMB2/Extensions.swift @@ -63,7 +63,7 @@ extension POSIXError { init(_ code: POSIXError.Code, description: String?) { let userInfo: [String: Any] = - description.map { [NSLocalizedFailureReasonErrorKey: $0] } ?? [:] + description.map { [NSLocalizedDescriptionKey: $0] } ?? [:] self = POSIXError(code, userInfo: userInfo) } } diff --git a/AMSMB2/FileHandle.swift b/AMSMB2/FileHandle.swift index a07939c..fb58e75 100644 --- a/AMSMB2/FileHandle.swift +++ b/AMSMB2/FileHandle.swift @@ -17,60 +17,6 @@ let O_SYMLINK: Int32 = O_NOFOLLOW #endif final class SMB2FileHandle { - struct SeekWhence: RawRepresentable, Sendable { - var rawValue: Int32 - - static let set = SeekWhence(rawValue: SEEK_SET) - static let current = SeekWhence(rawValue: SEEK_CUR) - static let end = SeekWhence(rawValue: SEEK_END) - } - - struct LockOperation: OptionSet, Sendable { - var rawValue: Int32 - - static let shared = LockOperation(rawValue: LOCK_SH) - static let exclusive = LockOperation(rawValue: LOCK_EX) - static let unlock = LockOperation(rawValue: LOCK_UN) - static let nonBlocking = LockOperation(rawValue: LOCK_NB) - - var smb2Flag: UInt32 { - var result: UInt32 = 0 - if contains(.shared) { result |= 0x0000_0001 } - if contains(.exclusive) { result |= 0x0000_0002 } - if contains(.unlock) { result |= 0x0000_0004 } - if contains(.nonBlocking) { result |= 0x0000_0010 } - return result - } - } - - struct Attributes: OptionSet, Sendable { - var rawValue: UInt32 - - init(rawValue: UInt32) { - self.rawValue = rawValue - } - - init(rawValue: Int32) { - self.rawValue = .init(bitPattern: rawValue) - } - - static let readonly = Self(rawValue: SMB2_FILE_ATTRIBUTE_READONLY) - static let hidden = Self(rawValue: SMB2_FILE_ATTRIBUTE_HIDDEN) - static let system = Self(rawValue: SMB2_FILE_ATTRIBUTE_SYSTEM) - static let directory = Self(rawValue: SMB2_FILE_ATTRIBUTE_DIRECTORY) - static let archive = Self(rawValue: SMB2_FILE_ATTRIBUTE_ARCHIVE) - static let normal = Self(rawValue: SMB2_FILE_ATTRIBUTE_NORMAL) - static let temporary = Self(rawValue: SMB2_FILE_ATTRIBUTE_TEMPORARY) - static let sparseFile = Self(rawValue: SMB2_FILE_ATTRIBUTE_SPARSE_FILE) - static let reparsePoint = Self(rawValue: SMB2_FILE_ATTRIBUTE_REPARSE_POINT) - static let compressed = Self(rawValue: SMB2_FILE_ATTRIBUTE_COMPRESSED) - static let offline = Self(rawValue: SMB2_FILE_ATTRIBUTE_OFFLINE) - static let notContentIndexed = Self(rawValue: SMB2_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) - static let encrypted = Self(rawValue: SMB2_FILE_ATTRIBUTE_ENCRYPTED) - static let integrityStream = Self(rawValue: SMB2_FILE_ATTRIBUTE_INTEGRITY_STREAM) - static let noScrubData = Self(rawValue: SMB2_FILE_ATTRIBUTE_NO_SCRUB_DATA) - } - private var context: SMB2Context private var handle: smb2fh? @@ -100,27 +46,28 @@ final class SMB2FileHandle { static func using( path: String, - opLock: Int32 = SMB2_OPLOCK_LEVEL_NONE, - impersonation: Int32 = SMB2_IMPERSONATION_IMPERSONATION, - desiredAccess: Int32 = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA - | SMB2_FILE_READ_EA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_EA - | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_READ_CONTROL | SMB2_SYNCHRONIZE, - fileAttributes: Int32 = 0, - shareAccess: Int32 = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE | SMB2_FILE_SHARE_DELETE, - createDisposition: Int32 = SMB2_FILE_OPEN, - createOptions: Int32 = 0, on context: SMB2Context + opLock: OpLock = .none, + impersonation: ImpersonationLevel = .impersonation, + desiredAccess: Access = [ + .readData, .writeData, .appendData, .fileReadEA, .fileReadAttributes, .fileWriteEA, + .fileWriteAttributes, .readControl, .synchronize + ], + fileAttributes: Attributes = [], + shareAccess: ShareAccess = [.read, .write, .delete], + createDisposition: CreateDisposition = .open, + createOptions: CreateOptions = [], on context: SMB2Context ) throws -> SMB2FileHandle { let (_, result) = try context.async_await_pdu(dataHandler: SMB2FileHandle.init) { context, cbPtr -> UnsafeMutablePointer? in path.replacingOccurrences(of: "/", with: "\\").withCString { path in var req = smb2_create_request() - req.requested_oplock_level = .init(bitPattern: .init(opLock)) - req.impersonation_level = .init(bitPattern: impersonation) - req.desired_access = .init(bitPattern: desiredAccess) - req.file_attributes = .init(bitPattern: fileAttributes) - req.share_access = .init(bitPattern: shareAccess) - req.create_disposition = .init(bitPattern: createDisposition) - req.create_options = .init(bitPattern: createOptions) + req.requested_oplock_level = opLock.rawValue + req.impersonation_level = impersonation.rawValue + req.desired_access = desiredAccess.rawValue + req.file_attributes = fileAttributes.rawValue + req.share_access = shareAccess.rawValue + req.create_disposition = createDisposition.rawValue + req.create_options = createOptions.rawValue req.name = path return smb2_cmd_create_async(context, &req, SMB2Context.generic_handler, cbPtr) } @@ -130,44 +77,44 @@ final class SMB2FileHandle { } static func open(path: String, flags: Int32, on context: SMB2Context) throws -> SMB2FileHandle { - let desiredAccess: Int32 - let shareAccess: Int32 - let createDisposition: Int32 - var createOptions: Int32 = 0 + let desiredAccess: Access + let shareAccess: ShareAccess + let createDisposition: CreateDisposition + var createOptions: CreateOptions = [] switch flags & O_ACCMODE { case O_RDWR: - desiredAccess = .init(bitPattern: SMB2_GENERIC_READ) | SMB2_GENERIC_WRITE | SMB2_DELETE - shareAccess = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE + desiredAccess = [.genericRead, .genericWrite, .delete] + shareAccess = [.read, .write] case O_WRONLY: - desiredAccess = SMB2_GENERIC_WRITE | SMB2_DELETE - shareAccess = SMB2_FILE_SHARE_WRITE + desiredAccess = [.genericWrite, .delete] + shareAccess = [.write] default: - desiredAccess = .init(bitPattern: SMB2_GENERIC_READ) - shareAccess = SMB2_FILE_SHARE_READ + desiredAccess = [.genericRead] + shareAccess = [.read] } if (flags & O_CREAT) != 0 { if (flags & O_EXCL) != 0 { - createDisposition = SMB2_FILE_CREATE + createDisposition = .create } else if (flags & O_TRUNC) != 0 { - createDisposition = SMB2_FILE_OVERWRITE_IF + createDisposition = .overwriteIfExists } else { - createDisposition = SMB2_FILE_OPEN_IF + createDisposition = .openIfExists } } else { if (flags & O_TRUNC) != 0 { - createDisposition = SMB2_FILE_OVERWRITE + createDisposition = .overwrite } else { - createDisposition = SMB2_FILE_OPEN + createDisposition = .open } } if (flags & O_DIRECTORY) != 0 { - createOptions |= SMB2_FILE_DIRECTORY_FILE + createOptions.insert(.directoryFile) } if (flags & O_SYMLINK) != 0 { - createOptions |= SMB2_FILE_OPEN_REPARSE_POINT + createOptions.insert(.openReparsePoint) } return try SMB2FileHandle.using( @@ -183,7 +130,7 @@ final class SMB2FileHandle { init(fileDescriptor: smb2_file_id, on context: SMB2Context) throws { self.context = context var fileDescriptor = fileDescriptor - self.handle = smb2_fh_from_file_id(context.unsafe, &fileDescriptor) + self.handle = smb2_fh_from_file_id(context.unsafeContext, &fileDescriptor) } private init(_ path: String, flags: Int32, on context: SMB2Context) throws { @@ -279,7 +226,7 @@ final class SMB2FileHandle { @discardableResult func lseek(offset: Int64, whence: SeekWhence) throws -> Int64 { let handle = try handle.unwrap() - let result = smb2_lseek(context.unsafe, handle, offset, whence.rawValue, nil) + let result = smb2_lseek(context.unsafeContext, handle, offset, whence.rawValue, nil) try POSIXError.throwIfError(result, description: context.error) return result } @@ -417,7 +364,7 @@ final class SMB2FileHandle { file_id: fileId.uuid, input_offset: 0, input_count: .init(buf.count), max_input_response: 0, - output_offset: 0, output_count: .max, + output_offset: 0, output_count: UInt32(context.maximumTransactionSize), max_output_response: 65535, flags: .init(SMB2_0_IOCTL_IS_FSCTL), input: buf.baseAddress @@ -441,3 +388,161 @@ final class SMB2FileHandle { try fcntl(command: command, args: []) } } + +extension SMB2FileHandle { + struct SeekWhence: RawRepresentable, Sendable { + var rawValue: Int32 + + static let set = SeekWhence(rawValue: SEEK_SET) + static let current = SeekWhence(rawValue: SEEK_CUR) + static let end = SeekWhence(rawValue: SEEK_END) + } + + struct LockOperation: OptionSet, Sendable { + var rawValue: Int32 + + static let shared = LockOperation(rawValue: LOCK_SH) + static let exclusive = LockOperation(rawValue: LOCK_EX) + static let unlock = LockOperation(rawValue: LOCK_UN) + static let nonBlocking = LockOperation(rawValue: LOCK_NB) + + var smb2Flag: UInt32 { + var result: UInt32 = 0 + if contains(.shared) { result |= 0x0000_0001 } + if contains(.exclusive) { result |= 0x0000_0002 } + if contains(.unlock) { result |= 0x0000_0004 } + if contains(.nonBlocking) { result |= 0x0000_0010 } + return result + } + } + + struct Attributes: OptionSet, Sendable { + var rawValue: UInt32 + + init(rawValue: UInt32) { + self.rawValue = rawValue + } + + static let readonly = Self(rawValue: SMB2_FILE_ATTRIBUTE_READONLY) + static let hidden = Self(rawValue: SMB2_FILE_ATTRIBUTE_HIDDEN) + static let system = Self(rawValue: SMB2_FILE_ATTRIBUTE_SYSTEM) + static let directory = Self(rawValue: SMB2_FILE_ATTRIBUTE_DIRECTORY) + static let archive = Self(rawValue: SMB2_FILE_ATTRIBUTE_ARCHIVE) + static let normal = Self(rawValue: SMB2_FILE_ATTRIBUTE_NORMAL) + static let temporary = Self(rawValue: SMB2_FILE_ATTRIBUTE_TEMPORARY) + static let sparseFile = Self(rawValue: SMB2_FILE_ATTRIBUTE_SPARSE_FILE) + static let reparsePoint = Self(rawValue: SMB2_FILE_ATTRIBUTE_REPARSE_POINT) + static let compressed = Self(rawValue: SMB2_FILE_ATTRIBUTE_COMPRESSED) + static let offline = Self(rawValue: SMB2_FILE_ATTRIBUTE_OFFLINE) + static let notContentIndexed = Self(rawValue: SMB2_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) + static let encrypted = Self(rawValue: SMB2_FILE_ATTRIBUTE_ENCRYPTED) + static let integrityStream = Self(rawValue: SMB2_FILE_ATTRIBUTE_INTEGRITY_STREAM) + static let noScrubData = Self(rawValue: SMB2_FILE_ATTRIBUTE_NO_SCRUB_DATA) + } + + struct OpLock: OptionSet, Sendable { + var rawValue: UInt8 + + static let none = Self(rawValue: SMB2_OPLOCK_LEVEL_NONE) + static let ii = Self(rawValue: SMB2_OPLOCK_LEVEL_II) + static let exclusive = Self(rawValue: SMB2_OPLOCK_LEVEL_EXCLUSIVE) + static let batch = Self(rawValue: SMB2_OPLOCK_LEVEL_BATCH) + static let lease = Self(rawValue: SMB2_OPLOCK_LEVEL_LEASE) + } + + enum ImpersonationLevel: UInt32, Hashable, Sendable { + case anonymous = 0x00000000 + case identification = 0x00000001 + case impersonation = 0x00000002 + case delegate = 0x00000003 + } + + struct Access: OptionSet, Sendable { + var rawValue: UInt32 + + /* Access mask common to all objects */ + static let fileReadEA = Self(rawValue: SMB2_FILE_READ_EA) + static let fileWriteEA = Self(rawValue: SMB2_FILE_WRITE_EA) + static let fileDeleteChild = Self(rawValue: SMB2_FILE_DELETE_CHILD) + static let fileReadAttributes = Self(rawValue: SMB2_FILE_READ_ATTRIBUTES) + static let fileWriteAttributes = Self(rawValue: SMB2_FILE_WRITE_ATTRIBUTES) + static let delete = Self(rawValue: SMB2_DELETE) + static let readControl = Self(rawValue: SMB2_READ_CONTROL) + static let writeDACL = Self(rawValue: SMB2_WRITE_DACL) + static let writeOwner = Self(rawValue: SMB2_WRITE_OWNER) + static let synchronize = Self(rawValue: SMB2_SYNCHRONIZE) + static let acessSystemSecurity = Self(rawValue: SMB2_ACCESS_SYSTEM_SECURITY) + static let maximumAllowed = Self(rawValue: SMB2_MAXIMUM_ALLOWED) + static let genericAll = Self(rawValue: SMB2_GENERIC_ALL) + static let genericExecute = Self(rawValue: SMB2_GENERIC_EXECUTE) + static let genericWrite = Self(rawValue: SMB2_GENERIC_WRITE) + static let genericRead = Self(rawValue: SMB2_GENERIC_READ) + + /* Access mask unique for file/pipe/printer */ + static let readData = Self(rawValue: SMB2_FILE_READ_DATA) + static let writeData = Self(rawValue: SMB2_FILE_WRITE_DATA) + static let appendData = Self(rawValue: SMB2_FILE_APPEND_DATA) + static let execute = Self(rawValue: SMB2_FILE_EXECUTE) + + /* Access mask unique for directories */ + static let listDirectory = Self(rawValue: SMB2_FILE_LIST_DIRECTORY) + static let addFile = Self(rawValue: SMB2_FILE_ADD_FILE) + static let addSubdirectory = Self(rawValue: SMB2_FILE_ADD_SUBDIRECTORY) + static let traverse = Self(rawValue: SMB2_FILE_TRAVERSE) + } + + struct ShareAccess: OptionSet, Sendable { + var rawValue: UInt32 + + static let read = Self(rawValue: SMB2_FILE_SHARE_READ) + static let write = Self(rawValue: SMB2_FILE_SHARE_WRITE) + static let delete = Self(rawValue: SMB2_FILE_SHARE_DELETE) + } + + enum CreateDisposition: UInt32, Sendable { + case supersede = 0x00000000 // SMB2_FILE_SUPERSEDE + case open = 0x00000001 // SMB2_FILE_OPEN + case create = 0x00000002 // SMB2_FILE_CREATE + case openIfExists = 0x00000003 // SMB2_FILE_OPEN_IF + case overwrite = 0x00000004 // SMB2_FILE_OVERWRITE + case overwriteIfExists = 0x00000005 // SMB2_FILE_OVERWRITE_IF + } + + struct CreateOptions: OptionSet, Sendable { + var rawValue: UInt32 + + static let directoryFile = Self(rawValue: SMB2_FILE_DIRECTORY_FILE) + static let writeThrough = Self(rawValue: SMB2_FILE_WRITE_THROUGH) + static let sequentialOnly = Self(rawValue: SMB2_FILE_SEQUENTIAL_ONLY) + static let noIntermediateBuffering = Self(rawValue: SMB2_FILE_NO_INTERMEDIATE_BUFFERING) + static let synchronousIOAlert = Self(rawValue: SMB2_FILE_SYNCHRONOUS_IO_ALERT) + static let synchronousIONonAlert = Self(rawValue: SMB2_FILE_SYNCHRONOUS_IO_NONALERT) + static let nonDirectoryFile = Self(rawValue: SMB2_FILE_NON_DIRECTORY_FILE) + static let completeIfOplocked = Self(rawValue: SMB2_FILE_COMPLETE_IF_OPLOCKED) + static let noEAKnowledge = Self(rawValue: SMB2_FILE_NO_EA_KNOWLEDGE) + static let randomAccess = Self(rawValue: SMB2_FILE_RANDOM_ACCESS) + static let deleteOnClose = Self(rawValue: SMB2_FILE_DELETE_ON_CLOSE) + static let openByFileID = Self(rawValue: SMB2_FILE_OPEN_BY_FILE_ID) + static let openForBackupIntent = Self(rawValue: SMB2_FILE_OPEN_FOR_BACKUP_INTENT) + static let noCompression = Self(rawValue: SMB2_FILE_NO_COMPRESSION) + static let openRemoteInstance = Self(rawValue: SMB2_FILE_OPEN_REMOTE_INSTANCE) + static let openRequiringOplock = Self(rawValue: SMB2_FILE_OPEN_REQUIRING_OPLOCK) + static let disallowExclusive = Self(rawValue: SMB2_FILE_DISALLOW_EXCLUSIVE) + static let reserveOpfilter = Self(rawValue: SMB2_FILE_RESERVE_OPFILTER) + static let openReparsePoint = Self(rawValue: SMB2_FILE_OPEN_REPARSE_POINT) + static let openNoRecall = Self(rawValue: SMB2_FILE_OPEN_NO_RECALL) + static let openForFreeSpaceQuery = Self(rawValue: SMB2_FILE_OPEN_FOR_FREE_SPACE_QUERY) + } +} + +extension RawRepresentable where RawValue == UInt32 { + init(rawValue: Int32) { + self.init(rawValue: .init(bitPattern: rawValue))! + } +} + +extension RawRepresentable where RawValue: BinaryInteger { + init(rawValue: Int32) { + self.init(rawValue: .init(truncatingIfNeeded: rawValue))! + } +} diff --git a/AMSMB2/Parsers.swift b/AMSMB2/Parsers.swift index b493d01..2714b8d 100644 --- a/AMSMB2/Parsers.swift +++ b/AMSMB2/Parsers.swift @@ -73,7 +73,7 @@ extension IOCtlReply { return } #endif - defer { smb2_free_data(context.unsafe, output) } + defer { smb2_free_data(context.unsafeContext, output) } let data = Data(bytes: output, count: Int(reply.output_count)) self = try Self(data: data) } diff --git a/Dependencies/libsmb2 b/Dependencies/libsmb2 index 1c7d607..fa12712 160000 --- a/Dependencies/libsmb2 +++ b/Dependencies/libsmb2 @@ -1 +1 @@ -Subproject commit 1c7d60724a05ca14770c66da8eea6b49e1215376 +Subproject commit fa127123b915e2e7c3c22f0c3d6cf9d0fa688525