Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e6a450e3e2 | |||
| 0fd6da3658 | |||
| 67b6cf64e2 | |||
| 3ab252e598 | |||
| 09f9909363 | |||
| c6d069cb46 |
@@ -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"
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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(¶mWordsCount, 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 ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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(¶mWordsCount, 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 }
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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"]
|
||||
Reference in New Issue
Block a user