Compare commits

..

6 Commits

Author SHA1 Message Date
Amir Abbas Mousavian e6a450e3e2 tvOS support 2016-07-27 15:02:14 +04:30
Amir Abbas Mousavian 0fd6da3658 Cocoapod project added 2016-07-27 14:56:33 +04:30
Amir Abbas Mousavian 67b6cf64e2 insert slash in the beginning of path 2016-07-26 10:34:34 +04:30
Amir Abbas Mousavian 3ab252e598 WebDav refactors and Dropbox partial implementation 2016-07-25 19:18:13 +04:30
Amir Abbas Mousavian 09f9909363 spliced SMB2 Types into several files 2016-07-21 00:40:21 +04:30
Amir Abbas Mousavian c6d069cb46 Added Write and IOCtl commands' types 2016-07-20 17:59:25 +04:30
32 changed files with 3991 additions and 1848 deletions
+4 -4
View File
@@ -16,7 +16,7 @@ Pod::Spec.new do |s|
#
s.name = "FileProvider"
s.version = "0.2.0"
s.version = "0.3.0"
s.summary = "NSFileManager replacement for Local and Remote (WebDAV/Dropbox/SMB2) files on iOS and MacOS."
# This description is used to generate tags and improve search results.
@@ -73,7 +73,7 @@ Pod::Spec.new do |s|
s.ios.deployment_target = "8.0"
s.osx.deployment_target = "10.10"
# s.watchos.deployment_target = "2.0"
# s.tvos.deployment_target = "9.0"
s.tvos.deployment_target = "9.0"
# ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
@@ -93,8 +93,8 @@ Pod::Spec.new do |s|
# Not including the public_header_files will make all headers public.
#
s.source_files = "Source/*.swift"
s.exclude_files = "Source/Exclude"
s.source_files = "Sources/*.swift"
s.exclude_files = "Sources/Exclude"
# s.public_header_files = "Classes/**/*.h"
+801
View File
@@ -0,0 +1,801 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
799396A71D48C02300086753 /* AEXML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396921D48C02300086753 /* AEXML.swift */; };
799396A81D48C02300086753 /* AEXML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396921D48C02300086753 /* AEXML.swift */; };
799396A91D48C02300086753 /* AEXML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396921D48C02300086753 /* AEXML.swift */; };
799396AA1D48C02300086753 /* DropboxFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396931D48C02300086753 /* DropboxFileProvider.swift */; };
799396AB1D48C02300086753 /* DropboxFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396931D48C02300086753 /* DropboxFileProvider.swift */; };
799396AC1D48C02300086753 /* DropboxFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396931D48C02300086753 /* DropboxFileProvider.swift */; };
799396B01D48C02300086753 /* FileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396951D48C02300086753 /* FileProvider.swift */; };
799396B11D48C02300086753 /* FileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396951D48C02300086753 /* FileProvider.swift */; };
799396B21D48C02300086753 /* FileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396951D48C02300086753 /* FileProvider.swift */; };
799396B31D48C02300086753 /* LocalFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396961D48C02300086753 /* LocalFileProvider.swift */; };
799396B41D48C02300086753 /* LocalFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396961D48C02300086753 /* LocalFileProvider.swift */; };
799396B51D48C02300086753 /* LocalFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396961D48C02300086753 /* LocalFileProvider.swift */; };
799396B61D48C02300086753 /* SMBClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396971D48C02300086753 /* SMBClient.swift */; };
799396B71D48C02300086753 /* SMBClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396971D48C02300086753 /* SMBClient.swift */; };
799396B81D48C02300086753 /* SMBClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396971D48C02300086753 /* SMBClient.swift */; };
799396B91D48C02300086753 /* SMBFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396981D48C02300086753 /* SMBFileProvider.swift */; };
799396BA1D48C02300086753 /* SMBFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396981D48C02300086753 /* SMBFileProvider.swift */; };
799396BB1D48C02300086753 /* SMBFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396981D48C02300086753 /* SMBFileProvider.swift */; };
799396BC1D48C02300086753 /* CIFSTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969A1D48C02300086753 /* CIFSTypes.swift */; };
799396BD1D48C02300086753 /* CIFSTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969A1D48C02300086753 /* CIFSTypes.swift */; };
799396BE1D48C02300086753 /* CIFSTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969A1D48C02300086753 /* CIFSTypes.swift */; };
799396BF1D48C02300086753 /* SMB2DataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969B1D48C02300086753 /* SMB2DataTypes.swift */; };
799396C01D48C02300086753 /* SMB2DataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969B1D48C02300086753 /* SMB2DataTypes.swift */; };
799396C11D48C02300086753 /* SMB2DataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969B1D48C02300086753 /* SMB2DataTypes.swift */; };
799396C21D48C02300086753 /* SMB2FileHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969C1D48C02300086753 /* SMB2FileHandle.swift */; };
799396C31D48C02300086753 /* SMB2FileHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969C1D48C02300086753 /* SMB2FileHandle.swift */; };
799396C41D48C02300086753 /* SMB2FileHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969C1D48C02300086753 /* SMB2FileHandle.swift */; };
799396C51D48C02300086753 /* SMB2FileOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969D1D48C02300086753 /* SMB2FileOperation.swift */; };
799396C61D48C02300086753 /* SMB2FileOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969D1D48C02300086753 /* SMB2FileOperation.swift */; };
799396C71D48C02300086753 /* SMB2FileOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969D1D48C02300086753 /* SMB2FileOperation.swift */; };
799396C81D48C02300086753 /* SMB2IOCtl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969E1D48C02300086753 /* SMB2IOCtl.swift */; };
799396C91D48C02300086753 /* SMB2IOCtl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969E1D48C02300086753 /* SMB2IOCtl.swift */; };
799396CA1D48C02300086753 /* SMB2IOCtl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969E1D48C02300086753 /* SMB2IOCtl.swift */; };
799396CB1D48C02300086753 /* SMB2Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969F1D48C02300086753 /* SMB2Query.swift */; };
799396CC1D48C02300086753 /* SMB2Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969F1D48C02300086753 /* SMB2Query.swift */; };
799396CD1D48C02300086753 /* SMB2Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993969F1D48C02300086753 /* SMB2Query.swift */; };
799396CE1D48C02300086753 /* SMB2Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A01D48C02300086753 /* SMB2Session.swift */; };
799396CF1D48C02300086753 /* SMB2Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A01D48C02300086753 /* SMB2Session.swift */; };
799396D01D48C02300086753 /* SMB2Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A01D48C02300086753 /* SMB2Session.swift */; };
799396D11D48C02300086753 /* SMB2SetInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A11D48C02300086753 /* SMB2SetInfo.swift */; };
799396D21D48C02300086753 /* SMB2SetInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A11D48C02300086753 /* SMB2SetInfo.swift */; };
799396D31D48C02300086753 /* SMB2SetInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A11D48C02300086753 /* SMB2SetInfo.swift */; };
799396D41D48C02300086753 /* SMB2Tree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A21D48C02300086753 /* SMB2Tree.swift */; };
799396D51D48C02300086753 /* SMB2Tree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A21D48C02300086753 /* SMB2Tree.swift */; };
799396D61D48C02300086753 /* SMB2Tree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A21D48C02300086753 /* SMB2Tree.swift */; };
799396D71D48C02300086753 /* SMB2Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A31D48C02300086753 /* SMB2Types.swift */; };
799396D81D48C02300086753 /* SMB2Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A31D48C02300086753 /* SMB2Types.swift */; };
799396D91D48C02300086753 /* SMB2Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A31D48C02300086753 /* SMB2Types.swift */; };
799396DA1D48C02300086753 /* SMBErrorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A41D48C02300086753 /* SMBErrorType.swift */; };
799396DB1D48C02300086753 /* SMBErrorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A41D48C02300086753 /* SMBErrorType.swift */; };
799396DC1D48C02300086753 /* SMBErrorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A41D48C02300086753 /* SMBErrorType.swift */; };
799396DD1D48C02300086753 /* TCPSocketClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A51D48C02300086753 /* TCPSocketClient.swift */; };
799396DE1D48C02300086753 /* TCPSocketClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A51D48C02300086753 /* TCPSocketClient.swift */; };
799396DF1D48C02300086753 /* TCPSocketClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A51D48C02300086753 /* TCPSocketClient.swift */; };
799396E01D48C02300086753 /* WebDAVFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A61D48C02300086753 /* WebDAVFileProvider.swift */; };
799396E11D48C02300086753 /* WebDAVFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A61D48C02300086753 /* WebDAVFileProvider.swift */; };
799396E21D48C02300086753 /* WebDAVFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396A61D48C02300086753 /* WebDAVFileProvider.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
799396671D48B7F600086753 /* FileProvider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FileProvider.framework; sourceTree = BUILT_PRODUCTS_DIR; };
799396751D48B80D00086753 /* FileProvider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FileProvider.framework; sourceTree = BUILT_PRODUCTS_DIR; };
799396821D48B82700086753 /* FileProvider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FileProvider.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7993968B1D48B8C700086753 /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = "<group>"; };
7993968C1D48B8C700086753 /* Info-MacOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-MacOS.plist"; sourceTree = "<group>"; };
7993968D1D48B8C700086753 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = "<group>"; };
799396921D48C02300086753 /* AEXML.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AEXML.swift; sourceTree = "<group>"; };
799396931D48C02300086753 /* DropboxFileProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropboxFileProvider.swift; sourceTree = "<group>"; };
799396941D48C02300086753 /* FileProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileProvider.h; sourceTree = "<group>"; };
799396951D48C02300086753 /* FileProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileProvider.swift; sourceTree = "<group>"; };
799396961D48C02300086753 /* LocalFileProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalFileProvider.swift; sourceTree = "<group>"; };
799396971D48C02300086753 /* SMBClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMBClient.swift; sourceTree = "<group>"; };
799396981D48C02300086753 /* SMBFileProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMBFileProvider.swift; sourceTree = "<group>"; };
7993969A1D48C02300086753 /* CIFSTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CIFSTypes.swift; sourceTree = "<group>"; };
7993969B1D48C02300086753 /* SMB2DataTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2DataTypes.swift; sourceTree = "<group>"; };
7993969C1D48C02300086753 /* SMB2FileHandle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2FileHandle.swift; sourceTree = "<group>"; };
7993969D1D48C02300086753 /* SMB2FileOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2FileOperation.swift; sourceTree = "<group>"; };
7993969E1D48C02300086753 /* SMB2IOCtl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2IOCtl.swift; sourceTree = "<group>"; };
7993969F1D48C02300086753 /* SMB2Query.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2Query.swift; sourceTree = "<group>"; };
799396A01D48C02300086753 /* SMB2Session.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2Session.swift; sourceTree = "<group>"; };
799396A11D48C02300086753 /* SMB2SetInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2SetInfo.swift; sourceTree = "<group>"; };
799396A21D48C02300086753 /* SMB2Tree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2Tree.swift; sourceTree = "<group>"; };
799396A31D48C02300086753 /* SMB2Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2Types.swift; sourceTree = "<group>"; };
799396A41D48C02300086753 /* SMBErrorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMBErrorType.swift; sourceTree = "<group>"; };
799396A51D48C02300086753 /* TCPSocketClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TCPSocketClient.swift; sourceTree = "<group>"; };
799396A61D48C02300086753 /* WebDAVFileProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebDAVFileProvider.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
799396631D48B7F600086753 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
799396711D48B80D00086753 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
7993967E1D48B82700086753 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
7993965B1D48B7BF00086753 = {
isa = PBXGroup;
children = (
799396911D48C02300086753 /* Sources */,
7993968A1D48B8C700086753 /* Pod */,
799396681D48B7F600086753 /* Products */,
);
sourceTree = "<group>";
};
799396681D48B7F600086753 /* Products */ = {
isa = PBXGroup;
children = (
799396671D48B7F600086753 /* FileProvider.framework */,
799396751D48B80D00086753 /* FileProvider.framework */,
799396821D48B82700086753 /* FileProvider.framework */,
);
name = Products;
sourceTree = "<group>";
};
7993968A1D48B8C700086753 /* Pod */ = {
isa = PBXGroup;
children = (
7993968B1D48B8C700086753 /* Info-iOS.plist */,
7993968C1D48B8C700086753 /* Info-MacOS.plist */,
7993968D1D48B8C700086753 /* Info-tvOS.plist */,
);
path = Pod;
sourceTree = "<group>";
};
799396911D48C02300086753 /* Sources */ = {
isa = PBXGroup;
children = (
799396991D48C02300086753 /* SMBTypes */,
799396921D48C02300086753 /* AEXML.swift */,
799396931D48C02300086753 /* DropboxFileProvider.swift */,
799396941D48C02300086753 /* FileProvider.h */,
799396951D48C02300086753 /* FileProvider.swift */,
799396961D48C02300086753 /* LocalFileProvider.swift */,
799396971D48C02300086753 /* SMBClient.swift */,
799396981D48C02300086753 /* SMBFileProvider.swift */,
799396A51D48C02300086753 /* TCPSocketClient.swift */,
799396A61D48C02300086753 /* WebDAVFileProvider.swift */,
);
path = Sources;
sourceTree = "<group>";
};
799396991D48C02300086753 /* SMBTypes */ = {
isa = PBXGroup;
children = (
7993969A1D48C02300086753 /* CIFSTypes.swift */,
7993969B1D48C02300086753 /* SMB2DataTypes.swift */,
7993969C1D48C02300086753 /* SMB2FileHandle.swift */,
7993969D1D48C02300086753 /* SMB2FileOperation.swift */,
7993969E1D48C02300086753 /* SMB2IOCtl.swift */,
7993969F1D48C02300086753 /* SMB2Query.swift */,
799396A01D48C02300086753 /* SMB2Session.swift */,
799396A11D48C02300086753 /* SMB2SetInfo.swift */,
799396A21D48C02300086753 /* SMB2Tree.swift */,
799396A31D48C02300086753 /* SMB2Types.swift */,
799396A41D48C02300086753 /* SMBErrorType.swift */,
);
path = SMBTypes;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
799396641D48B7F600086753 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
799396721D48B80D00086753 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
7993967F1D48B82700086753 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
799396661D48B7F600086753 /* FileProvider iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7993966F1D48B7F600086753 /* Build configuration list for PBXNativeTarget "FileProvider iOS" */;
buildPhases = (
799396621D48B7F600086753 /* Sources */,
799396631D48B7F600086753 /* Frameworks */,
799396641D48B7F600086753 /* Headers */,
799396651D48B7F600086753 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "FileProvider iOS";
productName = "FileProvider iOS";
productReference = 799396671D48B7F600086753 /* FileProvider.framework */;
productType = "com.apple.product-type.framework";
};
799396741D48B80D00086753 /* FileProvider OSX */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7993967A1D48B80D00086753 /* Build configuration list for PBXNativeTarget "FileProvider OSX" */;
buildPhases = (
799396701D48B80D00086753 /* Sources */,
799396711D48B80D00086753 /* Frameworks */,
799396721D48B80D00086753 /* Headers */,
799396731D48B80D00086753 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "FileProvider OSX";
productName = "FileProvider OSX";
productReference = 799396751D48B80D00086753 /* FileProvider.framework */;
productType = "com.apple.product-type.framework";
};
799396811D48B82700086753 /* FileProvider tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 799396871D48B82700086753 /* Build configuration list for PBXNativeTarget "FileProvider tvOS" */;
buildPhases = (
7993967D1D48B82700086753 /* Sources */,
7993967E1D48B82700086753 /* Frameworks */,
7993967F1D48B82700086753 /* Headers */,
799396801D48B82700086753 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "FileProvider tvOS";
productName = "FileProvider tvOS";
productReference = 799396821D48B82700086753 /* FileProvider.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
7993965C1D48B7BF00086753 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0730;
TargetAttributes = {
799396661D48B7F600086753 = {
CreatedOnToolsVersion = 7.3.1;
};
799396741D48B80D00086753 = {
CreatedOnToolsVersion = 7.3.1;
};
799396811D48B82700086753 = {
CreatedOnToolsVersion = 7.3.1;
};
};
};
buildConfigurationList = 7993965F1D48B7BF00086753 /* Build configuration list for PBXProject "FileProvider" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 7993965B1D48B7BF00086753;
productRefGroup = 799396681D48B7F600086753 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
799396661D48B7F600086753 /* FileProvider iOS */,
799396741D48B80D00086753 /* FileProvider OSX */,
799396811D48B82700086753 /* FileProvider tvOS */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
799396651D48B7F600086753 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
799396731D48B80D00086753 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
799396801D48B82700086753 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
799396621D48B7F600086753 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
799396B31D48C02300086753 /* LocalFileProvider.swift in Sources */,
799396D41D48C02300086753 /* SMB2Tree.swift in Sources */,
799396C81D48C02300086753 /* SMB2IOCtl.swift in Sources */,
799396DD1D48C02300086753 /* TCPSocketClient.swift in Sources */,
799396D71D48C02300086753 /* SMB2Types.swift in Sources */,
799396C51D48C02300086753 /* SMB2FileOperation.swift in Sources */,
799396BF1D48C02300086753 /* SMB2DataTypes.swift in Sources */,
799396B91D48C02300086753 /* SMBFileProvider.swift in Sources */,
799396BC1D48C02300086753 /* CIFSTypes.swift in Sources */,
799396D11D48C02300086753 /* SMB2SetInfo.swift in Sources */,
799396A71D48C02300086753 /* AEXML.swift in Sources */,
799396CE1D48C02300086753 /* SMB2Session.swift in Sources */,
799396E01D48C02300086753 /* WebDAVFileProvider.swift in Sources */,
799396DA1D48C02300086753 /* SMBErrorType.swift in Sources */,
799396C21D48C02300086753 /* SMB2FileHandle.swift in Sources */,
799396CB1D48C02300086753 /* SMB2Query.swift in Sources */,
799396AA1D48C02300086753 /* DropboxFileProvider.swift in Sources */,
799396B01D48C02300086753 /* FileProvider.swift in Sources */,
799396B61D48C02300086753 /* SMBClient.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
799396701D48B80D00086753 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
799396B41D48C02300086753 /* LocalFileProvider.swift in Sources */,
799396D51D48C02300086753 /* SMB2Tree.swift in Sources */,
799396C91D48C02300086753 /* SMB2IOCtl.swift in Sources */,
799396DE1D48C02300086753 /* TCPSocketClient.swift in Sources */,
799396D81D48C02300086753 /* SMB2Types.swift in Sources */,
799396C61D48C02300086753 /* SMB2FileOperation.swift in Sources */,
799396C01D48C02300086753 /* SMB2DataTypes.swift in Sources */,
799396BA1D48C02300086753 /* SMBFileProvider.swift in Sources */,
799396BD1D48C02300086753 /* CIFSTypes.swift in Sources */,
799396D21D48C02300086753 /* SMB2SetInfo.swift in Sources */,
799396A81D48C02300086753 /* AEXML.swift in Sources */,
799396CF1D48C02300086753 /* SMB2Session.swift in Sources */,
799396E11D48C02300086753 /* WebDAVFileProvider.swift in Sources */,
799396DB1D48C02300086753 /* SMBErrorType.swift in Sources */,
799396C31D48C02300086753 /* SMB2FileHandle.swift in Sources */,
799396CC1D48C02300086753 /* SMB2Query.swift in Sources */,
799396AB1D48C02300086753 /* DropboxFileProvider.swift in Sources */,
799396B11D48C02300086753 /* FileProvider.swift in Sources */,
799396B71D48C02300086753 /* SMBClient.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
7993967D1D48B82700086753 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
799396B51D48C02300086753 /* LocalFileProvider.swift in Sources */,
799396D61D48C02300086753 /* SMB2Tree.swift in Sources */,
799396CA1D48C02300086753 /* SMB2IOCtl.swift in Sources */,
799396DF1D48C02300086753 /* TCPSocketClient.swift in Sources */,
799396D91D48C02300086753 /* SMB2Types.swift in Sources */,
799396C71D48C02300086753 /* SMB2FileOperation.swift in Sources */,
799396C11D48C02300086753 /* SMB2DataTypes.swift in Sources */,
799396BB1D48C02300086753 /* SMBFileProvider.swift in Sources */,
799396BE1D48C02300086753 /* CIFSTypes.swift in Sources */,
799396D31D48C02300086753 /* SMB2SetInfo.swift in Sources */,
799396A91D48C02300086753 /* AEXML.swift in Sources */,
799396D01D48C02300086753 /* SMB2Session.swift in Sources */,
799396E21D48C02300086753 /* WebDAVFileProvider.swift in Sources */,
799396DC1D48C02300086753 /* SMBErrorType.swift in Sources */,
799396C41D48C02300086753 /* SMB2FileHandle.swift in Sources */,
799396CD1D48C02300086753 /* SMB2Query.swift in Sources */,
799396AC1D48C02300086753 /* DropboxFileProvider.swift in Sources */,
799396B21D48C02300086753 /* FileProvider.swift in Sources */,
799396B81D48C02300086753 /* SMBClient.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
799396601D48B7BF00086753 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Debug;
};
799396611D48B7BF00086753 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Release;
};
7993966D1D48B7F600086753 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "Pod/Info-iOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.mousavian.FileProvider-iOS";
PRODUCT_NAME = FileProvider;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
7993966E1D48B7F600086753 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "Pod/Info-iOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.mousavian.FileProvider-iOS";
PRODUCT_NAME = FileProvider;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
7993967B1D48B80D00086753 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "Pod/Info-MacOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.mousavian.FileProvider-OSX";
PRODUCT_NAME = FileProvider;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
7993967C1D48B80D00086753 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "Pod/Info-MacOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.mousavian.FileProvider-OSX";
PRODUCT_NAME = FileProvider;
SDKROOT = macosx;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
799396881D48B82700086753 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "Pod/Info-tvOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.mousavian.FileProvider-tvOS";
PRODUCT_NAME = FileProvider;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
799396891D48B82700086753 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "Pod/Info-tvOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.mousavian.FileProvider-tvOS";
PRODUCT_NAME = FileProvider;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0;
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
7993965F1D48B7BF00086753 /* Build configuration list for PBXProject "FileProvider" */ = {
isa = XCConfigurationList;
buildConfigurations = (
799396601D48B7BF00086753 /* Debug */,
799396611D48B7BF00086753 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7993966F1D48B7F600086753 /* Build configuration list for PBXNativeTarget "FileProvider iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7993966D1D48B7F600086753 /* Debug */,
7993966E1D48B7F600086753 /* Release */,
);
defaultConfigurationIsVisible = 0;
};
7993967A1D48B80D00086753 /* Build configuration list for PBXNativeTarget "FileProvider OSX" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7993967B1D48B80D00086753 /* Debug */,
7993967C1D48B80D00086753 /* Release */,
);
defaultConfigurationIsVisible = 0;
};
799396871D48B82700086753 /* Build configuration list for PBXNativeTarget "FileProvider tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
799396881D48B82700086753 /* Debug */,
799396891D48B82700086753 /* Release */,
);
defaultConfigurationIsVisible = 0;
};
/* End XCConfigurationList section */
};
rootObject = 7993965C1D48B7BF00086753 /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:FileProvider.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "799396741D48B80D00086753"
BuildableName = "FileProvider.framework"
BlueprintName = "FileProvider OSX"
ReferencedContainer = "container:FileProvider.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "799396741D48B80D00086753"
BuildableName = "FileProvider.framework"
BlueprintName = "FileProvider OSX"
ReferencedContainer = "container:FileProvider.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "799396741D48B80D00086753"
BuildableName = "FileProvider.framework"
BlueprintName = "FileProvider OSX"
ReferencedContainer = "container:FileProvider.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "799396661D48B7F600086753"
BuildableName = "FileProvider.framework"
BlueprintName = "FileProvider iOS"
ReferencedContainer = "container:FileProvider.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "799396661D48B7F600086753"
BuildableName = "FileProvider.framework"
BlueprintName = "FileProvider iOS"
ReferencedContainer = "container:FileProvider.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "799396661D48B7F600086753"
BuildableName = "FileProvider.framework"
BlueprintName = "FileProvider iOS"
ReferencedContainer = "container:FileProvider.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "799396811D48B82700086753"
BuildableName = "FileProvider.framework"
BlueprintName = "FileProvider tvOS"
ReferencedContainer = "container:FileProvider.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "799396811D48B82700086753"
BuildableName = "FileProvider.framework"
BlueprintName = "FileProvider tvOS"
ReferencedContainer = "container:FileProvider.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "799396811D48B82700086753"
BuildableName = "FileProvider.framework"
BlueprintName = "FileProvider tvOS"
ReferencedContainer = "container:FileProvider.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.3.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.3.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.3.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
+4 -2
View File
@@ -24,7 +24,7 @@ Local and WebDAV providers are fully tested and can be used in production enviro
- [x] **LocalFileProvider** a wrapper around `NSFileManager` with some additions like searching and reading a portion of file.
- [x] **WebDAVFileProvider** WebDAV protocol is usual file transmission system on Macs.
- [ ] **SMBFileProvider** SMB/CIFS and SMB2/3 are file and printer sharing protocol which is originated from IBM & Microsoft and SMB2/3 is now replacing AFP protocol on MacOS. I implemented data types and some basic functions but *main interface is not implemented yet!*
- [ ] **DropboxFileProvider**
- [ ] **DropboxFileProvider** *partially implemented*
- [ ] **FTPFileProvider**
- [ ] **AmazonS3FileProvider**
@@ -82,10 +82,12 @@ For remote file providers authentication may be necessary:
let credential = NSURLCredential(user: "user", password: "pass", persistence: NSURLCredentialPersistence.Permanent)
let webdavProvider = WebDAVFileProvider(baseURL: "http://www.example.com/dav", credential: credential)
* For Dropbox, user is clientID and password is Token which both must be retrieved via [OAuth2 API of Dropbox](https://www.dropbox.com/developers/reference/oauth-guide). There are libraries like [p2/OAuth2](https://github.com/p2/OAuth2) or [OAuthSwift](https://github.com/OAuthSwift/OAuthSwift) which can facilate the procedure to retrieve token.
For interaction with UI, set delegate variable of `FileProvider` object
You can use `absoluteURL()` method if provider to get direct access url (local or remote files) for some file systems which allows to do so (Dropbox doesn't support)
You can use `absoluteURL()` method if provider to get direct access url (local or remote files) for some file systems which allows to do so (Dropbox doesn't support and returns path simply)
### Delegates
File diff suppressed because it is too large Load Diff
-630
View File
@@ -1,630 +0,0 @@
//
// SMBTransmitter.swift
// FileProvider
//
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
protocol SMBRequest {
func data() -> NSData
}
protocol SMBResponse {
init? (data: NSData)
}
internal func encode<T>(inout value: T) -> NSData {
return withUnsafePointer(&value) { p in
NSData(bytes: p, length: sizeofValue(value))
}
}
internal func decode<T>(data: NSData) -> T {
let pointer = UnsafeMutablePointer<T>.alloc(sizeof(T.Type))
data.getBytes(pointer, length: sizeof(T.Type))
return pointer.move()
}
// This client implementation is for little-endian platform, namely x86, x64 & arm
// For big-endian platforms like PowerPC, there must be a huge overhaul
class SMBProtocolClient: TCPSocketClient {
var currentMessageID: UInt64 = 0
func negotiateToSMB2() -> SMB2.NegotiateResponse? {
let smbHeader = SMB2.Header(command: .NEGOTIATE, creditRequestResponse: 126, messageId: messageId(), treeId: 0, sessionId: 0)
currentMessageID += 1
let negMessage = SMB2.NegotiateRequest(request: SMB2.NegotiateRequest.Header(capabilities: []))
SMBProtocolClient.createSMB2Message(smbHeader, message: negMessage)
do {
try self.send(data: nil)
} catch _ {
return nil
}
self.waitUntilResponse()
let response = try? SMBProtocolClient.digestSMB2Message(dataReceived)
return response??.message as? SMB2.NegotiateResponse
}
func sessionSetupForSMB2() -> SMB2.SessionSetupResponse? {
return nil
}
func messageId() -> UInt64 {
defer {
currentMessageID += 1
}
return currentMessageID
}
// MARK: create and analyse messages
class func determineSMBVersion(data: NSData) -> Float {
var smbverChar: Int8 = 0
data.getBytes(&smbverChar, length: 1)
let version = 0 - smbverChar
return Float(version)
}
class func digestSMBMessage(data: NSData) throws -> (header: SMB1.Header, blocks: [(params: [UInt16], message: NSData?)]) {
guard data.length > 30 else {
throw NSURLError.BadServerResponse
}
var buffer = [UInt8](count: data.length, repeatedValue: 0)
guard determineSMBVersion(data) == 1 else {
throw SMBFileProviderError.IncompatibleHeader
}
let headersize = sizeof(SMB1.Header.self)
let header: SMB1.Header = decode(data)
var blocks = [(params: [UInt16], message: NSData?)]()
var offset = headersize
while offset < data.length {
let paramWords: [UInt16]
let paramWordsCount = Int(buffer[offset])
guard data.length > (paramWordsCount * 2 + offset) else {
throw SMBFileProviderError.IncorrectParamsLength
}
offset += sizeof(UInt8)
var rawParamWords = [UInt8](buffer[offset..<(offset + paramWordsCount * 2)])
let paramData = NSData(bytesNoCopy: &rawParamWords, length: rawParamWords.count)
paramWords = decode(paramData)
offset += paramWordsCount * 2
let messageBytesCountLittleEndian = [UInt8](buffer[offset...(offset + 1)])
let messageBytesCount = Int(UnsafePointer<UInt16>(messageBytesCountLittleEndian).memory)
offset += sizeof(UInt16)
guard data.length >= (offset + messageBytesCount) else {
throw SMBFileProviderError.IncorrectMessageLength
}
var rawMessage = [UInt8](buffer[offset..<(offset + messageBytesCount)])
offset += messageBytesCount
let message = NSData(bytes: &rawMessage, length: rawMessage.count)
blocks.append((params: paramWords, message: message))
}
return (header, blocks)
}
class func digestSMB2Message(data: NSData) throws -> (header: SMB2.Header, message: SMBResponse?)? {
guard data.length > 65 else {
throw NSURLError.BadServerResponse
}
guard determineSMBVersion(data) == 2 else {
throw SMBFileProviderError.IncompatibleHeader
}
let headersize = sizeof(SMB2.Header.self)
let headerData = data.subdataWithRange(NSRange(location: 0, length: headersize))
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:
return (header, SMB2.NegotiateResponse(data: messageData))
case .SESSION_SETUP:
return (header, SMB2.SessionSetupResponse(data: messageData))
case .LOGOFF:
return (header, SMB2.LogOff(data: messageData))
case .TREE_CONNECT:
return (header, SMB2.TreeConnectResponse(data: messageData))
case .TREE_DISCONNECT:
return (header, SMB2.TreeDisconnect(data: messageData))
case .CREATE:
return (header, SMB2.CreateResponse(data: messageData))
case .CLOSE:
return (header, SMB2.CloseResponse(data: messageData))
case .FLUSH:
return (header, SMB2.FlushResponse(data: messageData))
case .READ:
return (header, nil) // FIXME:
case .WRITE:
return (header, nil) // FIXME:
case .LOCK:
return (header, nil) // FIXME:
case .IOCTL:
return (header, nil)
case .CANCEL:
return (header, nil)
case .ECHO:
return (header, SMB2.Echo(data: messageData))
case .QUERY_DIRECTORY:
return (header, nil) // FIXME:
case .CHANGE_NOTIFY:
return (header, nil) // FIXME:
case .QUERY_INFO:
return (header, nil) // FIXME:
case .SET_INFO:
return (header, nil) // FIXME:
case .OPLOCK_BREAK:
return (header, nil) // FIXME:
case .INVALID:
throw SMBFileProviderError.InvalidCommand
}
}
class func createSMBMessage(header: SMB1.Header, blocks: [(params: NSData?, message: NSData?)]) -> NSData {
var headerv = header
let result = NSMutableData(data: encode(&headerv))
for block in blocks {
var paramWordsCount = UInt8(block.params?.length ?? 0)
result.appendBytes(&paramWordsCount, length: sizeofValue(paramWordsCount))
if let params = block.params {
result.appendData(params)
}
var messageLen = UInt16(block.message?.length ?? 0)
result.appendBytes(&messageLen, length: sizeofValue(messageLen))
if let message = block.message {
result.appendData(message)
}
}
return result
}
class func createSMB2Message(header: SMB2.Header, message: SMBRequest) -> NSData {
var headerv = header
let result = NSMutableData(data: encode(&headerv))
result.appendData(message.data())
return result
}
}
struct SMBTime {
var time: UInt64
init(time: UInt64) {
self.time = time
}
init(unixTime: UInt) {
self.time = (UInt64(unixTime) + 11644473600) * 10000000
}
init(timeIntervalSince1970: NSTimeInterval) {
self.time = UInt64((timeIntervalSince1970 + 11644473600) * 10000000)
}
init(date: NSDate) {
self.init(timeIntervalSince1970: date.timeIntervalSince1970)
}
var unixTime: UInt {
return UInt(self.time / 10000000 - 11644473600)
}
var date: NSDate {
return NSDate(timeIntervalSince1970: Double(self.time) / 10000000 - 11644473600)
}
}
protocol FileProviderSMBHeader {
var protocolID: UInt32 { get }
static var protocolConst: UInt32 { get }
}
// SMB/CIFS Types
struct SMB1 {
struct Header { // 32 bytes
// header is always \u{ff}SMB
let protocolID: UInt32
static let protocolConst: UInt32 = 0x424d53ff
private var _command: UInt8
var command: Command {
get {
return Command(rawValue: _command) ?? .INVALID
}
set {
_command = newValue.rawValue
}
}
// error messages from the server to the client
private var _status: (UInt8, UInt8, UInt8, UInt8)
var error: (Class: UInt8, code: UInt16) {
get {
return (_status.0, UInt16(_status.2) + (UInt16(_status.3) << 8))
}
set {
_status = (newValue.Class, 0, UInt8(newValue.code & 0xff), UInt8(newValue.code >> 8))
}
}
var ntStatus: UInt32 {
get {
let statusLo = UInt32(_status.0) + UInt32(_status.1) << 8
let statusHi = UInt32(_status.2) + UInt32(_status.3) << 8
return statusHi << 16 + statusLo
}
set {
_status = (UInt8(newValue & 0xff), UInt8(newValue >> 8 & 0xff), UInt8(newValue >> 16 & 0xff), UInt8(newValue >> 24 & 0xff))
}
}
var flags: Flags
var flags2: Flags2
var pidHigh: UInt16
// encryption key used for validating messages over connectionless transports
private var _securityKey: (UInt16, UInt16)
var securityKey: UInt32 {
get {
return UInt32(_securityKey.1) << 16 + UInt32(_securityKey.0)
}
set {
_securityKey = (UInt16(newValue & 0xffff), UInt16(newValue >> 16))
}
}
/// Connection identifier
var securityCID: UInt16
/// Identifier of the sequence of a message over connectionless transports
var securitySequenceNumber: UInt16
private var ununsed: UInt16
var treeId: UInt16
var pidLow: UInt16
var userId: UInt16
var multiplexId: UInt16
var pid: UInt32 {
get {
return UInt32(pidLow) + UInt32(pidHigh) << 16
}
set {
pidLow = UInt16(newValue & 0xffff)
pidHigh = UInt16(newValue >> 16)
}
}
init(command: Command, ntStatus: UInt32 = 0, flags: Flags, flags2: Flags2 = [.LONG_NAMES, .ERR_STATUS, .UNICODE], securityKey: UInt32 = 0, securityCID: UInt16 = 0, securitySequenceNumber: UInt16 = 0, treeId: UInt16, pid: UInt32, userId: UInt16, multiplexId: UInt16) {
self.protocolID = Header.protocolConst
self._command = command.rawValue
_status = (UInt8(ntStatus & 0xff), UInt8(ntStatus >> 8 & 0xff), UInt8(ntStatus >> 16 & 0xff), UInt8(ntStatus >> 24 & 0xff))
self.flags = flags
self.flags2 = flags2
self._securityKey = (UInt16(securityKey & 0xffff), UInt16(securityKey >> 16))
self.securityCID = securityCID
self.securitySequenceNumber = securitySequenceNumber
self.ununsed = 0
self.treeId = treeId
self.pidLow = UInt16(pid & 0xffff)
self.pidHigh = UInt16(pid >> 16)
self.userId = userId
self.multiplexId = multiplexId
}
}
struct Flags: OptionSetType {
let rawValue: UInt8
init(rawValue: UInt8) {
self.rawValue = rawValue
}
/** This bit is set (1) in the NEGOTIATE (0x72) Response if the server supports
* LOCK_AND_READ (0x13) and WRITE_AND_UNLOCK (0x14) commands. */
static let LOCK_AND_READ_OK = Flags(rawValue: 0x01)
static let BUF_AVAIL = Flags(rawValue: 0x02)
static let CASE_INSENSITIVE = Flags(rawValue: 0x08)
static let CANONICALIZED_PATHS = Flags(rawValue: 0x10)
static let OPLOCK = Flags(rawValue: 0x20)
static let OPBATCH = Flags(rawValue: 0x40)
/** When on, this message is being sent from the server in response to a client request. */
static let REPLY = Flags(rawValue: 0x80)
}
struct Flags2: OptionSetType {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
/** Client: the message MAY contain long file names. */
static let LONG_NAMES = Flags2(rawValue: 0x0001)
/** Client: the client is aware of extended attributes (EAs). */
static let EAS = Flags2(rawValue: 0x0002)
/** Client: the client is requesting signing (if signing is not yet active) or the message
* being sent is signed. This bit is used on the SMB header of an SESSION_SETUP_ANDX */
static let SMB_SECURITY_SIGNATURE = Flags2(rawValue: 0x0004)
/// Reserved but not implemented.
static let IS_LONG_NAME = Flags2(rawValue: 0x0040)
/** client aware of Extended Security negotiation */
static let EXT_SEC = Flags2(rawValue: 0x0800)
/** any pathnames in this SMB SHOULD be resolved in the Distributed File System (DFS) */
static let DFS = Flags2(rawValue: 0x1000)
/**
* This flag is useful only on a read request. If the bit is set, then the client MAY read
* the file if the client does not have read permission but does have execute permission. */
static let PAGING_IO = Flags2(rawValue: 0x2000) // READ_IF_EXECUTE
/**
* Client: the server MUST return errors as 32-bit NTSTATUS codes in the response
* Server: the Status field in the header is formatted as an NTSTATUS cod */
static let ERR_STATUS = Flags2(rawValue: 0x4000)
/**
* Each field that contains a string in this SMB message MUST be encoded
* as an array of 16-bit Unicode characters */
static let UNICODE = Flags2(rawValue: 0x8000)
}
enum Command: UInt8 {
case CREATE_DIRECTORY = 0x00
case DELETE_DIRECTORY = 0x01
case OPEN = 0x02
case CREATE = 0x03
case CLOSE = 0x04
case FLUSH = 0x05
case DELETE = 0x06
case RENAME = 0x07
case QUERY_INFORMATION = 0x08
case SET_INFORMATION = 0x09
case READ = 0x0A
case WRITE = 0x0B
case LOCK_BYTE_RANGE = 0x0C
case UNLOCK_BYTE_RANGE = 0x0D
case CREATE_TEMPORARY = 0x0E
case CREATE_NEW = 0x0F
case CHECK_DIRECTORY = 0x10
case PROCESS_EXIT = 0x11
case SEEK = 0x12
case LOCK_AND_READ = 0x13
case WRITE_AND_UNLOCK = 0x14
case READ_RAW = 0x1A
case READ_MPX = 0x1B
case READ_MPX_SECONDARY = 0x1C
case WRITE_RAW = 0x1D
case WRITE_MPX = 0x1E
case WRITE_COMPLETE = 0x20
case SET_INFORMATION2 = 0x22
case QUERY_INFORMATION2 = 0x23
case LOCKING_ANDX = 0x24
case TRANSACTION = 0x25
case TRANSACTION_SECONDARY = 0x26
case IOCTL = 0x27
case IOCTL_SECONDARY = 0x28
case COPY = 0x29
case MOVE = 0x2A
case ECHO = 0x2B
case WRITE_AND_CLOSE = 0x2C
case OPEN_ANDX = 0x2D
case READ_ANDX = 0x2E
case WRITE_ANDX = 0x2F
case CLOSE_AND_TREE_DISC = 0x31
case TRANSACTION2 = 0x32
case TRANSACTION2_SECONDARY = 0x33
case FIND_CLOSE2 = 0x34
case FIND_NOTIFY_CLOSE = 0x35
case TREE_CONNECT = 0x70
case TREE_DISCONNECT = 0x71
case NEGOTIATE = 0x72
case SESSION_SETUP_ANDX = 0x73
case LOGOFF_ANDX = 0x74
case TREE_CONNECT_ANDX = 0x75
case QUERY_INFORMATION_DISK = 0x80
case SEARCH = 0x81
case FIND = 0x82
case FIND_UNIQUE = 0x83
case NT_TRANSACT = 0xA0
case NT_TRANSACT_SECONDARY = 0xA1
case NT_CREATE_ANDX = 0xA2
case NT_CANCEL = 0xA4
case OPEN_PRINT_FILE = 0xC0
case WRITE_PRINT_FILE = 0xC1
case CLOSE_PRINT_FILE = 0xC2
case GET_PRINT_QUEUE = 0xC3
case READ_BULK = 0xD8
case WRITE_BULK = 0xD9
case WRITE_BULK_DATA = 0xDA
case INVALID = 0xFE
}
}
/// Error Types and Description
enum NTStatus: UInt32, ErrorType, CustomStringConvertible {
case SUCCESS = 0x00000000
case NOT_IMPLEMENTED = 0xC0000002
case INVALID_DEVICE_REQUEST = 0xC0000010
case ILLEGAL_FUNCTION = 0xC00000AF
case NO_SUCH_FILE = 0xC000000F
case NO_SUCH_DEVICE = 0xC000000E
case OBJECT_NAME_NOT_FOUND = 0xC0000034
case OBJECT_PATH_INVALID = 0xC0000039
case OBJECT_PATH_NOT_FOUND = 0xC000003A
case OBJECT_PATH_SYNTAX_BAD = 0xC000003B
case DFS_EXIT_PATH_FOUND = 0xC000009B
case REDIRECTOR_NOT_STARTED = 0xC00000FB
case TOO_MANY_OPENED_FILES = 0xC000011F
case ACCESS_DENIED = 0xC0000022
case INVALID_LOCK_SEQUENCE = 0xC000001E
case INVALID_VIEW_SIZE = 0xC000001F
case ALREADY_COMMITTED = 0xC0000021
case PORT_CONNECTION_REFUSED = 0xC0000041
case THREAD_IS_TERMINATING = 0xC000004B
case DELETE_PENDING = 0xC0000056
case PRIVILEGE_NOT_HELD = 0xC0000061
case LOGON_FAILURE = 0xC000006D
case FILE_IS_A_DIRECTORY = 0xC00000BA
case FILE_RENAMED = 0xC00000D5
case PROCESS_IS_TERMINATING = 0xC000010A
case DIRECTORY_NOT_EMPTY = 0xC0000101
case CANNOT_DELETE = 0xC0000121
case FILE_NOT_AVAILABLE = 0xC0000467
case FILE_DELETED = 0xC0000123
case SMB_BAD_FID = 0x00060001
case INVALID_HANDLE = 0xC0000008
case OBJECT_TYPE_MISMATCH = 0xC0000024
case PORT_DISCONNECTED = 0xC0000037
case INVALID_PORT_HANDLE = 0xC0000042
case FILE_CLOSED = 0xC0000128
case HANDLE_NOT_CLOSABLE = 0xC0000235
case SECTION_TOO_BIG = 0xC0000040
case TOO_MANY_PAGING_FILES = 0xC0000097
case INSUFF_SERVER_RESOURCES = 0xC0000205
case OS2_INVALID_ACCESS = 0x000C0001
case ACCESS_DENIED_2 = 0xC00000CA
case DATA_ERROR = 0xC000009C
case NOT_SAME_DEVICE = 0xC00000D4
case NO_MORE_FILES = 0x80000006
case NO_MORE_ENTRIES = 0x8000001A
case UNSUCCESSFUL = 0xC0000001
case SHARING_VIOLATION = 0xC0000043
case FILE_LOCK_CONFLICT = 0xC0000054
case LOCK_NOT_GRANTED = 0xC0000055
case END_OF_FILE = 0xC0000011
case NOT_SUPPORTED = 0xC00000BB
case OBJECT_NAME_COLLISION = 0xC0000035
case INVALID_PARAMETER = 0xC000000D
case OS2_INVALID_LEVEL = 0x007C0001
case OS2_NEGATIVE_SEEK = 0x00830001
case RANGE_NOT_LOCKED = 0xC000007E
case OS2_NO_MORE_SIDS = 0x00710001
case OS2_CANCEL_VIOLATION = 0x00AD0001
case OS2_ATOMIC_LOCKS_NOT_SUPPORTED = 0x00AE0001
case INVALID_INFO_CLASS = 0xC0000003
case INVALID_PIPE_STATE = 0xC00000AD
case INVALID_READ_MODE = 0xC00000B4
case OS2_CANNOT_COPY = 0x010A0001
case STOPPED_ON_SYMLINK = 0x8000002D
case INSTANCE_NOT_AVAILABLE = 0xC00000AB
case PIPE_NOT_AVAILABLE = 0xC00000AC
case PIPE_BUSY = 0xC00000AE
case PIPE_CLOSING = 0xC00000B1
case PIPE_EMPTY = 0xC00000D9
case PIPE_DISCONNECTED = 0xC00000B0
case BUFFER_OVERFLOW = 0x80000005
case MORE_PROCESSING_REQUIRED = 0xC0000016
case EA_TOO_LARGE = 0xC0000050
case OS2_EAS_DIDNT_FIT = 0x01130001
case EAS_NOT_SUPPORTED = 0xC000004F
case EA_LIST_INCONSISTENT = 0x80000014
case OS2_EA_ACCESS_DENIED = 0x03E20001
case NOTIFY_ENUM_DIR = 0x0000010C
case INVALID_SMB = 0x00010002
case WRONG_PASSWORD = 0xC000006A
case PATH_NOT_COVERED = 0xC0000257
case NETWORK_NAME_DELETED = 0xC00000C9
case SMB_BAD_TID = 0x00050002
case BAD_NETWORK_NAME = 0xC00000CC
case BAD_DEVICE_TYPE = 0xC00000CB
case SMB_BAD_COMMAND = 0x00160002
case PRINT_QUEUE_FULL = 0xC00000C6
case NO_SPOOL_SPACE = 0xC00000C7
case PRINT_CANCELLED = 0xC00000C8
case UNEXPECTED_NETWORK_ERROR = 0xC00000C4
case IO_TIMEOUT = 0xC00000B5
case REQUEST_NOT_ACCEPTED = 0xC00000D0
case TOO_MANY_SESSIONS = 0xC00000CE
case SMB_BAD_UID = 0x005B0002
case SMB_USE_MPX = 0x00FA0002
case SMB_USE_STANDARD = 0x00FB0002
case SMB_CONTINUE_MPX = 0x00FC0002
case ACCOUNT_DISABLED = 0xC0000072
case ACCOUNT_EXPIRED = 0xC0000193
case INVALID_WORKSTATION = 0xC0000070
case INVALID_LOGON_HOURS = 0xC000006F
case PASSWORD_EXPIRED = 0xC0000071
case PASSWORD_MUST_CHANGE = 0xC0000224
case SMB_NO_SUPPORT = 0xFFFF0002
case MEDIA_WRITE_PROTECTED = 0xC00000A2
case NO_MEDIA_IN_DEVICE = 0xC0000013
case INVALID_DEVICE_STATE = 0xC0000184
case DATA_ERROR_2 = 0xC000003E
case CRC_ERROR = 0xC000003F
case DISK_CORRUPT_ERROR = 0xC0000032
case NONEXISTENT_SECTOR = 0xC0000015
case DEVICE_PAPER_EMPTY = 0x8000000E
case WRONG_VOLUME = 0xC0000012
case DISK_FULL = 0xC000007F
case BUFFER_TOO_SMALL = 0xC0000023
case BAD_IMPERSONATION_LEVEL = 0xC00000A5
case USER_SESSION_DELETED = 0xC0000203
case NETWORK_SESSION_EXPIRED = 0xC000035C
case SMB_TOO_MANY_UIDS = 0xC000205A
var description: String {
switch self {
case NOT_IMPLEMENTED, INVALID_DEVICE_REQUEST, ILLEGAL_FUNCTION:
return "Invalid Function."
case NO_SUCH_FILE, NO_SUCH_DEVICE, OBJECT_NAME_NOT_FOUND:
return "File not found."
case OBJECT_PATH_INVALID, OBJECT_PATH_NOT_FOUND, OBJECT_PATH_SYNTAX_BAD, DFS_EXIT_PATH_FOUND, REDIRECTOR_NOT_STARTED:
return "A component in the path prefix is not a directory."
case TOO_MANY_OPENED_FILES:
return "Too many open files. No FIDs are available."
case ACCESS_DENIED, INVALID_LOCK_SEQUENCE, INVALID_VIEW_SIZE, ALREADY_COMMITTED, PORT_CONNECTION_REFUSED, THREAD_IS_TERMINATING, DELETE_PENDING, PRIVILEGE_NOT_HELD, LOGON_FAILURE, FILE_IS_A_DIRECTORY, FILE_RENAMED, PROCESS_IS_TERMINATING, CANNOT_DELETE, FILE_DELETED:
return "Access denied."
case SMB_BAD_FID, INVALID_HANDLE, OBJECT_TYPE_MISMATCH, PORT_DISCONNECTED, INVALID_PORT_HANDLE, FILE_CLOSED, HANDLE_NOT_CLOSABLE:
return "Invalid FID."
case SECTION_TOO_BIG, TOO_MANY_PAGING_FILES, INSUFF_SERVER_RESOURCES:
return "Insufficient server memory to perform the requested operation."
case OS2_INVALID_ACCESS:
return "Invalid open mode."
case DATA_ERROR:
return "Bad data. (May be generated by IOCTL calls on the server.)"
case DIRECTORY_NOT_EMPTY:
return "Remove of directory failed because it was not empty."
case NOT_SAME_DEVICE:
return "A file system operation (such as a rename) across two devices was attempted."
case NO_MORE_FILES:
return "No (more) files found following a file search command."
case UNSUCCESSFUL:
return "General error."
case SHARING_VIOLATION:
return "Sharing violation. A requested open mode conflicts with the sharing mode of an existing file handle."
case FILE_LOCK_CONFLICT, LOCK_NOT_GRANTED:
return "A lock request specified an invalid locking mode, or conflicted with an existing file lock."
case END_OF_FILE:
return "Attempted to read beyond the end of the file."
case NOT_SUPPORTED:
return "This command is not supported by the server."
case OBJECT_NAME_COLLISION:
return "An attempt to create a file or directory failed because an object with the same pathname already exists."
case INVALID_PARAMETER:
return "A parameter supplied with the message is invalid."
case OS2_INVALID_LEVEL:
return "Invalid information level."
case OS2_NEGATIVE_SEEK:
return "An attempt was made to seek to a negative absolute offset within a file."
case RANGE_NOT_LOCKED:
return "The byte range specified in an unlock request was not locked."
case OS2_NO_MORE_SIDS:
return "Maximum number of searches has been exhausted."
case OS2_CANCEL_VIOLATION:
return "No lock request was outstanding for the supplied cancel region."
case OS2_ATOMIC_LOCKS_NOT_SUPPORTED:
return "The file system does not support atomic changes to the lock type."
case INVALID_INFO_CLASS, INVALID_PIPE_STATE, INVALID_READ_MODE:
return "Invalid named pipe."
case OS2_CANNOT_COPY:
return "The copy functions cannot be used."
case INSTANCE_NOT_AVAILABLE, PIPE_NOT_AVAILABLE, PIPE_BUSY:
return "All instances of the designated named pipe are busy."
case PIPE_CLOSING, PIPE_EMPTY:
return "The designated named pipe is in the process of being closed."
case PIPE_DISCONNECTED:
return "The designated named pipe exists, but there is no server process listening on the server side."
case BUFFER_OVERFLOW, MORE_PROCESSING_REQUIRED:
return "There is more data available to read on the designated named pipe."
case EA_TOO_LARGE, OS2_EAS_DIDNT_FIT:
return "Either there are no extended attributes, or the available extended attributes did not fit into the response."
case EAS_NOT_SUPPORTED:
return "The server file system does not support Extended Attributes."
case OS2_EA_ACCESS_DENIED:
return "Access to the extended attribute was denied."
default:
return ""
}
}
}
+385
View File
@@ -0,0 +1,385 @@
//
// DropboxFileProvider.swift
// FileProvider
//
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
public enum FileProviderDropboxErrorCode: Int {
case BadInputParameter = 400
case ExpiredToken = 401
case Forbidden = 403
case Endpoint = 409
case TooManyRequests = 429
case InternalServer = 500
case BadGateway = 502
}
public struct FileProviderDropboxError: ErrorType, CustomStringConvertible {
let code: FileProviderDropboxErrorCode
let path: String
public var description: String {
switch code {
case .BadInputParameter: return "Bad input parameter."
case .ExpiredToken: return "Bad or expired token. To fix this, you should re-authenticate the user."
case .Forbidden: return "Forbidden."
case .Endpoint: return "Endpoint-specific error."
case .TooManyRequests: return "Your app is making too many requests"
case .InternalServer: return "An error occurred on the Dropbox servers."
case .BadGateway: return "An error occurred on the Dropbox servers."
}
}
}
public final class DropboxFileObject: FileObject {
let serverTime: NSDate?
let id: String?
let rev: String?
init(absoluteURL: NSURL, name: String, path: String, size: Int64, serverTime: NSDate?, createdDate: NSDate?, modifiedDate: NSDate?, fileType: FileType, isHidden: Bool, isReadOnly: Bool, id: String?, rev: String?) {
self.serverTime = serverTime
self.id = id
self.rev = rev
super.init(absoluteURL: absoluteURL, name: name, path: path, size: size, createdDate: createdDate, modifiedDate: modifiedDate, fileType: fileType, isHidden: isHidden, isReadOnly: isReadOnly)
}
}
// Because this class uses NSURLSession, it's necessary to disable App Transport Security
// in case of using this class with unencrypted HTTP connection.
public class DropboxFileProvider: NSObject, FileProviderBasic {
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 {
willSet {
assert(_session == nil, "It's not effective to change dispatch_queue property after session is initialized.")
}
}
public weak var delegate: FileProviderDelegate?
public let credential: NSURLCredential?
private var _session: NSURLSession?
private var session: NSURLSession {
if _session == nil {
let queue = NSOperationQueue()
//queue.underlyingQueue = dispatch_queue
_session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: self, delegateQueue: queue)
}
return _session!
}
init? (baseURL: NSURL, credential: NSURLCredential?) {
if !["http", "https"].contains(baseURL.scheme.lowercaseString) {
return nil
}
self.baseURL = baseURL
dispatch_queue = dispatch_queue_create("FileProvider.\(type)", DISPATCH_QUEUE_CONCURRENT)
//let url = baseURL.absoluteString
self.credential = credential
}
deinit {
_session?.invalidateAndCancel()
}
public func contentsOfDirectoryAtPath(path: String, completionHandler: ((contents: [FileObject], error: ErrorType?) -> Void)) {
NotImplemented()
}
public func attributesOfItemAtPath(path: String, completionHandler: ((attributes: FileObject?, error: ErrorType?) -> Void)) {
let url = NSURL(string: "https://api.dropboxapi.com/2/files/list_revisions")!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let requestDictionary = ["path": correctPath(path)!]
request.HTTPBody = dictionaryToJSON(requestDictionary)?.dataUsingEncoding(NSUTF8StringEncoding)
let task = session.dataTaskWithRequest(request) { (data, response, error) in
if let response = response as? NSHTTPURLResponse {
defer {
self.delegateNotify(FileOperation.Create(path: path), error: error)
}
let code = FileProviderDropboxErrorCode(rawValue: response.statusCode)
let dbError: FileProviderDropboxError? = code != nil ? FileProviderDropboxError(code: code!, path: path) : nil
if let data = data, let jsonStr = String(data: data, encoding: NSUTF8StringEncoding) {
let json = self.jsonToDictionary(jsonStr)
if (json?["is_deleted"] as? NSNumber)?.boolValue ?? false, let entries = json?["entries"] as? [AnyObject] where entries.count > 0 , let entry = entries[0] as? [String: AnyObject], let file = self.mapToFileObject(entry) {
completionHandler(attributes: file, error: dbError)
return
}
}
completionHandler(attributes: nil, error: dbError)
return
}
completionHandler(attributes: nil, error: error)
}
task.resume()
}
public weak var fileOperationDelegate: FileOperationDelegate?
}
extension DropboxFileProvider: FileProviderOperations {
public func createFolder(folderName: String, atPath: String, completionHandler: SimpleCompletionHandler) {
let path = (atPath as NSString).stringByAppendingPathComponent(folderName) + "/"
doOperation(.Create(path: path), completionHandler: completionHandler)
}
public func createFile(fileAttribs: FileObject, atPath path: String, contents data: NSData?, completionHandler: SimpleCompletionHandler) {
NotImplemented()
}
public func moveItemAtPath(path: String, toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) {
doOperation(.Move(source: path, destination: toPath), completionHandler: completionHandler)
}
public func copyItemAtPath(path: String, toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) {
doOperation(.Copy(source: path, destination: toPath), completionHandler: completionHandler)
}
public func removeItemAtPath(path: String, completionHandler: SimpleCompletionHandler) {
doOperation(.Remove(path: path), completionHandler: completionHandler)
}
private func doOperation(operation: FileOperation, completionHandler: SimpleCompletionHandler) {
let url: String
var path: String?, fromPath: String?, toPath: String?
switch operation {
case .Create(path: let p):
url = "https://api.dropboxapi.com/2/files/create_folder"
path = p
case .Copy(source: let fp, destination: let tp):
url = "https://api.dropboxapi.com/2/files/copy"
fromPath = fp
toPath = tp
case .Move(source: let fp, destination: let tp):
url = "https://api.dropboxapi.com/2/files/move"
fromPath = fp
toPath = tp
case .Modify(path: let p):
return
case .Remove(path: let p):
url = "https://api.dropboxapi.com/2/files/delete"
path = p
case .Link(link: _, target: _):
return
}
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
request.HTTPMethod = "POST"
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
var requestDictionary = [String: AnyObject]()
requestDictionary["path"] = correctPath(path)
requestDictionary["from_path"] = correctPath(fromPath)
requestDictionary["to_path"] = correctPath(toPath)
request.HTTPBody = dictionaryToJSON(requestDictionary)?.dataUsingEncoding(NSUTF8StringEncoding)
let task = session.dataTaskWithRequest(request) { (data, response, error) in
if let response = response as? NSHTTPURLResponse {
let code = FileProviderDropboxErrorCode(rawValue: response.statusCode)
let dbError: FileProviderDropboxError? = code != nil ? FileProviderDropboxError(code: code!, path: path ?? fromPath ?? "") : nil
defer {
self.delegateNotify(operation, error: error ?? dbError)
}
/*if let data = data, let jsonStr = String(data: data, encoding: NSUTF8StringEncoding) {
let json = self.jsonToDictionary(jsonStr)
}*/
completionHandler?(error: dbError)
return
}
completionHandler?(error: error)
}
task.resume()
}
public func copyLocalFileToPath(localFile: NSURL, toPath: String, completionHandler: SimpleCompletionHandler) {
NotImplemented()
let request = NSMutableURLRequest(URL: absoluteURL(toPath))
request.HTTPMethod = "PUT"
let task = session.uploadTaskWithRequest(request, fromFile: localFile) { (data, response, error) in
completionHandler?(error: error)
self.delegateNotify(.Move(source: localFile.absoluteString, destination: toPath), error: error)
}
task.taskDescription = self.dictionaryToJSON(["type": "Copy", "source": localFile.absoluteString, "dest": toPath])
task.resume()
}
public func copyPathToLocalFile(path: String, toLocalURL: NSURL, completionHandler: SimpleCompletionHandler) {
NotImplemented()
let request = NSMutableURLRequest(URL: absoluteURL(path))
let task = session.downloadTaskWithRequest(request) { (sourceFileURL, response, error) in
if let sourceFileURL = sourceFileURL {
do {
try NSFileManager.defaultManager().copyItemAtURL(sourceFileURL, toURL: toLocalURL)
} catch let e {
completionHandler?(error: e)
return
}
}
completionHandler?(error: error)
}
task.taskDescription = self.dictionaryToJSON(["type": "Copy", "source": path, "dest": toLocalURL.absoluteString])
task.resume()
}
}
extension DropboxFileProvider: FileProviderReadWrite {
public func contentsAtPath(path: String, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void)) {
self.contentsAtPath(path, offset: 0, length: -1, completionHandler: completionHandler)
}
public func contentsAtPath(path: String, offset: Int64, length: Int, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void)) {
let url = NSURL(string: "https://api.dropboxapi.com/2/files/download")!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "GET"
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
if length > 0 {
request.setValue("bytes=\(offset)-\(offset + length)", forHTTPHeaderField: "Range")
} else if offset > 0 && length < 0 {
request.setValue("bytes=\(offset)-", forHTTPHeaderField: "Range")
}
let requestDictionary = ["path": path]
request.setValue(dictionaryToJSON(requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
let task = session.downloadTaskWithRequest(request, completionHandler: { (cacheURL, response, error) in
guard let cacheURL = cacheURL, let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode < 300 else {
let code = FileProviderDropboxErrorCode(rawValue: (response as? NSHTTPURLResponse)?.statusCode ?? -1)
let dbError: FileProviderDropboxError? = code != nil ? FileProviderDropboxError(code: code!, path: path) : nil
completionHandler(contents: nil, error: dbError ?? error)
return
}
let destURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(cacheURL.lastPathComponent ?? "tmpfile")
do {
try NSFileManager.defaultManager().moveItemAtURL(cacheURL, toURL: destURL)
completionHandler(contents: NSData(contentsOfURL: destURL), error: error)
} catch let e {
completionHandler(contents: nil, error: e)
}
})
task.resume()
}
public func writeContentsAtPath(path: String, contents data: NSData, atomically: Bool = false, completionHandler: SimpleCompletionHandler) {
NotImplemented()
let url = atomically ? absoluteURL(path).URLByAppendingPathExtension("tmp") : absoluteURL(path)
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "PUT"
let task = session.uploadTaskWithRequest(request, fromData: data) { (data, response, error) in
defer {
self.delegateNotify(.Modify(path: path), error: error)
}
if atomically {
self.moveItemAtPath((path as NSString).stringByAppendingPathExtension("tmp")!, toPath: path, completionHandler: completionHandler)
}
if let error = error {
// If there is no error, completionHandler has been executed by move command
completionHandler?(error: error)
}
}
task.taskDescription = self.dictionaryToJSON(["type": "Modify", "source": path])
task.resume()
}
public func searchFilesAtPath(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObject) -> Void)?, completionHandler: ((files: [FileObject], error: ErrorType?) -> Void)) {
NotImplemented()
}
private func registerNotifcation(path: String, eventHandler: (() -> Void)) {
/* There is two ways to monitor folders chaging in Dropbox. Either using webooks
* which means you have to implement a server to translate it to push notifications
* or using apiv2 list_folder/longpoll method. The second one is implemeted here.
* Tough webhooks are much more efficient, longpoll is much simpler to implement!
* You can implemnt your own webhook service and replace this method accordingly.
*/
NotImplemented()
}
private func unregisterNotifcation(path: String) {
NotImplemented()
}
}
internal extension DropboxFileProvider {
private func mapToFileObject(jsonStr: String) -> DropboxFileObject? {
guard let json = self.jsonToDictionary(jsonStr) else { return nil }
return self.mapToFileObject(json)
}
private func mapToFileObject(json: [String: AnyObject]) -> DropboxFileObject? {
guard let name = json["name"] as? String else { return nil }
guard let path = json["path_display"] as? String else { return nil }
let href = NSURL(string: path)!
let size = (json["size"] as? NSNumber)?.longLongValue ?? -1
let serverTime = resolveDate(json["server_modified"] as? String ?? "")
let modifiedDate = resolveDate(json["client_modified"] as? String ?? "")
let isDirectory = (json[".tag"] as? String) == "folder"
let isReadonly = (json["sharing_info"]?["read_only"] as? NSNumber)?.boolValue ?? false
let id = json["id"] as? String
let rev = json["id"] as? String
return DropboxFileObject(absoluteURL: href, name: name, path: path, size: size, serverTime: serverTime, createdDate: nil, modifiedDate: modifiedDate, fileType: isDirectory ? .Directory : .Regular, isHidden: false, isReadOnly: isReadonly, id: id, rev: rev)
}
private func delegateNotify(operation: FileOperation, error: ErrorType?) {
dispatch_async(dispatch_get_main_queue(), {
if error == nil {
self.delegate?.fileproviderSucceed(self, operation: operation)
} else {
self.delegate?.fileproviderFailed(self, operation: operation)
}
})
}
}
// MARK: URLSession delegate
extension DropboxFileProvider: NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
public func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
return
}
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
}
guard let type = json["type"] as? String, let source = json["source"] as? String else {
return
}
let dest = json["dest"] as? String
let op : FileOperation
switch type {
case "Create":
op = .Create(path: source)
case "Copy":
guard let dest = dest else { return }
op = .Copy(source: source, destination: dest)
case "Move":
guard let dest = dest else { return }
op = .Move(source: source, destination: dest)
case "Modify":
op = .Modify(path: source)
case "Remove":
op = .Remove(path: source)
case "Link":
guard let dest = dest else { return }
op = .Link(link: source, target: dest)
default:
return
}
let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
self.delegate?.fileproviderProgress(self, operation: op, progress: progress)
}
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
}
self.delegate?.fileproviderProgress(self, operation: .Copy(source: source, destination: dest), progress: Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
}
}
+35
View File
@@ -0,0 +1,35 @@
//
// FileProvider iOS.h
// FileProvider iOS
//
// Created by Amir Abbas Mousavian on 5/6/95.
//
//
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
#import <UIKit/UIKit.h>
//! Project version number for FileProvider iOS.
FOUNDATION_EXPORT double FileProvider_iOSVersionNumber;
//! Project version string for FileProvider iOS.
FOUNDATION_EXPORT const unsigned char FileProvider_iOSVersionString[];
#elif defined TARGET_OS_TV
#import <UIKit/UIKit.h>
//! Project version number for FileProvider tvOS.
FOUNDATION_EXPORT double FileProvider_tvOSVersionNumber;
//! Project version string for FileProvider tvOS.
FOUNDATION_EXPORT const unsigned char FileProvider_tvOSVersionString[];
#elif defined TARGET_OS_MAC
#import <Cocoa/Cocoa.h>
//! Project version number for FileProvider OSX.
FOUNDATION_EXPORT double FileProvider_OSXVersionNumber;
//! Project version string for FileProvider OSX.
FOUNDATION_EXPORT const unsigned char FileProvider_OSXVersionString[];
#else
// Unsupported platform
#endif
// In this header, you should import all the public headers of your framework using statements like #import <FileProvider_iOS/PublicHeader.h>
@@ -7,7 +7,7 @@
//
import Foundation
#if os(iOS)
#if os(iOS) || os(tvOS)
import UIKit
public typealias ImageClass = UIImage
#elseif os(OSX)
@@ -185,6 +185,11 @@ extension FileProviderBasic {
return url.URLByStandardizingPath!.absoluteString.stringByReplacingOccurrencesOfString(baseURL.absoluteString, withString: "/").stringByRemovingPercentEncoding!
}
internal func correctPath(path: String?) -> String? {
guard let path = path else { return nil }
return path.hasPrefix("/") ? path : "/" + path
}
public func fileByUniqueName(filePath: String) -> String {
let fileUrl = NSURL(fileURLWithPath: filePath)
let dirPath = fileUrl.URLByDeletingLastPathComponent?.path ?? ""
@@ -239,21 +244,25 @@ extension FileProviderBasic {
assert(false, "method not implemented")
}
internal func resolveRFCDate(httpDateString: String) -> NSDate? {
internal func resolveDate(dateString: String) -> NSDate? {
let dateFor: NSDateFormatter = NSDateFormatter()
dateFor.locale = NSLocale(localeIdentifier: "en_US")
dateFor.dateFormat = "EEE',' dd' 'MMM' 'yyyy HH':'mm':'ss zzz"
if let rfc1123 = dateFor.dateFromString(httpDateString) {
if let rfc1123 = dateFor.dateFromString(dateString) {
return rfc1123
}
dateFor.dateFormat = "EEEE',' dd'-'MMM'-'yy HH':'mm':'ss z"
if let rfc850 = dateFor.dateFromString(httpDateString) {
if let rfc850 = dateFor.dateFromString(dateString) {
return rfc850
}
dateFor.dateFormat = "EEE MMM d HH':'mm':'ss yyyy"
if let asctime = dateFor.dateFromString(httpDateString) {
if let asctime = dateFor.dateFromString(dateString) {
return asctime
}
dateFor.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssz"
if let isotime = dateFor.dateFromString(dateString) {
return isotime
}
//self.init()
return nil
}
+194
View File
@@ -0,0 +1,194 @@
//
// SMBTransmitter.swift
// FileProvider
//
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
internal func encode<T>(inout value: T) -> NSData {
return withUnsafePointer(&value) { p in
NSData(bytes: p, length: sizeofValue(value))
}
}
internal func encode<T>(value: T) -> NSData {
var value = value
return withUnsafePointer(&value) { p in
NSData(bytes: p, length: sizeofValue(value))
}
}
internal func decode<T>(data: NSData) -> T {
let pointer = UnsafeMutablePointer<T>.alloc(sizeof(T.Type))
data.getBytes(pointer, length: sizeof(T.Type))
return pointer.move()
}
// This client implementation is for little-endian platform, namely x86, x64 & arm
// For big-endian platforms like PowerPC, there must be a huge overhaul
class SMBProtocolClient: TCPSocketClient {
var currentMessageID: UInt64 = 0
func negotiateToSMB2() -> SMB2.NegotiateResponse? {
let smbHeader = SMB2.Header(command: .NEGOTIATE, creditRequestResponse: 126, messageId: messageId(), treeId: 0, sessionId: 0)
currentMessageID += 1
let negMessage = SMB2.NegotiateRequest(request: SMB2.NegotiateRequest.Header(capabilities: []))
SMBProtocolClient.createSMB2Message(smbHeader, message: negMessage)
do {
try self.send(data: nil)
} catch _ {
return nil
}
self.waitUntilResponse()
let response = try? SMBProtocolClient.digestSMB2Message(dataReceived)
return response??.message as? SMB2.NegotiateResponse
}
func sessionSetupForSMB2() -> SMB2.SessionSetupResponse? {
return nil
}
func messageId() -> UInt64 {
defer {
currentMessageID += 1
}
return currentMessageID
}
// MARK: create and analyse messages
class func determineSMBVersion(data: NSData) -> Float {
var smbverChar: Int8 = 0
data.getBytes(&smbverChar, length: 1)
let version = 0 - smbverChar
return Float(version)
}
class func digestSMBMessage(data: NSData) throws -> (header: SMB1.Header, blocks: [(params: [UInt16], message: NSData?)]) {
guard data.length > 30 else {
throw NSURLError.BadServerResponse
}
var buffer = [UInt8](count: data.length, repeatedValue: 0)
guard determineSMBVersion(data) == 1 else {
throw SMBFileProviderError.IncompatibleHeader
}
let headersize = sizeof(SMB1.Header.self)
let header: SMB1.Header = decode(data)
var blocks = [(params: [UInt16], message: NSData?)]()
var offset = headersize
while offset < data.length {
let paramWords: [UInt16]
let paramWordsCount = Int(buffer[offset])
guard data.length > (paramWordsCount * 2 + offset) else {
throw SMBFileProviderError.IncorrectParamsLength
}
offset += sizeof(UInt8)
var rawParamWords = [UInt8](buffer[offset..<(offset + paramWordsCount * 2)])
let paramData = NSData(bytesNoCopy: &rawParamWords, length: rawParamWords.count)
paramWords = decode(paramData)
offset += paramWordsCount * 2
let messageBytesCountLittleEndian = [UInt8](buffer[offset...(offset + 1)])
let messageBytesCount = Int(UnsafePointer<UInt16>(messageBytesCountLittleEndian).memory)
offset += sizeof(UInt16)
guard data.length >= (offset + messageBytesCount) else {
throw SMBFileProviderError.IncorrectMessageLength
}
var rawMessage = [UInt8](buffer[offset..<(offset + messageBytesCount)])
offset += messageBytesCount
let message = NSData(bytes: &rawMessage, length: rawMessage.count)
blocks.append((params: paramWords, message: message))
}
return (header, blocks)
}
class func digestSMB2Message(data: NSData) throws -> (header: SMB2.Header, message: SMBResponse?)? {
guard data.length > 65 else {
throw NSURLError.BadServerResponse
}
guard determineSMBVersion(data) == 2 else {
throw SMBFileProviderError.IncompatibleHeader
}
let headersize = sizeof(SMB2.Header.self)
let headerData = data.subdataWithRange(NSRange(location: 0, length: headersize))
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:
return (header, SMB2.NegotiateResponse(data: messageData))
case .SESSION_SETUP:
return (header, SMB2.SessionSetupResponse(data: messageData))
case .LOGOFF:
return (header, SMB2.LogOff(data: messageData))
case .TREE_CONNECT:
return (header, SMB2.TreeConnectResponse(data: messageData))
case .TREE_DISCONNECT:
return (header, SMB2.TreeDisconnect(data: messageData))
case .CREATE:
return (header, SMB2.CreateResponse(data: messageData))
case .CLOSE:
return (header, SMB2.CloseResponse(data: messageData))
case .FLUSH:
return (header, SMB2.FlushResponse(data: messageData))
case .READ:
return (header, nil) // FIXME:
case .WRITE:
return (header, nil) // FIXME:
case .LOCK:
return (header, nil) // FIXME:
case .IOCTL:
return (header, nil)
case .CANCEL:
return (header, nil)
case .ECHO:
return (header, SMB2.Echo(data: messageData))
case .QUERY_DIRECTORY:
return (header, nil) // FIXME:
case .CHANGE_NOTIFY:
return (header, nil) // FIXME:
case .QUERY_INFO:
return (header, nil) // FIXME:
case .SET_INFO:
return (header, nil) // FIXME:
case .OPLOCK_BREAK:
return (header, nil) // FIXME:
case .INVALID:
throw SMBFileProviderError.InvalidCommand
}
}
class func createSMBMessage(header: SMB1.Header, blocks: [(params: NSData?, message: NSData?)]) -> NSData {
var headerv = header
let result = NSMutableData(data: encode(&headerv))
for block in blocks {
var paramWordsCount = UInt8(block.params?.length ?? 0)
result.appendBytes(&paramWordsCount, length: sizeofValue(paramWordsCount))
if let params = block.params {
result.appendData(params)
}
var messageLen = UInt16(block.message?.length ?? 0)
result.appendBytes(&messageLen, length: sizeofValue(messageLen))
if let message = block.message {
result.appendData(message)
}
}
return result
}
class func createSMB2Message(header: SMB2.Header, message: SMBRequest) -> NSData {
var headerv = header
let result = NSMutableData(data: encode(&headerv))
result.appendData(message.data())
return result
}
}
protocol FileProviderSMBHeader {
var protocolID: UInt32 { get }
static var protocolConst: UInt32 { get }
}
+217
View File
@@ -0,0 +1,217 @@
//
// CIFSTypes.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/30/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
// SMB/CIFS Types
struct SMB1 {
struct Header { // 32 bytes
// header is always \u{ff}SMB
let protocolID: UInt32
static let protocolConst: UInt32 = 0x424d53ff
private var _command: UInt8
var command: Command {
get {
return Command(rawValue: _command) ?? .INVALID
}
set {
_command = newValue.rawValue
}
}
// error messages from the server to the client
private var _status: (UInt8, UInt8, UInt8, UInt8)
var error: (Class: UInt8, code: UInt16) {
get {
return (_status.0, UInt16(_status.2) + (UInt16(_status.3) << 8))
}
set {
_status = (newValue.Class, 0, UInt8(newValue.code & 0xff), UInt8(newValue.code >> 8))
}
}
var ntStatus: UInt32 {
get {
let statusLo = UInt32(_status.0) + UInt32(_status.1) << 8
let statusHi = UInt32(_status.2) + UInt32(_status.3) << 8
return statusHi << 16 + statusLo
}
set {
_status = (UInt8(newValue & 0xff), UInt8(newValue >> 8 & 0xff), UInt8(newValue >> 16 & 0xff), UInt8(newValue >> 24 & 0xff))
}
}
var flags: Flags
var flags2: Flags2
var pidHigh: UInt16
// encryption key used for validating messages over connectionless transports
private var _securityKey: (UInt16, UInt16)
var securityKey: UInt32 {
get {
return UInt32(_securityKey.1) << 16 + UInt32(_securityKey.0)
}
set {
_securityKey = (UInt16(newValue & 0xffff), UInt16(newValue >> 16))
}
}
/// Connection identifier
var securityCID: UInt16
/// Identifier of the sequence of a message over connectionless transports
var securitySequenceNumber: UInt16
private var ununsed: UInt16
var treeId: UInt16
var pidLow: UInt16
var userId: UInt16
var multiplexId: UInt16
var pid: UInt32 {
get {
return UInt32(pidLow) + UInt32(pidHigh) << 16
}
set {
pidLow = UInt16(newValue & 0xffff)
pidHigh = UInt16(newValue >> 16)
}
}
init(command: Command, ntStatus: UInt32 = 0, flags: Flags, flags2: Flags2 = [.LONG_NAMES, .ERR_STATUS, .UNICODE], securityKey: UInt32 = 0, securityCID: UInt16 = 0, securitySequenceNumber: UInt16 = 0, treeId: UInt16, pid: UInt32, userId: UInt16, multiplexId: UInt16) {
self.protocolID = Header.protocolConst
self._command = command.rawValue
_status = (UInt8(ntStatus & 0xff), UInt8(ntStatus >> 8 & 0xff), UInt8(ntStatus >> 16 & 0xff), UInt8(ntStatus >> 24 & 0xff))
self.flags = flags
self.flags2 = flags2
self._securityKey = (UInt16(securityKey & 0xffff), UInt16(securityKey >> 16))
self.securityCID = securityCID
self.securitySequenceNumber = securitySequenceNumber
self.ununsed = 0
self.treeId = treeId
self.pidLow = UInt16(pid & 0xffff)
self.pidHigh = UInt16(pid >> 16)
self.userId = userId
self.multiplexId = multiplexId
}
}
struct Flags: OptionSetType {
let rawValue: UInt8
init(rawValue: UInt8) {
self.rawValue = rawValue
}
/** This bit is set (1) in the NEGOTIATE (0x72) Response if the server supports
* LOCK_AND_READ (0x13) and WRITE_AND_UNLOCK (0x14) commands. */
static let LOCK_AND_READ_OK = Flags(rawValue: 0x01)
static let BUF_AVAIL = Flags(rawValue: 0x02)
static let CASE_INSENSITIVE = Flags(rawValue: 0x08)
static let CANONICALIZED_PATHS = Flags(rawValue: 0x10)
static let OPLOCK = Flags(rawValue: 0x20)
static let OPBATCH = Flags(rawValue: 0x40)
/** When on, this message is being sent from the server in response to a client request. */
static let REPLY = Flags(rawValue: 0x80)
}
struct Flags2: OptionSetType {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
/** Client: the message MAY contain long file names. */
static let LONG_NAMES = Flags2(rawValue: 0x0001)
/** Client: the client is aware of extended attributes (EAs). */
static let EAS = Flags2(rawValue: 0x0002)
/** Client: the client is requesting signing (if signing is not yet active) or the message
* being sent is signed. This bit is used on the SMB header of an SESSION_SETUP_ANDX */
static let SMB_SECURITY_SIGNATURE = Flags2(rawValue: 0x0004)
/// Reserved but not implemented.
static let IS_LONG_NAME = Flags2(rawValue: 0x0040)
/** client aware of Extended Security negotiation */
static let EXT_SEC = Flags2(rawValue: 0x0800)
/** any pathnames in this SMB SHOULD be resolved in the Distributed File System (DFS) */
static let DFS = Flags2(rawValue: 0x1000)
/**
* This flag is useful only on a read request. If the bit is set, then the client MAY read
* the file if the client does not have read permission but does have execute permission. */
static let PAGING_IO = Flags2(rawValue: 0x2000) // READ_IF_EXECUTE
/**
* Client: the server MUST return errors as 32-bit NTSTATUS codes in the response
* Server: the Status field in the header is formatted as an NTSTATUS cod */
static let ERR_STATUS = Flags2(rawValue: 0x4000)
/**
* Each field that contains a string in this SMB message MUST be encoded
* as an array of 16-bit Unicode characters */
static let UNICODE = Flags2(rawValue: 0x8000)
}
enum Command: UInt8 {
case CREATE_DIRECTORY = 0x00
case DELETE_DIRECTORY = 0x01
case OPEN = 0x02
case CREATE = 0x03
case CLOSE = 0x04
case FLUSH = 0x05
case DELETE = 0x06
case RENAME = 0x07
case QUERY_INFORMATION = 0x08
case SET_INFORMATION = 0x09
case READ = 0x0A
case WRITE = 0x0B
case LOCK_BYTE_RANGE = 0x0C
case UNLOCK_BYTE_RANGE = 0x0D
case CREATE_TEMPORARY = 0x0E
case CREATE_NEW = 0x0F
case CHECK_DIRECTORY = 0x10
case PROCESS_EXIT = 0x11
case SEEK = 0x12
case LOCK_AND_READ = 0x13
case WRITE_AND_UNLOCK = 0x14
case READ_RAW = 0x1A
case READ_MPX = 0x1B
case READ_MPX_SECONDARY = 0x1C
case WRITE_RAW = 0x1D
case WRITE_MPX = 0x1E
case WRITE_COMPLETE = 0x20
case SET_INFORMATION2 = 0x22
case QUERY_INFORMATION2 = 0x23
case LOCKING_ANDX = 0x24
case TRANSACTION = 0x25
case TRANSACTION_SECONDARY = 0x26
case IOCTL = 0x27
case IOCTL_SECONDARY = 0x28
case COPY = 0x29
case MOVE = 0x2A
case ECHO = 0x2B
case WRITE_AND_CLOSE = 0x2C
case OPEN_ANDX = 0x2D
case READ_ANDX = 0x2E
case WRITE_ANDX = 0x2F
case CLOSE_AND_TREE_DISC = 0x31
case TRANSACTION2 = 0x32
case TRANSACTION2_SECONDARY = 0x33
case FIND_CLOSE2 = 0x34
case FIND_NOTIFY_CLOSE = 0x35
case TREE_CONNECT = 0x70
case TREE_DISCONNECT = 0x71
case NEGOTIATE = 0x72
case SESSION_SETUP_ANDX = 0x73
case LOGOFF_ANDX = 0x74
case TREE_CONNECT_ANDX = 0x75
case QUERY_INFORMATION_DISK = 0x80
case SEARCH = 0x81
case FIND = 0x82
case FIND_UNIQUE = 0x83
case NT_TRANSACT = 0xA0
case NT_TRANSACT_SECONDARY = 0xA1
case NT_CREATE_ANDX = 0xA2
case NT_CANCEL = 0xA4
case OPEN_PRINT_FILE = 0xC0
case WRITE_PRINT_FILE = 0xC1
case CLOSE_PRINT_FILE = 0xC2
case GET_PRINT_QUEUE = 0xC3
case READ_BULK = 0xD8
case WRITE_BULK = 0xD9
case WRITE_BULK_DATA = 0xDA
case INVALID = 0xFE
}
}
+49
View File
@@ -0,0 +1,49 @@
//
// SMB2DataTypes.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/30/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
protocol SMBRequest {
func data() -> NSData
}
protocol SMBResponse {
init? (data: NSData)
}
protocol IOCtlRequestProtocol: SMBRequest {}
protocol IOCtlResponseProtocol: SMBResponse {}
struct SMBTime {
var time: UInt64
init(time: UInt64) {
self.time = time
}
init(unixTime: UInt) {
self.time = (UInt64(unixTime) + 11644473600) * 10000000
}
init(timeIntervalSince1970: NSTimeInterval) {
self.time = UInt64((timeIntervalSince1970 + 11644473600) * 10000000)
}
init(date: NSDate) {
self.init(timeIntervalSince1970: date.timeIntervalSince1970)
}
var unixTime: UInt {
return UInt(self.time / 10000000 - 11644473600)
}
var date: NSDate {
return NSDate(timeIntervalSince1970: Double(self.time) / 10000000 - 11644473600)
}
}
+448
View File
@@ -0,0 +1,448 @@
//
// SMB2CreateClose.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/30/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
extension SMB2 {
// MARK: SMB2 Create
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 {
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 {
let size: UInt16
private let securityFlags: UInt8
private var _requestedOplockLevel: UInt8
var requestedOplockLevel: OplockLevel {
get {
return OplockLevel(rawValue: _requestedOplockLevel)!
}
set {
_requestedOplockLevel = newValue.rawValue
}
}
private var _impersonationLevel: UInt32
var impersonationLevel: ImpersonationLevel {
get {
return ImpersonationLevel(rawValue: _impersonationLevel)!
}
set {
_impersonationLevel = newValue.rawValue
}
}
private let flags: UInt64
private let reserved: UInt64
let access: FileAccessMask
let fileAttributes: FileAttributes
let shareAccess: ShareAccess
private var _desposition: UInt32
var desposition: CreateDisposition {
get {
return CreateDisposition(rawValue: _desposition)!
}
set {
_desposition = newValue.rawValue
}
}
let options: CreateOptions
var nameOffset: UInt16
var nameLength: UInt16
var contextOffset: UInt32
var contextLength: UInt32
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.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
}
}
struct CreateOptions: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let DIRECTORY_FILE = CreateOptions(rawValue: 0x00000001)
static let WRITE_THROUGH = CreateOptions(rawValue: 0x00000002)
static let SEQUENTIAL_ONLY = CreateOptions(rawValue: 0x00000004)
static let NO_INTERMEDIATE_BUFFERING = CreateOptions(rawValue: 0x00000008)
static let NON_DIRECTORY_FILE = CreateOptions(rawValue: 0x00000040)
static let NO_EA_KNOWLEDGE = CreateOptions(rawValue: 0x00000200)
static let RANDOM_ACCESS = CreateOptions(rawValue: 0x00000800)
static let DELETE_ON_CLOSE = CreateOptions(rawValue: 0x00001000)
static let OPEN_BY_FILE_ID = CreateOptions(rawValue: 0x00002000)
static let OPEN_FOR_BACKUP_INTENT = CreateOptions(rawValue: 0x00004000)
static let NO_COMPRESSION = CreateOptions(rawValue: 0x00008000)
static let OPEN_REPARSE_POINT = CreateOptions(rawValue: 0x00200000)
static let OPEN_NO_RECALL = CreateOptions(rawValue: 0x00400000)
private static let SYNCHRONOUS_IO_ALERT = CreateOptions(rawValue: 0x00000010)
private static let SYNCHRONOUS_IO_NONALERT = CreateOptions(rawValue: 0x00000020)
private static let COMPLETE_IF_OPLOCKED = CreateOptions(rawValue: 0x00000100)
private static let REMOTE_INSTANCE = CreateOptions(rawValue: 0x00000400)
private static let OPEN_FOR_FREE_SPACE_QUERY = CreateOptions(rawValue: 0x00800000)
private static let OPEN_REQUIRING_OPLOCK = CreateOptions(rawValue: 0x00010000)
private static let DISALLOW_EXCLUSIVE = CreateOptions(rawValue: 0x00020000)
private static let RESERVE_OPFILTER = CreateOptions(rawValue: 0x00100000)
}
enum CreateDisposition: UInt32 {
/// If the file already exists, supersede it. Otherwise, create the file.
case SUPERSEDE = 0x00000000
/// If the file already exists, return success; otherwise, fail the operation.
case OPEN = 0x00000001
/// If the file already exists, fail the operation; otherwise, create the file.
case CREATE = 0x00000002
/// Open the file if it already exists; otherwise, create the file.
case OPEN_IF = 0x00000003
/// Overwrite the file if it already exists; otherwise, fail the operation.
case OVERWRITE = 0x00000004
/// Overwrite the file if it already exists; otherwise, create the file.
case OVERWRITE_IF = 0x00000005
}
enum ImpersonationLevel: UInt32 {
case Anonymous = 0x00000000
case Identification = 0x00000001
case Impersonation = 0x00000002
case Delegate = 0x00000003
}
}
struct CreateResponse: SMBResponse {
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 fileId: FileId
let contextsOffset: UInt32
let ContextsLength: UInt32
}
let header: CreateResponse.Header
let contexts: [CreateContext]
init? (data: NSData) {
guard data.length >= sizeof(CreateResponse.Header.self) else {
return nil
}
self.header = decode(data)
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
}
self.header = decode(data)
self.buffer = data.subdataWithRange(NSRange(location: headersize, length: data.length - headersize))
}
func data() -> NSData {
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 NONE = 0x00
case LEVEL_II = 0x01
case EXCLUSIVE = 0x08
case BATCH = 0x09
case LEASE = 0xFF
}
struct ShareAccess: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let READ = ShareAccess(rawValue: 0x00000001)
static let WRITE = ShareAccess(rawValue: 0x00000002)
static let DELETE = ShareAccess(rawValue: 0x00000004)
}
struct FileAccessMask: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
// File and Printer/Pipe Accesses
static let FILE_READ_DATA = FileAccessMask(rawValue: 0x00000001)
static let FILE_WRITE_DATA = FileAccessMask(rawValue: 0x00000002)
static let FILE_APPEND_DATA = FileAccessMask(rawValue: 0x00000004)
static let FILE_EXECUTE = FileAccessMask(rawValue: 0x00000020)
// Directory
static let FILE_LIST_DIRECTORY = FileAccessMask(rawValue: 0x00000001)
static let FILE_ADD_FILE = FileAccessMask(rawValue: 0x00000002)
static let FILE_ADD_SUBDIRECTORY = FileAccessMask(rawValue: 0x00000004)
static let FILE_TRAVERSE = FileAccessMask(rawValue: 0x00000020)
// Generic
static let FILE_READ_EA = FileAccessMask(rawValue: 0x00000008)
static let FILE_WRITE_EA = FileAccessMask(rawValue: 0x00000010)
static let FILE_DELETE_CHILD = FileAccessMask(rawValue: 0x00000040)
static let FILE_READ_ATTRIBUTES = FileAccessMask(rawValue: 0x00000080)
static let FILE_WRITE_ATTRIBUTES = FileAccessMask(rawValue: 0x00000100)
static let DELETE = FileAccessMask(rawValue: 0x00010000)
static let READ_CONTROL = FileAccessMask(rawValue: 0x00020000)
static let WRITE_DAC = FileAccessMask(rawValue: 0x00040000)
static let WRITE_OWNER = FileAccessMask(rawValue: 0x00080000)
static let SYNCHRONIZE = FileAccessMask(rawValue: 0x00100000)
static let ACCESS_SYSTEM_SECURITY = FileAccessMask(rawValue: 0x01000000)
static let MAXIMUM_ALLOWED = FileAccessMask(rawValue: 0x02000000)
static let GENERIC_ALL = FileAccessMask(rawValue: 0x10000000)
static let GENERIC_EXECUTE = FileAccessMask(rawValue: 0x20000000)
static let GENERIC_WRITE = FileAccessMask(rawValue: 0x40000000)
static let GENERIC_READ = FileAccessMask(rawValue: 0x80000000)
}
struct FileAttributes: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let READONLY = FileAttributes(rawValue: 0x00000001)
static let HIDDEN = FileAttributes(rawValue: 0x00000002)
static let SYSTEM = FileAttributes(rawValue: 0x00000004)
static let DIRECTORY = FileAttributes(rawValue: 0x00000010)
static let ARCHIVE = FileAttributes(rawValue: 0x00000020)
static let NORMAL = FileAttributes(rawValue: 0x00000080)
static let TEMPORARY = FileAttributes(rawValue: 0x00000100)
static let SPARSE_FILE = FileAttributes(rawValue: 0x00000200)
static let REPARSE_POINT = FileAttributes(rawValue: 0x00000400)
static let COMPRESSED = FileAttributes(rawValue: 0x00000800)
static let OFFLINE = FileAttributes(rawValue: 0x00001000)
static let NOT_CONTENT_INDEXED = FileAttributes(rawValue: 0x00002000)
static let ENCRYPTED = FileAttributes(rawValue: 0x00004000)
static let INTEGRITY_STREAM = FileAttributes(rawValue: 0x00008000)
static let NO_SCRUB_DATA = FileAttributes(rawValue: 0x00020000)
}
struct FileId {
let persistent: UInt64
let volatile: UInt64
}
// MARK: SMB2 Close
struct CloseRequest: SMBRequest {
let size: UInt16
let flags: CloseFlags
private let reserved2: UInt32
let filePersistantId: UInt64
let fileVolatileId: UInt64
init(filePersistantId: UInt64, fileVolatileId: UInt64) {
self.size = 24
self.filePersistantId = filePersistantId
self.fileVolatileId = fileVolatileId
self.flags = []
self.reserved2 = 0
}
func data() -> NSData {
return encode(self)
}
}
struct CloseResponse: SMBResponse {
let size: UInt16
let flags: CloseFlags
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
init? (data: NSData) {
self = decode(data)
}
}
struct CloseFlags: OptionSetType {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
static let POSTQUERY_ATTRIB = Flags(rawValue: 0x0001)
}
// MARK: SMB2 Flush
struct FlushRequest: SMBRequest {
let size: UInt16
private let reserved: UInt16
private let reserved2: UInt32
let filePersistantId: UInt64
let fileVolatileId: UInt64
init(filePersistantId: UInt64, fileVolatileId: UInt64) {
self.size = 24
self.filePersistantId = filePersistantId
self.fileVolatileId = fileVolatileId
self.reserved = 0
self.reserved2 = 0
}
func data() -> NSData {
return encode(self)
}
}
struct FlushResponse: SMBResponse {
let size: UInt16
let reserved: UInt16
init() {
self.size = 4
self.reserved = 0
}
init? (data: NSData) {
self = decode(data)
}
}
}
+251
View File
@@ -0,0 +1,251 @@
//
// SMB2FileOperation.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/30/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
extension SMB2 {
// MARK: SMB2 Read
struct ReadRequest: SMBRequest {
let size: UInt16
private let padding: UInt8
let flags: ReadRequest.Flags
let length: UInt32
let offset: UInt64
let fileId: FileId
let minimumLength: UInt32
private let _channel: UInt32
var channel: Channel {
return Channel(rawValue: _channel) ?? .NONE
}
let remainingBytes: UInt32
private let channelInfoOffset: UInt16
private let channelInfoLength: UInt16
private let channelBuffer: UInt8
init (fileId: FileId, offset: UInt64, length: UInt32, flags: ReadRequest.Flags = [], minimumLength: UInt32 = 0, remainingBytes: UInt32 = 0, channel: Channel = .NONE) {
self.size = 49
self.padding = 0
self.flags = flags
self.length = length
self.offset = offset
self.fileId = fileId
self.minimumLength = minimumLength
self._channel = channel.rawValue
self.remainingBytes = remainingBytes
self.channelInfoOffset = 0
self.channelInfoLength = 0
self.channelBuffer = 0
}
func data() -> NSData {
return encode(read)
}
struct Flags: OptionSetType {
let rawValue: UInt8
init(rawValue: UInt8) {
self.rawValue = rawValue
}
static let UNBUFFERED = Flags(rawValue: 0x01)
}
}
struct ReadRespone: SMBResponse {
struct Header {
let size: UInt16
let offset: UInt8
private let reserved: UInt8
let length: UInt32
let remaining: UInt32
private let reserved2: UInt32
}
let header: ReadRespone.Header
let buffer: NSData
init?(data: NSData) {
guard data.length > 16 else {
return nil
}
self.header = decode(data)
let headersize = sizeof(Header)
self.buffer = data.subdataWithRange(NSRange(location: headersize, length: data.length - headersize))
}
}
enum Channel: UInt32 {
case NONE = 0x00000000
case RDMA_V1 = 0x00000001
case RDMA_V1_INVALIDATE = 0x00000002
}
// MARK: SMB2 Write
struct WriteRequest: SMBRequest {
let header: WriteRequest.Header
let channelInfo: ChannelInfo?
let fileData: NSData
struct Header {
let size: UInt16
let dataOffset: UInt16
let length: UInt32
let offset: UInt64
let fileId: FileId
private let _channel: UInt32
var channel: Channel {
return Channel(rawValue: _channel) ?? .NONE
}
let remainingBytes: UInt32
let channelInfoOffset: UInt16
let channelInfoLength: UInt16
let flags: WriteRequest.Flags
}
init(fileId: FileId, offset: UInt64, remainingBytes: UInt32 = 0, data: NSData, channel: Channel = .NONE, channelInfo: ChannelInfo? = nil, flags: WriteRequest.Flags = []) {
var channelInfoOffset: UInt16 = 0
var channelInfoLength: UInt16 = 0
if channel != .NONE, let channelInfo = channelInfo {
channelInfoOffset = UInt16(sizeof(SMB2.Header.self) + sizeof(WriteRequest.Header.self))
channelInfoLength = UInt16(sizeof(channelInfo.dynamicType))
}
let dataOffset = UInt16(sizeof(SMB2.Header.self) + sizeof(WriteRequest.Header.self)) + channelInfoLength
self.header = WriteRequest.Header(size: UInt16(49), dataOffset: dataOffset, length: UInt32(data.length), offset: offset, fileId: fileId, _channel: channel.rawValue, remainingBytes: remainingBytes, channelInfoOffset: channelInfoOffset, channelInfoLength: channelInfoLength, flags: flags)
self.channelInfo = channelInfo
self.fileData = data
}
func data() -> NSData {
let result = NSMutableData(data: encode(self.header))
if let channelInfo = channelInfo {
result.appendData(channelInfo.data())
}
result.appendData(fileData)
return result
}
struct Flags: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let THROUGH = Flags(rawValue: 0x00000001)
static let UNBUFFERED = Flags(rawValue: 0x00000002)
}
}
struct WriteResponse: SMBResponse {
let size: UInt16
private let reserved: UInt16
let writtenBytes: UInt32
private let remaining: UInt32
private let channelInfoOffset: UInt16
private let channelInfoLength: UInt16
init?(data: NSData) {
self = decode(data)
}
}
struct ChannelInfo: SMBRequest {
let offset: UInt64
let token: UInt32
let length: UInt32
func data() -> NSData {
return encode(data)
}
}
// MARK: SMB2 Lock
struct LockElement: SMBRequest {
let offset: UInt64
let length: UInt64
let flags: LockElement.Flags
private let reserved: UInt32
func data() -> NSData {
return encode(self)
}
struct Flags: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let SHARED_LOCK = Flags(rawValue: 0x00000001)
static let EXCLUSIVE_LOCK = Flags(rawValue: 0x00000002)
static let UNLOCK = Flags(rawValue: 0x00000004)
static let FAIL_IMMEDIATELY = Flags(rawValue: 0x00000010)
}
}
struct LockRequest: SMBRequest {
let header: LockRequest.Header
let locks: [LockElement]
init(fileId: FileId,locks: [LockElement], lockSequenceNumber : Int8 = 0, lockSequenceIndex: UInt32 = 0) {
self.header = LockRequest.Header(size: 48, lockCount: UInt16(locks.count), lockSequence: UInt32(lockSequenceNumber << 28) + lockSequenceIndex, fileId: fileId)
self.locks = locks
}
func data() -> NSData {
let result = NSMutableData(data: encode(header))
for lock in locks {
result.appendData(encode(lock))
}
return result
}
struct Header {
let size: UInt16
private let lockCount: UInt16
let lockSequence: UInt32
let fileId : FileId
}
}
struct LockResponse: SMBResponse {
let size: UInt16
let reserved: UInt16
init() {
self.size = 4
self.reserved = 0
}
init? (data: NSData) {
self = decode(data)
}
}
// MARK: SMB2 Cancel
struct CancelRequest: SMBRequest {
let size: UInt16
let reserved: UInt16
init() {
self.size = 4
self.reserved = 0
}
func data() -> NSData {
return encode(self)
}
}
}
+388
View File
@@ -0,0 +1,388 @@
//
// SMB2IOCtl.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/30/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
extension SMB2 {
// MARK: SMB2 IOCTL
/**
* IOCtl usage is usually limited in SMB to pipe requests and duplicating file inside server
*/
struct IOCtlRequest: SMBRequest {
let header: Header
let requestData: IOCtlRequestProtocol?
init(fileId: FileId ,ctlCode: IOCtlCode, requestData: IOCtlRequestProtocol?, flags: IOCtlRequest.Flags = []) {
let offset = requestData != nil ? UInt32(sizeof(SMB2.Header.self) + sizeof(IOCtlRequest.Header.self)) : 0
self.header = Header(size: 57, reserved: 0, _ctlCode: ctlCode.rawValue, fileId: fileId, inputOffset: offset, inputCount: UInt32((requestData?.data().length ?? 0)), maxInputResponse: 0, outputOffset: offset, outputCount: 0, maxOutputResponse: UInt32(Int32.max), flags: flags, reserved2: 0)
self.requestData = requestData
}
func data() -> NSData {
let result = NSMutableData(data: encode(self.header))
if let reqData = requestData?.data() {
result.appendData(reqData)
}
return result
}
struct Header {
let size: UInt16
private let reserved: UInt16
private let _ctlCode: UInt32
var ctlCode: IOCtlCode {
return IOCtlCode(rawValue: _ctlCode)!
}
let fileId: FileId
let inputOffset: UInt32
let inputCount: UInt32
let maxInputResponse: UInt32
let outputOffset: UInt32
let outputCount: UInt32
let maxOutputResponse: UInt32
let flags: IOCtlRequest.Flags
private let reserved2: UInt32
}
struct Flags: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let IOCTL = Flags(rawValue: 0x00000000)
static let FSCTL = Flags(rawValue: 0x00000001)
}
}
struct IOCtlResponse: SMBResponse {
let header: Header
let responseData: IOCtlResponseProtocol?
init?(data: NSData) {
self.header = decode(data)
let responseRange = NSRange(location: Int(self.header.outputOffset - 64), length: Int(self.header.outputCount))
let response = data.subdataWithRange(responseRange)
switch self.header.ctlCode {
case .SRV_COPYCHUNK, .SRV_COPYCHUNK_WRITE:
self.responseData = IOCtlResponseData.SrvCopyChunk(data: response)
case .SRV_ENUMERATE_SNAPSHOTS:
self.responseData = IOCtlResponseData.SrvSnapshots(data: response)
case .SRV_REQUEST_RESUME_KEY:
self.responseData = IOCtlResponseData.ResumeKey(data: response)
case .SRV_READ_HASH:
self.responseData = IOCtlResponseData.ReadHash(data: response)
case .QUERY_NETWORK_INTERFACE_INFO:
self.responseData = IOCtlResponseData.NetworkInterfaceInfo(data: response)
case .VALIDATE_NEGOTIATE_INFO:
self.responseData = IOCtlResponseData.ValidateNegotiateInfo(data: response)
default:
self.responseData = nil
}
}
struct Header {
let size: UInt16
private let reserved: UInt16
private let _ctlCode: UInt32
var ctlCode: IOCtlCode {
return IOCtlCode(rawValue: _ctlCode)!
}
let fileId: FileId
let inputOffset: UInt32
let inputCount: UInt32
let outputOffset: UInt32
let outputCount: UInt32
private let flags: UInt32
private let reserved2: UInt32
}
}
enum IOCtlCode: UInt32 {
case DFS_GET_REFERRALS = 0x00060194
case DFS_GET_REFERRALS_EX = 0x000601B0
case SET_REPARSE_POINT = 0x000900A4
case FILE_LEVEL_TRIM = 0x00098208
case PIPE_PEEK = 0x0011400C
case PIPE_WAIT = 0x00110018
/// PIPE_TRANSCEIVE is valid only on a named pipe with mode set to FILE_PIPE_MESSAGE_MODE.
case PIPE_TRANSCEIVE = 0x0011C017
/// Get ResumeKey used by the client to uniquely identify the source file in an FSCTL_SRV_COPYCHUNK or FSCTL_SRV_COPYCHUNK_WRITE request.
case SRV_REQUEST_RESUME_KEY = 0x00140078
/// Get all the revision time-stamps that are associated with the Tree Connect share in which the open resides
case SRV_ENUMERATE_SNAPSHOTS = 0x00144064
/// Reads a chunk of file for performing server side copy operations.
case SRV_COPYCHUNK = 0x001440F2
/// Retrieve data from the Content Information File associated with a specified file, not valid for the SMB 2.0.2 dialect.
case SRV_READ_HASH = 0x001441BB
/// Writes the chunk of file for performing server side copy operations.
case SRV_COPYCHUNK_WRITE = 0x001480F2
/// Request resiliency for a specified open file, not valid for the SMB 2.0.2 dialect.
case LMR_REQUEST_RESILIENCY = 0x001401D4
/// Get server network interface info e.g. link speed and socket address information
case QUERY_NETWORK_INTERFACE_INFO = 0x001401FC
/// Request validation of a previous SMB 2 NEGOTIATE, valid for SMB 3.0 and SMB 3.0.2 dialects.
case VALIDATE_NEGOTIATE_INFO = 0x00140204
}
struct IOCtlRequestData {
struct CopyChunk: IOCtlRequestProtocol {
let sourceKey: (UInt64, UInt64, UInt64)
let chunkCount: UInt32
let chunks: [Chunk]
func data() -> NSData {
let result = NSMutableData(data: encode(sourceKey))
result.appendData(encode(chunkCount))
var reserved: UInt32 = 0
result.appendData(encode(&reserved))
return NSData()
}
struct Chunk {
let sourceOffset: UInt64
let targetOffset: UInt64
let length: UInt32
private let reserved: UInt32
func data() -> NSData {
return encode(self)
}
}
}
struct ReadHash: IOCtlRequestProtocol {
let _hashType: UInt32
var hashType: IOCtlHashType {
return IOCtlHashType(rawValue: _hashType) ?? .PEER_DIST
}
let _hashVersion: UInt32
var hashVersion: IOCtlHashVersion {
return IOCtlHashVersion(rawValue: _hashVersion) ?? .VER_1
}
let _hashRetrievalType: UInt32
var hashRetrievalType: IOCtlHashRetrievalType {
return IOCtlHashRetrievalType(rawValue: _hashRetrievalType) ?? .FILE_BASED
}
let length: UInt32
let offset: UInt64
init(offset: UInt64, length: UInt32, hashType: IOCtlHashType = .PEER_DIST, hashVersion: IOCtlHashVersion = .VER_1, hashRetrievalType: IOCtlHashRetrievalType = .FILE_BASED) {
self._hashType = hashType.rawValue
self._hashVersion = hashVersion.rawValue
self._hashRetrievalType = hashRetrievalType.rawValue
self.length = length
self.offset = offset
}
func data() -> NSData {
return encode(self)
}
}
struct ResilencyRequest: IOCtlRequestProtocol {
let timeout: UInt32
private let reserved: UInt32
/// The requested time the server holds the file open after a disconnect before releasing it. This time is in milliseconds.
init(timeout: UInt32) {
self.timeout = timeout
self.reserved = 0
}
func data() -> NSData {
return encode(self)
}
}
struct ValidateNegotiateInfo: IOCtlRequestProtocol {
let header: ValidateNegotiateInfo.Header
let dialects: [UInt16]
init(dialects: [UInt16], guid: uuid_t, capabilities: IOCtlCapabilities, securityMode: UInt16) {
self.header = Header(capabilities: capabilities, guid: guid, securityMode: securityMode, dialectCount: UInt16(dialects.count))
self.dialects = dialects
}
func data() -> NSData {
let result = NSMutableData(data: encode(self.header))
dialects.forEach { result.appendData(encode($0)) }
return result
}
struct Header {
let capabilities: IOCtlCapabilities
/// Client's GUID
let guid: uuid_t
let securityMode: UInt16
let dialectCount: UInt16
}
}
}
struct IOCtlResponseData {
// SRV_COPYCHUNK, SRV_COPYCHUNK_WRITE
struct SrvCopyChunk: IOCtlResponseProtocol {
let chunksCount: UInt32
let chunksBytesWritten: UInt32
let totalBytesWriiten: UInt32
init?(data: NSData) {
self = decode(data)
}
}
// SRV_ENUMERATE_SNAPSHOTS
struct SrvSnapshots: IOCtlResponseProtocol {
let count: UInt32
let snapshots: [SMBTime]
init?(data: NSData) {
self.count = decode(data)
let returnedCount: UInt32 = decode(data.subdataWithRange(NSRange(location: 4, length: 4)))
//let size: UInt32 = decode(data.subdataWithRange(NSRange(location: 8, length: 4)))
var snapshots = [SMBTime]()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "'@GMT-'yyyy'.'MM'.'dd'-'HH'.'mm'.'ss"
for i in 0..<Int(returnedCount) {
let offset = 24 + i * 48
if data.length < offset + 48 {
return nil
}
let datestring = String(data: data.subdataWithRange(NSRange(location: offset, length: 48)), encoding: NSUTF16StringEncoding)
if let datestring = datestring, let date = dateFormatter.dateFromString(datestring) {
snapshots.append(SMBTime(date: date))
}
}
self.snapshots = snapshots
}
}
struct ResumeKey: IOCtlResponseProtocol {
let key: (UInt64, UInt64, UInt64)
private let contextLength: UInt32
private let context: UInt32
init?(data: NSData) {
self = decode(data)
}
}
struct ReadHash: IOCtlResponseProtocol {
// TODO: Implement IOCTL READ_HASH
init?(data: NSData) {
self = decode(data)
}
}
struct NetworkInterfaceInfo: IOCtlResponseProtocol {
let items: [NetworkInterfaceInfo.Item]
init?(data: NSData) {
let count = data.length / sizeof(Item)
guard count > 0 else {
return nil
}
var items = [Item]()
for i in 0..<count {
let itemdata = data.subdataWithRange(NSRange(location: i * sizeof(Item), length: sizeof(Item)))
items.append(decode(itemdata))
}
self.items = items
}
struct Item {
/// The offset, in bytes, from the beginning of this structure to the beginning of a subsequent 8-byte aligned network interface.
let next: UInt32
/// specifies the network interface index.
let ifIndex: UInt32
let capability: IOCtlCapabilities
private let reserved: UInt32
/// Speed of the network interface in bits per second
let linkSpeed: UInt64
private let sockaddrStorage: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)
var family: sa_family_t {
return sockaddrStorage.1
}
static let ipv4: sa_family_t = 0x02
static let ipv6: sa_family_t = 0x17
var sockaddr: sockaddr_in {
var sockaddrStorage = self.sockaddrStorage
let data = NSData(bytes: &sockaddrStorage, length: 16)
return decode(data)
}
var sockaddr6: sockaddr_in6 {
var sockaddrStorage = self.sockaddrStorage
let data = NSData(bytes: &sockaddrStorage, length: 28)
return decode(data)
}
}
}
struct ValidateNegotiateInfo: IOCtlResponseProtocol {
let capabilities: IOCtlCapabilities
let guid: uuid_t
let securityMode: UInt16
private let _dialect: UInt16
var dialect: (major: Int, minor: Int) {
return (major: Int(_dialect & 0xFF), minor: Int(_dialect >> 8))
}
init?(data: NSData) {
self = decode(data)
}
}
}
struct IOCtlCapabilities: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let RSS_CAPABLE = IOCtlCapabilities(rawValue: 0x00000001)
static let RDMA_CAPABLE = IOCtlCapabilities(rawValue: 0x00000002)
}
enum IOCtlHashType: UInt32 {
case PEER_DIST = 0x00000001
}
enum IOCtlHashVersion: UInt32 {
case VER_1 = 0x00000001
case VER_2 = 0x00000002
}
enum IOCtlHashRetrievalType: UInt32 {
case HASH_BASED = 0x00000001
case FILE_BASED = 0x00000002
}
}
+18
View File
@@ -0,0 +1,18 @@
//
// SMB2Query.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/31/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
extension SMB2 {
// MARK: SMB2 Query Directory
// MARK: SMB2 Change Notify
// MARK: SMB2 Query Info
}
+318
View File
@@ -0,0 +1,318 @@
//
// SMB2NegotiationTypes.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/30/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
extension SMB2 {
// MARK: SMB2 Negotiating
struct NegotiateRequest: SMBRequest {
let request: NegotiateRequest.Header
let dialects: [UInt16]
let contexts: [(type: NegotiateContextType, data: NSData)]
init(request: NegotiateRequest.Header, dialects: [UInt16] = [0x0202], contexts: [(type: NegotiateContextType, data: NSData)] = []) {
self.request = request
self.dialects = dialects
self.contexts = contexts
}
func data() -> NSData {
var request = self.request
request.dialectCount = UInt16(dialects.count)
let dialectData = NSMutableData()
for dialect in dialects {
var dialect = dialect
dialectData.appendBytes(&dialect, length: 2)
}
let pad = ((1024 - dialectData.length) % 8)
dialectData.increaseLengthBy(pad)
request.contextOffset = UInt32(sizeof(request.dynamicType.self)) + UInt32(dialectData.length)
request.contextCount = UInt16(contexts.count)
let contextData = NSMutableData()
for context in contexts {
var contextType = context.type.rawValue
contextData.appendBytes(&contextType, length: 2)
var dataLen = UInt16(context.data.length)
contextData.increaseLengthBy(4)
contextData.appendBytes(&dataLen, length: 2)
}
let result = NSMutableData(data: encode(&request))
result.appendData(dialectData)
result.appendData(contextData)
return result
}
struct Header {
var size: UInt16
var dialectCount: UInt16
let singing: NegotiateSinging
private let reserved: UInt16
let capabilities: GlobalCapabilities
let guid: uuid_t
var contextOffset: UInt32
var contextCount: UInt16
private let reserved2: UInt16
var clientStartTime: SMBTime {
let time = UInt64(contextOffset) + (UInt64(contextCount) << 32) + (UInt64(contextCount) << 48)
return SMBTime(time: time)
}
init(singing: NegotiateSinging = [.ENABLED], capabilities: GlobalCapabilities, guid: uuid_t? = nil, clientStartTime: SMBTime? = nil) {
self.size = 36
self.dialectCount = 0
self.singing = singing
self.reserved = 0
self.capabilities = capabilities
self.guid = guid ?? (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
if let clientStartTime = clientStartTime {
let time = clientStartTime.time
self.contextOffset = UInt32(time & 0xffffffff)
self.contextCount = UInt16(time & 0x0000ffff00000000 >> 32)
self.reserved2 = UInt16(time >> 48)
} else {
self.contextOffset = 0
self.contextCount = 0
self.reserved2 = 0
}
}
}
}
struct NegotiateResponse: SMBResponse {
let header: NegotiateResponse.Header
let buffer: NSData?
let contexts: [(type: NegotiateContextType, data: NSData)]
init? (data: NSData) {
if data.length < 64 {
return nil
}
self.header = decode(data)
if Int(header.size) != 65 {
return nil
}
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))
} else {
self.buffer = nil
}
let contextCount = Int(self.header.contextCount)
let contextOffset = Int(self.header.contextOffset) - sizeof(SMB2.Header.self)
if contextCount > 0 && contextOffset > 0 {
// TODO: NegotiateResponse context support for SMB3
self.contexts = []
} else {
self.contexts = []
}
}
struct Header {
let size: UInt16
let singing: NegotiateSinging
let dialect: UInt16
let contextCount: UInt16
let serverGuid: uuid_t
let capabilities: GlobalCapabilities
let maxTransactSize: UInt32
let maxReadSize: UInt32
let maxWriteSize: UInt32
let systemTime: SMBTime
let serverStartTime: SMBTime
let bufferOffset: UInt16
let bufferLength: UInt16
let contextOffset: UInt32
}
}
struct NegotiateSinging: OptionSetType {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
static let ENABLED = NegotiateSinging(rawValue: 0x0001)
static let REQUIRED = NegotiateSinging(rawValue: 0x0002)
}
struct NegotiateContextType: OptionSetType {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
static let PREAUTH_INTEGRITY_CAPABILITIES = NegotiateContextType(rawValue: 0x0001)
static let ENCRYPTION_CAPABILITIES = NegotiateContextType(rawValue: 0x0002)
}
struct GlobalCapabilities: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let DFS = GlobalCapabilities(rawValue: 0x00000001)
static let LEASING = GlobalCapabilities(rawValue: 0x00000002)
static let LARGE_MTU = GlobalCapabilities(rawValue: 0x00000004)
static let MULTI_CHANNEL = GlobalCapabilities(rawValue: 0x00000008)
static let PERSISTENT_HANDLES = GlobalCapabilities(rawValue: 0x00000010)
static let DIRECTORY_LEASING = GlobalCapabilities(rawValue: 0x00000020)
static let ENCRYPTION = GlobalCapabilities(rawValue: 0x00000040)
}
// MARK: SMB2 Session Setup
struct SessionSetupRequest: SMBRequest {
let header: SessionSetupRequest.Header
let buffer: NSData?
init(header: SessionSetupRequest.Header, buffer: NSData) {
self.header = header
self.buffer = buffer
}
func data() -> NSData {
var header = self.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 {
result.appendData(buffer)
}
return result
}
struct Header {
let size: UInt16
let flags: SessionSetupRequest.Flags
let signing: SessionSetupSinging
let capabilities: GlobalCapabilities
private let channel: UInt32
var bufferOffset: UInt16
var bufferLength: UInt16
let sessionId: UInt64
init(sessionId: UInt64, flags: SessionSetupRequest.Flags = [], singing: SessionSetupSinging, capabilities: GlobalCapabilities) {
self.size = 25
self.flags = flags
self.signing = singing
self.capabilities = capabilities
self.channel = 0
self.bufferOffset = 0
self.bufferLength = 0
self.sessionId = sessionId
}
}
/// Works the client implements the SMB 3.x dialect family
struct Flags: OptionSetType {
let rawValue: UInt8
init(rawValue: UInt8) {
self.rawValue = rawValue
}
static let BINDING = NegotiateSinging(rawValue: 0x01)
}
}
struct SessionSetupResponse: SMBResponse {
let header: SessionSetupResponse.Header
let buffer: NSData?
init? (data: NSData) {
if data.length < 64 {
return nil
}
self.header = decode(data)
if Int(header.size) != 9 {
return nil
}
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))
} else {
self.buffer = nil
}
}
struct Header {
let size: UInt16
let flags: SessionSetupResponse.Flags
let bufferOffset: UInt16
let bufferLength: UInt16
}
struct Flags: OptionSetType {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
static let IS_GUEST = Flags(rawValue: 0x0001)
static let IS_NULL = Flags(rawValue: 0x0002)
static let ENCRYPT_DATA = Flags(rawValue: 0x0004)
}
}
struct SessionSetupSinging: OptionSetType {
let rawValue: UInt8
init(rawValue: UInt8) {
self.rawValue = rawValue
}
static let ENABLED = NegotiateSinging(rawValue: 0x01)
static let REQUIRED = NegotiateSinging(rawValue: 0x02)
}
// MARK: SMB2 Log off
struct LogOff: SMBRequest, SMBResponse {
let size: UInt16
let reserved: UInt16
init() {
self.size = 4
self.reserved = 0
}
init? (data: NSData) {
self = decode(data)
}
func data() -> NSData {
return encode(self)
}
}
// MARK: SMB2 Echo
struct Echo: SMBRequest, SMBResponse {
let size: UInt16
let reserved: UInt16
init() {
self.size = 4
self.reserved = 0
}
init? (data: NSData) {
self = decode(data)
}
func data() -> NSData {
return encode(self)
}
}
}
+14
View File
@@ -0,0 +1,14 @@
//
// SMB2SetInfo.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/31/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
extension SMB2 {
// MARK: SMB2 Set Info
}
+151
View File
@@ -0,0 +1,151 @@
//
// SMB2Tree.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/30/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
extension SMB2 {
// MARK: SMB2 Tree Connect
struct TreeConnectRequest: SMBRequest {
let header: TreeConnectRequest.Header
let buffer: NSData?
var path: String {
return ""
}
var share: String {
return ""
}
init? (header: TreeConnectRequest.Header, host: String, share: String) {
guard !host.containsString("/") && !host.containsString("/") && !share.containsString("/") && !share.containsString("/") else {
return nil
}
self.header = header
let path = "\\\\\(host)\\\(share)"
self.buffer = path.dataUsingEncoding(NSUTF8StringEncoding)
}
func data() -> NSData {
var header = self.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 {
result.appendData(buffer)
}
return result
}
struct Header {
let size: UInt16
let flags: TreeConnectRequest.Flags
var pathOffset: UInt16
var pathLength: UInt16
init(flags: TreeConnectRequest.Flags) {
self.size = 9
self.flags = flags
self.pathOffset = 0
self.pathLength = 0
}
}
struct Flags: OptionSetType {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
static let SHAREFLAG_CLUSTER_RECONNECT = Flags(rawValue: 0x0001)
}
}
struct TreeConnectResponse: SMBResponse {
let size: UInt16 // = 16
private let _type: UInt8
var type: ShareType {
return ShareType(rawValue: _type) ?? .UNKNOWN
}
private let reserved: UInt8
let flags: TreeConnectResponse.ShareFlags
let capabilities: TreeConnectResponse.Capabilities
let maximalAccess: FileAccessMask
init? (data: NSData) {
if data.length != 16 {
return nil
}
self = decode(data)
}
enum ShareType: UInt8 {
case UNKNOWN = 0x00
case DISK = 0x01
case PIPE = 0x02
case PRINT = 0x03
}
struct ShareFlags: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let DFS = ShareFlags(rawValue: 0x00000001)
static let DFS_ROOT = ShareFlags(rawValue: 0x00000002)
static let MANUAL_CACHING = ShareFlags(rawValue: 0x00000000)
static let AUTO_CACHING = ShareFlags(rawValue: 0x00000010)
static let VDO_CACHING = ShareFlags(rawValue: 0x00000020)
static let NO_CACHING = ShareFlags(rawValue: 0x00000030)
static let RESTRICT_EXCLUSIVE_OPENS = ShareFlags(rawValue: 0x00000100)
static let FORCE_SHARED_DELETE = ShareFlags(rawValue: 0x00000200)
static let ALLOW_NAMESPACE_CACHING = ShareFlags(rawValue: 0x00000400)
static let ACCESS_BASED_DIRECTORY_ENUM = ShareFlags(rawValue: 0x00000800)
static let FORCE_LEVELII_OPLOCK = ShareFlags(rawValue: 0x00001000)
static let ENABLE_HASH_V1 = ShareFlags(rawValue: 0x00002000)
static let ENABLE_HASH_V2 = ShareFlags(rawValue: 0x00004000)
static let ENCRYPT_DATA = ShareFlags(rawValue: 0x00008000)
}
struct Capabilities: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let DFS = Capabilities(rawValue: 0x00000008)
static let CONTINUOUS_AVAILABILITY = Capabilities(rawValue: 0x00000010)
static let SCALEOUT = Capabilities(rawValue: 0x00000020)
static let CLUSTER = Capabilities(rawValue: 0x00000040)
static let ASYMMETRIC = Capabilities(rawValue: 0x00000080)
}
}
// MARK: SMB2 Tree Disconnect
struct TreeDisconnect: SMBRequest, SMBResponse {
let size: UInt16
let reserved: UInt16
init() {
self.size = 4
self.reserved = 0
}
init? (data: NSData) {
self = decode(data)
}
func data() -> NSData {
return encode(self)
}
}
}
+131
View File
@@ -0,0 +1,131 @@
//
// SMB2Types.swift
// FileProvider
//
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
// SMB2 Types
struct SMB2 {
struct Header: FileProviderSMBHeader { // 64 bytes
// header is always \u{fe}SMB
let protocolID: UInt32
static let protocolConst: UInt32 = 0x424d53fe
let size: UInt16
let creditCharge: UInt16
// error messages from the server to the client
let status: UInt32
enum StatusSeverity: UInt8 {
case Success = 0, Information, Warning, Error
}
var statusDetails: (severity: StatusSeverity, customer: Bool, facility: UInt16, code: UInt16) {
let severity = StatusSeverity(rawValue: UInt8(status >> 30))!
return (severity, status & 0x20000000 != 0, UInt16((status & 0x0FFF0000) >> 16), UInt16(status & 0x0000FFFF))
}
private let _command: UInt16
var command: Command {
get {
return Command(rawValue: _command) ?? .INVALID
}
}
let creditRequestResponse: UInt16
let flags: Flags
var nextCommand: UInt32
let messageId: UInt64
private let reserved: UInt32
let treeId: UInt32
var asyncId: UInt64 {
get {
return UInt64(reserved) + (UInt64(treeId) << 32)
}
}
let sessionId: UInt64
let signature: (UInt64, UInt64)
init(command: Command, status: NTStatus = .SUCCESS, creditCharge: UInt16 = 0, creditRequestResponse: UInt16, flags: Flags = [], nextCommand: UInt32 = 0, messageId: UInt64, treeId: UInt32, sessionId: UInt64, signature: (UInt64, UInt64) = (0, 0)) {
self.protocolID = self.dynamicType.protocolConst
self.size = 64
self.status = status.rawValue
self._command = command.rawValue
self.creditCharge = creditCharge
self.creditRequestResponse = creditRequestResponse
self.flags = flags
self.nextCommand = nextCommand
self.messageId = messageId
self.reserved = 0
self.treeId = treeId
self.sessionId = sessionId
self.signature = signature
}
init(asyncCommand: Command, status: NTStatus = .SUCCESS, creditCharge: UInt16 = 0, creditRequestResponse: UInt16, flags: Flags = [.ASYNC_COMMAND], nextCommand: UInt32 = 0, messageId: UInt64, asyncId: UInt64, sessionId: UInt64, signature: (UInt64, UInt64) = (0, 0)) {
self.protocolID = self.dynamicType.protocolConst
self.size = 64
self.status = status.rawValue
self._command = asyncCommand.rawValue
self.creditCharge = creditCharge
self.creditRequestResponse = creditRequestResponse
self.flags = flags.union([Flags.ASYNC_COMMAND])
self.nextCommand = nextCommand
self.messageId = messageId
self.reserved = UInt32(asyncId & 0xffffffff)
self.treeId = UInt32(asyncId >> 32)
self.sessionId = sessionId
self.signature = signature
}
}
struct Flags: OptionSetType {
var rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
var priorityMask: UInt8 {
get {
return UInt8((rawValue & Flags.PRIORITY_MASK.rawValue) >> 4)
}
set {
rawValue = (rawValue & 0xffffff8f) | (UInt32(newValue & 0x7) << 4)
}
}
static let SERVER_TO_REDIR = Flags(rawValue: 0x00000001)
static let ASYNC_COMMAND = Flags(rawValue: 0x00000002)
static let RELATED_OPERATIONS = Flags(rawValue: 0x00000004)
static let SIGNED = Flags(rawValue: 0x00000008)
private static let PRIORITY_MASK = Flags(rawValue: 0x00000070)
static let DFS_OPERATIONS = Flags(rawValue: 0x10000000)
static let REPLAY_OPERATION = Flags(rawValue: 0x20000000)
}
enum Command: UInt16 {
case NEGOTIATE = 0x0000
case SESSION_SETUP = 0x0001
case LOGOFF = 0x0002
case TREE_CONNECT = 0x0003
case TREE_DISCONNECT = 0x0004
case CREATE = 0x0005
case CLOSE = 0x0006
case FLUSH = 0x0007
case READ = 0x0008
case WRITE = 0x0009
case LOCK = 0x000A
case IOCTL = 0x000B
case CANCEL = 0x000C
case ECHO = 0x000D
case QUERY_DIRECTORY = 0x000E
case CHANGE_NOTIFY = 0x000F
case QUERY_INFO = 0x0010
case SET_INFO = 0x0011
case OPLOCK_BREAK = 0x0012
case INVALID = 0xFFFF
}
// MARK: SMB2 Oplock Break
}
+208
View File
@@ -0,0 +1,208 @@
//
// SMBErrorType.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/30/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
/// Error Types and Description
enum NTStatus: UInt32, ErrorType, CustomStringConvertible {
case SUCCESS = 0x00000000
case NOT_IMPLEMENTED = 0xC0000002
case INVALID_DEVICE_REQUEST = 0xC0000010
case ILLEGAL_FUNCTION = 0xC00000AF
case NO_SUCH_FILE = 0xC000000F
case NO_SUCH_DEVICE = 0xC000000E
case OBJECT_NAME_NOT_FOUND = 0xC0000034
case OBJECT_PATH_INVALID = 0xC0000039
case OBJECT_PATH_NOT_FOUND = 0xC000003A
case OBJECT_PATH_SYNTAX_BAD = 0xC000003B
case DFS_EXIT_PATH_FOUND = 0xC000009B
case REDIRECTOR_NOT_STARTED = 0xC00000FB
case TOO_MANY_OPENED_FILES = 0xC000011F
case ACCESS_DENIED = 0xC0000022
case INVALID_LOCK_SEQUENCE = 0xC000001E
case INVALID_VIEW_SIZE = 0xC000001F
case ALREADY_COMMITTED = 0xC0000021
case PORT_CONNECTION_REFUSED = 0xC0000041
case THREAD_IS_TERMINATING = 0xC000004B
case DELETE_PENDING = 0xC0000056
case PRIVILEGE_NOT_HELD = 0xC0000061
case LOGON_FAILURE = 0xC000006D
case FILE_IS_A_DIRECTORY = 0xC00000BA
case FILE_RENAMED = 0xC00000D5
case PROCESS_IS_TERMINATING = 0xC000010A
case DIRECTORY_NOT_EMPTY = 0xC0000101
case CANNOT_DELETE = 0xC0000121
case FILE_NOT_AVAILABLE = 0xC0000467
case FILE_DELETED = 0xC0000123
case SMB_BAD_FID = 0x00060001
case INVALID_HANDLE = 0xC0000008
case OBJECT_TYPE_MISMATCH = 0xC0000024
case PORT_DISCONNECTED = 0xC0000037
case INVALID_PORT_HANDLE = 0xC0000042
case FILE_CLOSED = 0xC0000128
case HANDLE_NOT_CLOSABLE = 0xC0000235
case SECTION_TOO_BIG = 0xC0000040
case TOO_MANY_PAGING_FILES = 0xC0000097
case INSUFF_SERVER_RESOURCES = 0xC0000205
case OS2_INVALID_ACCESS = 0x000C0001
case ACCESS_DENIED_2 = 0xC00000CA
case DATA_ERROR = 0xC000009C
case NOT_SAME_DEVICE = 0xC00000D4
case NO_MORE_FILES = 0x80000006
case NO_MORE_ENTRIES = 0x8000001A
case UNSUCCESSFUL = 0xC0000001
case SHARING_VIOLATION = 0xC0000043
case FILE_LOCK_CONFLICT = 0xC0000054
case LOCK_NOT_GRANTED = 0xC0000055
case END_OF_FILE = 0xC0000011
case NOT_SUPPORTED = 0xC00000BB
case OBJECT_NAME_COLLISION = 0xC0000035
case INVALID_PARAMETER = 0xC000000D
case OS2_INVALID_LEVEL = 0x007C0001
case OS2_NEGATIVE_SEEK = 0x00830001
case RANGE_NOT_LOCKED = 0xC000007E
case OS2_NO_MORE_SIDS = 0x00710001
case OS2_CANCEL_VIOLATION = 0x00AD0001
case OS2_ATOMIC_LOCKS_NOT_SUPPORTED = 0x00AE0001
case INVALID_INFO_CLASS = 0xC0000003
case INVALID_PIPE_STATE = 0xC00000AD
case INVALID_READ_MODE = 0xC00000B4
case OS2_CANNOT_COPY = 0x010A0001
case STOPPED_ON_SYMLINK = 0x8000002D
case INSTANCE_NOT_AVAILABLE = 0xC00000AB
case PIPE_NOT_AVAILABLE = 0xC00000AC
case PIPE_BUSY = 0xC00000AE
case PIPE_CLOSING = 0xC00000B1
case PIPE_EMPTY = 0xC00000D9
case PIPE_DISCONNECTED = 0xC00000B0
case BUFFER_OVERFLOW = 0x80000005
case MORE_PROCESSING_REQUIRED = 0xC0000016
case EA_TOO_LARGE = 0xC0000050
case OS2_EAS_DIDNT_FIT = 0x01130001
case EAS_NOT_SUPPORTED = 0xC000004F
case EA_LIST_INCONSISTENT = 0x80000014
case OS2_EA_ACCESS_DENIED = 0x03E20001
case NOTIFY_ENUM_DIR = 0x0000010C
case INVALID_SMB = 0x00010002
case WRONG_PASSWORD = 0xC000006A
case PATH_NOT_COVERED = 0xC0000257
case NETWORK_NAME_DELETED = 0xC00000C9
case SMB_BAD_TID = 0x00050002
case BAD_NETWORK_NAME = 0xC00000CC
case BAD_DEVICE_TYPE = 0xC00000CB
case SMB_BAD_COMMAND = 0x00160002
case PRINT_QUEUE_FULL = 0xC00000C6
case NO_SPOOL_SPACE = 0xC00000C7
case PRINT_CANCELLED = 0xC00000C8
case UNEXPECTED_NETWORK_ERROR = 0xC00000C4
case IO_TIMEOUT = 0xC00000B5
case REQUEST_NOT_ACCEPTED = 0xC00000D0
case TOO_MANY_SESSIONS = 0xC00000CE
case SMB_BAD_UID = 0x005B0002
case SMB_USE_MPX = 0x00FA0002
case SMB_USE_STANDARD = 0x00FB0002
case SMB_CONTINUE_MPX = 0x00FC0002
case ACCOUNT_DISABLED = 0xC0000072
case ACCOUNT_EXPIRED = 0xC0000193
case INVALID_WORKSTATION = 0xC0000070
case INVALID_LOGON_HOURS = 0xC000006F
case PASSWORD_EXPIRED = 0xC0000071
case PASSWORD_MUST_CHANGE = 0xC0000224
case SMB_NO_SUPPORT = 0xFFFF0002
case MEDIA_WRITE_PROTECTED = 0xC00000A2
case NO_MEDIA_IN_DEVICE = 0xC0000013
case INVALID_DEVICE_STATE = 0xC0000184
case DATA_ERROR_2 = 0xC000003E
case CRC_ERROR = 0xC000003F
case DISK_CORRUPT_ERROR = 0xC0000032
case NONEXISTENT_SECTOR = 0xC0000015
case DEVICE_PAPER_EMPTY = 0x8000000E
case WRONG_VOLUME = 0xC0000012
case DISK_FULL = 0xC000007F
case BUFFER_TOO_SMALL = 0xC0000023
case BAD_IMPERSONATION_LEVEL = 0xC00000A5
case USER_SESSION_DELETED = 0xC0000203
case NETWORK_SESSION_EXPIRED = 0xC000035C
case SMB_TOO_MANY_UIDS = 0xC000205A
var description: String {
switch self {
case NOT_IMPLEMENTED, INVALID_DEVICE_REQUEST, ILLEGAL_FUNCTION:
return "Invalid Function."
case NO_SUCH_FILE, NO_SUCH_DEVICE, OBJECT_NAME_NOT_FOUND:
return "File not found."
case OBJECT_PATH_INVALID, OBJECT_PATH_NOT_FOUND, OBJECT_PATH_SYNTAX_BAD, DFS_EXIT_PATH_FOUND, REDIRECTOR_NOT_STARTED:
return "A component in the path prefix is not a directory."
case TOO_MANY_OPENED_FILES:
return "Too many open files. No FIDs are available."
case ACCESS_DENIED, INVALID_LOCK_SEQUENCE, INVALID_VIEW_SIZE, ALREADY_COMMITTED, PORT_CONNECTION_REFUSED, THREAD_IS_TERMINATING, DELETE_PENDING, PRIVILEGE_NOT_HELD, LOGON_FAILURE, FILE_IS_A_DIRECTORY, FILE_RENAMED, PROCESS_IS_TERMINATING, CANNOT_DELETE, FILE_DELETED:
return "Access denied."
case SMB_BAD_FID, INVALID_HANDLE, OBJECT_TYPE_MISMATCH, PORT_DISCONNECTED, INVALID_PORT_HANDLE, FILE_CLOSED, HANDLE_NOT_CLOSABLE:
return "Invalid FID."
case SECTION_TOO_BIG, TOO_MANY_PAGING_FILES, INSUFF_SERVER_RESOURCES:
return "Insufficient server memory to perform the requested operation."
case OS2_INVALID_ACCESS:
return "Invalid open mode."
case DATA_ERROR:
return "Bad data. (May be generated by IOCTL calls on the server.)"
case DIRECTORY_NOT_EMPTY:
return "Remove of directory failed because it was not empty."
case NOT_SAME_DEVICE:
return "A file system operation (such as a rename) across two devices was attempted."
case NO_MORE_FILES:
return "No (more) files found following a file search command."
case UNSUCCESSFUL:
return "General error."
case SHARING_VIOLATION:
return "Sharing violation. A requested open mode conflicts with the sharing mode of an existing file handle."
case FILE_LOCK_CONFLICT, LOCK_NOT_GRANTED:
return "A lock request specified an invalid locking mode, or conflicted with an existing file lock."
case END_OF_FILE:
return "Attempted to read beyond the end of the file."
case NOT_SUPPORTED:
return "This command is not supported by the server."
case OBJECT_NAME_COLLISION:
return "An attempt to create a file or directory failed because an object with the same pathname already exists."
case INVALID_PARAMETER:
return "A parameter supplied with the message is invalid."
case OS2_INVALID_LEVEL:
return "Invalid information level."
case OS2_NEGATIVE_SEEK:
return "An attempt was made to seek to a negative absolute offset within a file."
case RANGE_NOT_LOCKED:
return "The byte range specified in an unlock request was not locked."
case OS2_NO_MORE_SIDS:
return "Maximum number of searches has been exhausted."
case OS2_CANCEL_VIOLATION:
return "No lock request was outstanding for the supplied cancel region."
case OS2_ATOMIC_LOCKS_NOT_SUPPORTED:
return "The file system does not support atomic changes to the lock type."
case INVALID_INFO_CLASS, INVALID_PIPE_STATE, INVALID_READ_MODE:
return "Invalid named pipe."
case OS2_CANNOT_COPY:
return "The copy functions cannot be used."
case INSTANCE_NOT_AVAILABLE, PIPE_NOT_AVAILABLE, PIPE_BUSY:
return "All instances of the designated named pipe are busy."
case PIPE_CLOSING, PIPE_EMPTY:
return "The designated named pipe is in the process of being closed."
case PIPE_DISCONNECTED:
return "The designated named pipe exists, but there is no server process listening on the server side."
case BUFFER_OVERFLOW, MORE_PROCESSING_REQUIRED:
return "There is more data available to read on the designated named pipe."
case EA_TOO_LARGE, OS2_EAS_DIDNT_FIT:
return "Either there are no extended attributes, or the available extended attributes did not fit into the response."
case EAS_NOT_SUPPORTED:
return "The server file system does not support Extended Attributes."
case OS2_EA_ACCESS_DENIED:
return "Access to the extended attribute was denied."
default:
return ""
}
}
}
@@ -151,7 +151,6 @@ public class WebDAVFileProvider: NSObject, FileProviderBasic {
extension WebDAVFileProvider: FileProviderOperations {
public func createFolder(folderName: String, atPath: String, completionHandler: SimpleCompletionHandler) {
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let url = absoluteURL((atPath as NSString).stringByAppendingPathComponent(folderName) + "/")
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "MKCOL"
@@ -179,42 +178,21 @@ extension WebDAVFileProvider: FileProviderOperations {
}
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)
request.HTTPMethod = "MOVE"
request.setValue(baseURL?.absoluteString, forHTTPHeaderField: "Host")
request.setValue(absoluteURL(path).absoluteString, forHTTPHeaderField: "Destination")
if !overwrite {
request.setValue("F", forHTTPHeaderField: "Overwrite")
}
let task = session.dataTaskWithRequest(request) { (data, response, error) in
if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) {
defer {
self.delegateNotify(.Move(source: path, destination: toPath), error: error)
}
if code == .MultiStatus, let data = data {
let xresponses = self.parseXMLResponse(data)
for xresponse in xresponses {
if xresponse.status >= 300 {
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
}
}
} else {
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
}
return
}
completionHandler?(error: error)
}
task.resume()
self.copyMoveItemAtPath(true, path: path, toPath: toPath, overwrite: overwrite, completionHandler: completionHandler)
}
public func copyItemAtPath(path: String, toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) {
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
self.copyMoveItemAtPath(false, path: path, toPath: toPath, overwrite: overwrite, completionHandler: completionHandler)
}
private func copyMoveItemAtPath(move:Bool, path: String, toPath: String, overwrite: Bool, completionHandler: SimpleCompletionHandler) {
let url = absoluteURL(path)
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "COPY"
if move {
request.HTTPMethod = "MOVE"
} else {
request.HTTPMethod = "COPY"
}
request.setValue(baseURL?.absoluteString, forHTTPHeaderField: "Host")
request.setValue(absoluteURL(path).absoluteString, forHTTPHeaderField: "Destination")
if !overwrite {
@@ -223,14 +201,13 @@ extension WebDAVFileProvider: FileProviderOperations {
let task = session.dataTaskWithRequest(request) { (data, response, error) in
if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) {
defer {
self.delegateNotify(.Copy(source: path, destination: toPath), error: error)
let op = move ? FileOperation.Move(source: path, destination: toPath) : .Copy(source: path, destination: toPath)
self.delegateNotify(op, error: error)
}
if code == .MultiStatus, let data = data {
let xresponses = self.parseXMLResponse(data)
for xresponse in xresponses {
if xresponse.status >= 300 {
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
}
for xresponse in xresponses where xresponse.status >= 300 {
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
}
} else {
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
@@ -243,7 +220,6 @@ extension WebDAVFileProvider: FileProviderOperations {
}
public func removeItemAtPath(path: String, completionHandler: SimpleCompletionHandler) {
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let url = absoluteURL(path)
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "DELETE"
@@ -255,10 +231,8 @@ extension WebDAVFileProvider: FileProviderOperations {
}
if code == .MultiStatus, let data = data {
let xresponses = self.parseXMLResponse(data)
for xresponse in xresponses {
if xresponse.status >= 300 {
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
}
for xresponse in xresponses where xresponse.status >= 300 {
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
}
} else {
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
@@ -301,19 +275,17 @@ extension WebDAVFileProvider: FileProviderOperations {
extension WebDAVFileProvider: FileProviderReadWrite {
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
completionHandler(contents: data, error: error)
}
task.resume()
self.contentsAtPath(path, offset: 0, length: -1, completionHandler: completionHandler)
}
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"
request.setValue("bytes=\(offset)-\(offset + length)", forHTTPHeaderField: "Range")
if length > 0 {
request.setValue("bytes=\(offset)-\(offset + length)", forHTTPHeaderField: "Range")
} else if offset > 0 && length < 0 {
request.setValue("bytes=\(offset)-", forHTTPHeaderField: "Range")
}
let task = session.dataTaskWithRequest(request) { (data, response, error) in
completionHandler(contents: data, error: error)
}
@@ -401,16 +373,12 @@ internal extension WebDAVFileProvider {
let xml = try AEXMLDocument(xmlData: response)
var rootnode = xml.root
var responsetag = "response"
for node in rootnode.all ?? [] {
if node.name.lowercaseString.hasSuffix("multistatus") {
rootnode = node
}
for node in rootnode.all ?? [] where node.name.lowercaseString.hasSuffix("multistatus") {
rootnode = node
}
for node in rootnode.children ?? [] {
if node.name.lowercaseString.hasSuffix("response") {
responsetag = node.name
break
}
for node in rootnode.children ?? [] where node.name.lowercaseString.hasSuffix("response") {
responsetag = node.name
break
}
for responseNode in rootnode[responsetag].all ?? [] {
var hreftag = "href"
@@ -436,29 +404,23 @@ internal extension WebDAVFileProvider {
}
var propDic = [String: String]()
let propStatNode = responseNode[propstattag]
for node in propStatNode.children ?? [] {
if node.name.lowercaseString.hasSuffix("status") {
statustag = node.name
break
}
for node in propStatNode.children ?? [] where node.name.lowercaseString.hasSuffix("status"){
statustag = node.name
break
}
let statusDesc2 = (propStatNode[statustag].stringValue).componentsSeparatedByString(" ")
if statusDesc2.count > 2 {
status = Int(statusDesc2[1])
}
var proptag = "prop"
for tnode in propStatNode.children ?? [] {
if tnode.name.lowercaseString.hasSuffix("prop") {
proptag = tnode.name
}
for tnode in propStatNode.children ?? [] where tnode.name.lowercaseString.hasSuffix("prop") {
proptag = tnode.name
break
}
for propItemNode in propStatNode[proptag].children ?? [] {
propDic[propItemNode.name.componentsSeparatedByString(":").last!.lowercaseString] = propItemNode.value
if propItemNode.name.hasSuffix("resourcetype") {
if propItemNode.xmlStringCompact.containsString("collection") {
propDic["getcontenttype"] = "httpd/unix-directory"
}
if propItemNode.name.hasSuffix("resourcetype") && propItemNode.xmlStringCompact.containsString("collection") {
propDic["getcontenttype"] = "httpd/unix-directory"
}
}
result.append(DavResponse(href: hrefURL, hrefString: href, status: status, prop: propDic))
@@ -476,8 +438,8 @@ internal extension WebDAVFileProvider {
}
let name = davResponse.prop["displayname"] ?? (davResponse.hrefString.stringByRemovingPercentEncoding! as NSString).lastPathComponent
let size = Int64(davResponse.prop["getcontentlength"] ?? "-1") ?? NSURLSessionTransferSizeUnknown
let createdDate = self.resolveRFCDate(davResponse.prop["creationdate"] ?? "")
let modifiedDate = self.resolveRFCDate(davResponse.prop["getlastmodified"] ?? "")
let createdDate = self.resolveDate(davResponse.prop["creationdate"] ?? "")
let modifiedDate = self.resolveDate(davResponse.prop["getlastmodified"] ?? "")
let contentType = davResponse.prop["getcontenttype"] ?? "octet/stream"
let isDirectory = contentType == "httpd/unix-directory"
let entryTag = davResponse.prop["getetag"]