Change Notifier, SMB2 Create Request/Response, Bug fix
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+173
-89
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user