From d6059fc5df3a0227b489e1201188afb04cd36715 Mon Sep 17 00:00:00 2001 From: Amir Abbas Mousavian Date: Mon, 4 Jul 2016 19:38:36 +0430 Subject: [PATCH] Change Notifier, SMB2 Create Request/Response, Bug fix --- Source/FileProvider.swift | 3 + Source/LocalFileProvider.swift | 70 +++++++++ Source/SMBClient.swift | 262 +++++++++++++++++++++----------- Source/SMBFileProvider.swift | 9 ++ Source/WebDAVFileProvider.swift | 71 +++++---- 5 files changed, 294 insertions(+), 121 deletions(-) diff --git a/Source/FileProvider.swift b/Source/FileProvider.swift index 08206b5..5b963dc 100644 --- a/Source/FileProvider.swift +++ b/Source/FileProvider.swift @@ -121,6 +121,9 @@ public protocol FileProvider: class { func writeContentsAtPath(path: String, contents data: NSData, atomically: Bool, completionHandler: SimpleCompletionHandler) func searchFilesAtPath(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObjectClass) -> Void)?, completionHandler: ((files: [FileObjectClass], error: ErrorType?) -> Void)) + + func registerNotifcation(path: String, eventHandler: (() -> Void)) + func unregisterNotifcation(path: String) } extension FileProvider { diff --git a/Source/LocalFileProvider.swift b/Source/LocalFileProvider.swift index 3017bf2..555957c 100644 --- a/Source/LocalFileProvider.swift +++ b/Source/LocalFileProvider.swift @@ -283,6 +283,32 @@ public class LocalFileProvider: FileProvider { completionHandler(files: result, error: nil) } } + + private var monitorDictionary = [String : LocalFolderMonitor]() + + public func registerNotifcation(path: String, eventHandler: (() -> Void)) { + self.unregisterNotifcation(path) + var isdirv: AnyObject? + do { + try absoluteURL(path).getResourceValue(&isdirv, forKey: NSURLIsDirectoryKey) + } catch _ { + } + if !(isdirv?.boolValue ?? false) { + return + } + let monitor = LocalFolderMonitor(url: absoluteURL(path)) { + eventHandler() + } + monitor.start() + monitorDictionary[path] = monitor + } + + public func unregisterNotifcation(path: String) { + if let prevMonitor = monitorDictionary[path] { + prevMonitor.stop() + monitorDictionary.removeValueForKey(path) + } + } } extension LocalFileProvider { @@ -303,3 +329,47 @@ extension LocalFileProvider { } } } + +private class LocalFolderMonitor { + private let source: dispatch_source_t + private let descriptor: CInt + private let qq: dispatch_queue_t = dispatch_get_main_queue() + private var state: Bool = false + + /// Creates a folder monitor object with monitoring enabled. + init(url: NSURL, handler: ()->Void) { + + descriptor = open(url.fileSystemRepresentation, O_EVTONLY) + + source = dispatch_source_create( + DISPATCH_SOURCE_TYPE_VNODE, + UInt(descriptor), + DISPATCH_VNODE_WRITE, + qq + ) + + dispatch_source_set_event_handler(source, handler) + start() + } + + /// Starts sending notifications if currently stopped + func start() { + if !state { + state = true + dispatch_resume(source) + } + } + + /// Stops sending notifications if currently enabled + func stop() { + if state { + state = false + dispatch_suspend(source) + } + } + + deinit { + close(descriptor) + dispatch_source_cancel(source) + } +} diff --git a/Source/SMBClient.swift b/Source/SMBClient.swift index 17eeaae..2e6bb85 100644 --- a/Source/SMBClient.swift +++ b/Source/SMBClient.swift @@ -101,7 +101,8 @@ class SMBProtocolClient: TCPSocketClient { } let headersize = sizeof(SMB2.Header.self) let headerData = data.subdataWithRange(NSRange(location: 0, length: headersize)) - let messageData = data.subdataWithRange(NSRange(location: headersize, length: 0)) + let messageSize = data.length - headersize + let messageData = data.subdataWithRange(NSRange(location: headersize, length: messageSize)) let header: SMB2.Header = decode(headerData) switch header.command { case .NEGOTIATE: @@ -145,7 +146,6 @@ class SMBProtocolClient: TCPSocketClient { case .INVALID: throw SMBFileProviderError.InvalidCommand } - throw SMBFileProviderError.BadHeader } class func createSMBMessage(header: SMB1.Header, blocks: [(params: NSData?, message: NSData?)]) -> NSData { @@ -643,7 +643,7 @@ struct SMB2 { if Int(header.size) != 65 { return nil } - let bufOffset = Int(self.header.bufferOffset) + let bufOffset = Int(self.header.bufferOffset) - sizeof(SMB2.Header.self) let bufLen = Int(self.header.bufferLength) if bufOffset > 0 && bufLen > 0 && data.length >= bufOffset + bufLen { self.buffer = data.subdataWithRange(NSRange(location: bufOffset, length: bufLen)) @@ -651,7 +651,7 @@ struct SMB2 { self.buffer = nil } let contextCount = Int(self.header.contextCount) - let contextOffset = Int(self.header.contextOffset) + let contextOffset = Int(self.header.contextOffset) - sizeof(SMB2.Header.self) if contextCount > 0 && contextOffset > 0 { // TODO: NegotiateResponse context support for SMB3 self.contexts = [] @@ -726,7 +726,7 @@ struct SMB2 { func data() -> NSData { var header = self.header - header.bufferOffset = UInt16(sizeofValue(header)) + header.bufferOffset = UInt16(sizeof(SMB2.Header.self) + sizeof(SessionSetupRequest.Header.self)) header.bufferLength = UInt16(buffer?.length ?? 0) let result = NSMutableData(data: encode(&header)) if let buffer = self.buffer { @@ -782,7 +782,7 @@ struct SMB2 { if Int(header.size) != 9 { return nil } - let bufOffset = Int(self.header.bufferOffset) + let bufOffset = Int(self.header.bufferOffset) - sizeof(SMB2.Header.self) let bufLen = Int(self.header.bufferLength) if bufOffset > 0 && bufLen > 0 && data.length >= bufOffset + bufLen { self.buffer = data.subdataWithRange(NSRange(location: bufOffset, length: bufLen)) @@ -866,7 +866,7 @@ struct SMB2 { func data() -> NSData { var header = self.header - header.pathOffset = UInt16(sizeofValue(header)) + header.pathOffset = UInt16(sizeof(SMB2.Header.self) + sizeof(TreeConnectRequest.Header.self)) header.pathLength = UInt16(buffer?.length ?? 0) let result = NSMutableData(data: encode(&header)) if let buffer = self.buffer { @@ -988,10 +988,36 @@ struct SMB2 { struct CreateRequest: SMBRequest { let header: CreateRequest.Header + let name: String? let contexts: [CreateContext] + init (header: CreateRequest.Header, name: String? = nil, contexts: [CreateContext] = []) { + self.header = header + self.name = name + self.contexts = contexts + } + func data() -> NSData { - return NSData() + var header = self.header + var offset = 0x78 //UInt16(sizeof(SMB2.Header.self) + sizeof(CreateContext.Header.self) - 1) + let body = NSMutableData() + if let name = self.name, let nameData = name.dataUsingEncoding(NSUTF8StringEncoding) { + header.nameOffset = UInt16(offset) + header.nameLength = UInt16(nameData.length) + offset += nameData.length + body.appendData(nameData) + } + if contexts.count > 0 { + // TODO: Context CreateRequest implementation, 8 bit allign offset + header.contextOffset = UInt32(offset) + + + header.contextLength = 0 + //result.appendData(nameData) + } + let result = NSMutableData(data: encode(&header)) + result.appendData(body) + return result } struct Header { @@ -1030,66 +1056,27 @@ struct SMB2 { } } let options: CreateOptions + var nameOffset: UInt16 + var nameLength: UInt16 + var contextOffset: UInt32 + var contextLength: UInt32 - - } - - struct CreateContext: SMBRequest, SMBResponse { - var next: UInt32 - let nameOffset: UInt16 - let nameLength: UInt16 - private let reserved: UInt16 - let dataOffset: UInt16 - let dataLength: UInt32 - let buffer: NSData - - init(name: ContextNames, data: NSData) { + init(requestedOplockLevel: OplockLevel = .NONE, impersonationLevel: ImpersonationLevel = .Anonymous, access: FileAccessMask = [.GENERIC_ALL], fileAttributes: FileAttributes = [], shareAccess: ShareAccess = [.READ], desposition: CreateDisposition = .OPEN_IF, options: CreateOptions = []) { + self.size = 57 + self.securityFlags = 0 + self._requestedOplockLevel = requestedOplockLevel.rawValue + self._impersonationLevel = impersonationLevel.rawValue + self.flags = 0 self.reserved = 0 - self.next = 0 - self.nameOffset = 32 - let result = NSMutableData(data: (name.rawValue).dataUsingEncoding(NSUTF8StringEncoding)!) - self.nameLength = UInt16(result.length) - self.dataOffset = UInt16(result.length) - self.dataLength = UInt32(data.length) - result.appendData(data) - buffer = result - } - - init(name: NSUUID, data: NSData) { - self.reserved = 0 - self.next = 0 - self.nameOffset = 32 - var uuid = uuid_t(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) - name.getUUIDBytes(&uuid.0) - let result = NSMutableData(bytes: &uuid, length: 16) - self.nameLength = UInt16(result.length) - self.dataOffset = UInt16(result.length) - self.dataLength = UInt32(data.length) - result.appendData(data) - buffer = result - } - - init? (data: NSData) { - return nil - } - - func data() -> NSData { - return NSData() - } - - enum ContextNames: String { - /// Extended attributes - case EA_BUFFER = "ExtA" - /// Security descriptor - case SD_BUFFER = "SecD" - /// Requesting the open to be durable - case DURABLE_HANDLE_REQUEST = "DHnQ" - /// Requesting to reconnect to a durable open after being disconnected - case DURABLE_HANDLE_RECONNECT = "DHnC" - /// Required allocation size of the newly created file - case ALLOCATION_SIZE = "AISi" - case QUERY_MAXIMAL_ACCESS_REQUEST = "MxAc" - case TIMEWARP_TOKEN = "TWrp" + self.access = access + self.fileAttributes = fileAttributes + self.shareAccess = shareAccess + self._desposition = desposition.rawValue + self.options = options + self.nameOffset = 0 + self.nameLength = 0 + self.contextOffset = 0 + self.contextLength = 0 } } @@ -1147,31 +1134,133 @@ struct SMB2 { } struct CreateResponse: SMBResponse { - let size: UInt16 - private let _oplockLevel: UInt8 - var oplockLevel: OplockLevel { - return OplockLevel(rawValue: _oplockLevel)! + struct Header { + let size: UInt16 + private let _oplockLevel: UInt8 + var oplockLevel: OplockLevel { + return OplockLevel(rawValue: _oplockLevel)! + } + private let reserved: UInt32 + let creationTime: SMBTime + let lastAccessTime: SMBTime + let lastWriteTime: SMBTime + let changeTime: SMBTime + let allocationSize: UInt64 + let endOfFile: UInt64 + let fileAttributes: FileAttributes + private let reserved2: UInt32 + let fileIdPersistent: UInt64 + let fileIdVolatile: UInt64 + let contextsOffset: UInt32 + let ContextsLength: UInt32 } - private let reserved: UInt32 - let creationTime: SMBTime - let lastAccessTime: SMBTime - let lastWriteTime: SMBTime - let changeTime: SMBTime - let allocationSize: UInt64 - let endOfFile: UInt64 - let fileAttributes: FileAttributes + + let header: CreateResponse.Header + let contexts: [CreateContext] init? (data: NSData) { - self = decode(data) + guard data.length >= sizeof(CreateResponse.Header.self) else { + return nil + } + let headerData = data.subdataWithRange(NSRange(location: 0, length: sizeof(CreateResponse.Header.self))) + self.header = decode(headerData) + if self.header.contextsOffset > 0 { + var contexts = [CreateContext]() + var contextOffset = Int(self.header.contextsOffset) - sizeof(SMB2.Header.self) + while contextOffset > 0 { + guard contextOffset < data.length else { + self.contexts = contexts + return + } + let contextDataHeader = data.subdataWithRange(NSRange(location: contextOffset, length: sizeof(CreateContext.Header.self))) + if let lastContextHeader = CreateContext(data: contextDataHeader) { + let lastContextLen = Int(lastContextHeader.header.dataOffset) + Int(lastContextHeader.header.dataLength) - contextOffset + let lastContextData = data.subdataWithRange(NSRange(location: contextOffset, length: lastContextLen)) + if let newContext = CreateContext(data: lastContextData) { + contexts.append(newContext) + } + contextOffset = Int(lastContextHeader.header.next) - sizeof(SMB2.Header.self) + } + } + self.contexts = contexts + } else { + self.contexts = [] + } + } + } + + struct CreateContext { + struct Header { + var next: UInt32 + let nameOffset: UInt16 + let nameLength: UInt16 + private let reserved: UInt16 + let dataOffset: UInt16 + let dataLength: UInt32 + } + + var header: CreateContext.Header + let buffer: NSData + + init(name: ContextNames, data: NSData) { + let nameData = NSMutableData(data: (name.rawValue).dataUsingEncoding(NSUTF8StringEncoding)!) + self.header = CreateContext.Header(next: 0, nameOffset: 32, nameLength: UInt16(nameData.length), reserved: 0, dataOffset: UInt16(nameData.length), dataLength: UInt32(data.length)) + self.buffer = data + } + + init(name: NSUUID, data: NSData) { + var uuid = uuid_t(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) + name.getUUIDBytes(&uuid.0) + let nameData = NSMutableData(bytes: &uuid, length: 16) + self.header = CreateContext.Header(next: 0, nameOffset: 32, nameLength: UInt16(nameData.length), reserved: 0, dataOffset: UInt16(nameData.length), dataLength: UInt32(data.length)) + self.buffer = data + } + + init? (data: NSData) { + let headersize = sizeof(Header) + guard data.length > headersize else { + return nil + } + let headerData = data.subdataWithRange(NSRange(location: 0, length: headersize)) + self.header = decode(headerData) + self.buffer = data.subdataWithRange(NSRange(location: headersize, length: data.length - headersize)) + } + + func data() -> NSData { + var header = self.header + let result = NSMutableData(data: encode(&header)) + result.appendData(buffer) + return result + } + + enum ContextNames: String { + /// Request Create Context: Extended attributes + case EA_BUFFER = "ExtA" + /// Request Create Context: Security descriptor + case SD_BUFFER = "SecD" + /// Request & Response Create Context: Open to be durable + case DURABLE_HANDLE = "DHnQ" + case DURABLE_HANDLE_RESPONSE_V2 = "DH2Q" + /// Request Create Context: Reconnect to a durable open after being disconnected + case DURABLE_HANDLE_RECONNECT = "DHnC" + /// Request Create Context: Required allocation size of the newly created file + case ALLOCATION_SIZE = "AISi" + /// Request & Response Create Context: Maximal access information + case QUERY_MAXIMAL_ACCESS = "MxAc" + case TIMEWARP_TOKEN = "TWrp" + /// Response Create Context: DiskID of the open file in a volume. + case QUERY_ON_DISK_ID = "QFid" + /// Response Create Context: A lease. This value is only supported for the SMB 2.1 and 3.x dialect family. + case LEASE = "RqLs" } } enum OplockLevel: UInt8 { - case LEVEL_NONE = 0x00 + case NONE = 0x00 case LEVEL_II = 0x01 - case LEVEL_EXCLUSIVE = 0x08 - case LEVEL_BATCH = 0x09 - case LEVEL_LEASE = 0xFF + case EXCLUSIVE = 0x08 + case BATCH = 0x09 + case LEASE = 0xFF } struct ShareAccess: OptionSetType { @@ -1340,12 +1429,7 @@ struct SMB2 { // MARK: SMB2 Lock // MARK: SMB2 IOCTL - - /* - * Device-Platform specific operations, which is defferent from system to system - * Should not be implemented in a general SMB client - */ - + // MARK: SMB2 Cancel struct CancelRequest: SMBRequest { diff --git a/Source/SMBFileProvider.swift b/Source/SMBFileProvider.swift index b545b58..94ecce4 100644 --- a/Source/SMBFileProvider.swift +++ b/Source/SMBFileProvider.swift @@ -96,6 +96,15 @@ class SMBFileProvider: FileProvider { func searchFilesAtPath(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObjectClass) -> Void)?, completionHandler: ((files: [FileObjectClass], error: ErrorType?) -> Void)) { NotImplemented() } + + func registerNotifcation(path: String, eventHandler: (() -> Void)) { + NotImplemented() + } + + func unregisterNotifcation(path: String) { + NotImplemented() + } + } // MARK: basic CIFS interactivity diff --git a/Source/WebDAVFileProvider.swift b/Source/WebDAVFileProvider.swift index ab5d8ab..3dff7ef 100644 --- a/Source/WebDAVFileProvider.swift +++ b/Source/WebDAVFileProvider.swift @@ -8,7 +8,7 @@ import Foundation -enum FileProviderWebDavErrorCode: Int { +public enum FileProviderWebDavErrorCode: Int { case OK = 200 case Created = 201 case NoContent = 204 @@ -24,11 +24,11 @@ enum FileProviderWebDavErrorCode: Int { case InsufficientStorage = 507 } -struct FileProviderWebDavError: ErrorType, CustomStringConvertible { +public struct FileProviderWebDavError: ErrorType, CustomStringConvertible { let code: FileProviderWebDavErrorCode let url: NSURL - var description: String { + public var description: String { switch code { case .OK: return "OK" case .Created: return "Created" @@ -47,7 +47,7 @@ struct FileProviderWebDavError: ErrorType, CustomStringConvertible { } } -final class WebDavFileObject: FileObject { +public final class WebDavFileObject: FileObject { let contentType: String let entryTag: String? @@ -61,16 +61,16 @@ final class WebDavFileObject: FileObject { // Because this class uses NSURLSession, it's necessary to disable App Transport Security // in case of using this class with unencrypted HTTP connection. -class WebDAVFileProvider: NSObject, FileProvider { - let type: String = "WebDAV" - let isPathRelative: Bool = true - let baseURL: NSURL? - var currentPath: String = "" - var dispatch_queue: dispatch_queue_t - var delegate: FileProviderDelegate? - let credential: NSURLCredential? +public class WebDAVFileProvider: NSObject, FileProvider { + public let type: String = "WebDAV" + public let isPathRelative: Bool = true + public let baseURL: NSURL? + public var currentPath: String = "" + public var dispatch_queue: dispatch_queue_t + public var delegate: FileProviderDelegate? + public let credential: NSURLCredential? - typealias FileObjectClass = FileObject + public typealias FileObjectClass = FileObject private var _session: NSURLSession? private var session: NSURLSession { @@ -93,7 +93,7 @@ class WebDAVFileProvider: NSObject, FileProvider { deinit { } - func contentsOfDirectoryAtPath(path: String, completionHandler: ((contents: [FileObjectClass], error: ErrorType?) -> Void)) { + public func contentsOfDirectoryAtPath(path: String, completionHandler: ((contents: [FileObjectClass], error: ErrorType?) -> Void)) { let url = absoluteURL(path) let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "PROPFIND" @@ -129,7 +129,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func attributesOfItemAtPath(path: String, completionHandler: ((attributes: FileObjectClass?, error: ErrorType?) -> Void)) { + public func attributesOfItemAtPath(path: String, completionHandler: ((attributes: FileObjectClass?, error: ErrorType?) -> Void)) { let request = NSMutableURLRequest(URL: absoluteURL(path)) request.HTTPMethod = "PROPFIND" request.setValue(baseURL?.absoluteString, forHTTPHeaderField: "Host") @@ -159,7 +159,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func createFolder(folderName: String, atPath: String, completionHandler: SimpleCompletionHandler) { + public func createFolder(folderName: String, atPath: String, completionHandler: SimpleCompletionHandler) { let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration()) let url = absoluteURL(atPath.stringByAppendingPathComponent(folderName) + "/") let request = NSMutableURLRequest(URL: url) @@ -182,7 +182,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func createFile(fileAttribs: FileObject, atPath path: String, contents data: NSData?, completionHandler: SimpleCompletionHandler) { + public func createFile(fileAttribs: FileObject, atPath path: String, contents data: NSData?, completionHandler: SimpleCompletionHandler) { let request = NSMutableURLRequest(URL: absoluteURL(path)) request.HTTPMethod = "PUT" let task = session.uploadTaskWithRequest(request, fromData: data) { (data, response, error) in @@ -199,7 +199,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func moveItemAtPath(path: String, toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) { + public func moveItemAtPath(path: String, toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) { let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration()) let url = absoluteURL(path) let request = NSMutableURLRequest(URL: url) @@ -237,7 +237,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func copyItemAtPath(path: String, toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) { + public func copyItemAtPath(path: String, toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) { let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration()) let url = absoluteURL(path) let request = NSMutableURLRequest(URL: url) @@ -275,7 +275,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func removeItemAtPath(path: String, completionHandler: SimpleCompletionHandler) { + public func removeItemAtPath(path: String, completionHandler: SimpleCompletionHandler) { let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration()) let url = absoluteURL(path) let request = NSMutableURLRequest(URL: url) @@ -309,7 +309,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func copyLocalFileToPath(localFile: NSURL, toPath: String, completionHandler: SimpleCompletionHandler) { + public func copyLocalFileToPath(localFile: NSURL, toPath: String, completionHandler: SimpleCompletionHandler) { let request = NSMutableURLRequest(URL: absoluteURL(toPath)) request.HTTPMethod = "PUT" let task = session.uploadTaskWithRequest(request, fromFile: localFile) { (data, response, error) in @@ -326,7 +326,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func copyPathToLocalFile(path: String, toLocalURL: NSURL, completionHandler: SimpleCompletionHandler) { + public func copyPathToLocalFile(path: String, toLocalURL: NSURL, completionHandler: SimpleCompletionHandler) { let request = NSMutableURLRequest(URL: absoluteURL(path)) let task = session.downloadTaskWithRequest(request) { (sourceFileURL, response, error) in if let sourceFileURL = sourceFileURL { @@ -343,7 +343,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func contentsAtPath(path: String, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void)) { + public func contentsAtPath(path: String, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void)) { let request = NSMutableURLRequest(URL: absoluteURL(path)) request.HTTPMethod = "GET" let task = session.dataTaskWithRequest(request) { (data, response, error) in @@ -352,7 +352,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func contentsAtPath(path: String, offset: Int64, length: Int, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void)) { + public func contentsAtPath(path: String, offset: Int64, length: Int, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void)) { let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration()) let request = NSMutableURLRequest(URL: absoluteURL(path)) request.HTTPMethod = "GET" @@ -363,7 +363,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func writeContentsAtPath(path: String, contents data: NSData, atomically: Bool = false, completionHandler: SimpleCompletionHandler) { + public func writeContentsAtPath(path: String, contents data: NSData, atomically: Bool = false, completionHandler: SimpleCompletionHandler) { // FIXME: lock destination before writing process let url = atomically ? absoluteURL(path).URLByAppendingPathExtension("tmp") : absoluteURL(path) let request = NSMutableURLRequest(URL: url) @@ -390,7 +390,7 @@ class WebDAVFileProvider: NSObject, FileProvider { task.resume() } - func searchFilesAtPath(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObjectClass) -> Void)?, completionHandler: ((files: [FileObjectClass], error: ErrorType?) -> Void)) { + public func searchFilesAtPath(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObjectClass) -> Void)?, completionHandler: ((files: [FileObjectClass], error: ErrorType?) -> Void)) { let url = absoluteURL(path) let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "PROPFIND" @@ -427,12 +427,19 @@ class WebDAVFileProvider: NSObject, FileProvider { } task.resume() } + + public func registerNotifcation(path: String, eventHandler: (() -> Void)) { + NotImplemented() + } + public func unregisterNotifcation(path: String) { + NotImplemented() + } // TODO: implements methods for lock mechanism } // MARK: WEBDAV XML response implementation -extension WebDAVFileProvider { +internal extension WebDAVFileProvider { struct DavResponse { let href: NSURL let status: Int? @@ -531,11 +538,11 @@ extension WebDAVFileProvider { // MARK: URLSession delegate extension WebDAVFileProvider: NSURLSessionDataDelegate, NSURLSessionDownloadDelegate { - func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) { + public func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) { return } - func URLSession(session: NSURLSession, task: NSURLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) { + public func URLSession(session: NSURLSession, task: NSURLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) { guard let desc = task.taskDescription, let json = jsonToDictionary(desc) else { return } @@ -569,7 +576,7 @@ extension WebDAVFileProvider: NSURLSessionDataDelegate, NSURLSessionDownloadDele self.delegate?.fileproviderProgress(self, operation: op, progress: progress) } - func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { + public func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { guard let desc = downloadTask.taskDescription, let json = jsonToDictionary(desc), let source = json["source"] as? String, dest = json["dest"] as? String else { return } @@ -577,11 +584,11 @@ extension WebDAVFileProvider: NSURLSessionDataDelegate, NSURLSessionDownloadDele self.delegate?.fileproviderProgress(self, operation: .Copy(source: source, destination: dest), progress: Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)) } - func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { + public func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential) } - func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { + public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential) } } \ No newline at end of file