Repository: kolyvan/kxsmb
Branch: master
Commit: 30fc7b8d043c
Files: 20
Total size: 174.6 KB
Directory structure:
gitextract_3ps15m81/
├── .gitignore
├── KxSMB/
│ └── KxSMB-Prefix.pch
├── KxSMBProvider.h
├── KxSMBProvider.m
├── KxSMBSample/
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── FileViewController.h
│ ├── FileViewController.m
│ ├── KxSMBSample-Info.plist
│ ├── KxSMBSample-Prefix.pch
│ ├── SmbAuthViewController.h
│ ├── SmbAuthViewController.m
│ ├── TreeViewController.h
│ ├── TreeViewController.m
│ ├── en.lproj/
│ │ └── InfoPlist.strings
│ └── main.m
├── KxSMBSample.xcodeproj/
│ └── project.pbxproj
├── LICENSE
├── Rakefile
└── readme.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
## xcode specific
build/*
*.pbxuser
*.mode2v3
*.mode1v3
*.perspective
*.perspectivev3
*~.nib
## ignore private workspace stuff added by Xcode4
xcuserdata
project.xcworkspace
*.xcuserdata
## generic files to ignore
*~
*.lock
*.DS_Store
*.swp
*.out
## my
tmp/*
libs/*
samba/*
plan
================================================
FILE: KxSMB/KxSMB-Prefix.pch
================================================
//
// Prefix header for all source files of the 'KxSMB' target in the 'KxSMB' project
//
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#endif
================================================
FILE: KxSMBProvider.h
================================================
//
// KxSambaProvider.h
// kxsmb project
// https://github.com/kolyvan/kxsmb/
//
// Created by Kolyvan on 28.03.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <Foundation/Foundation.h>
extern NSString * const _Nonnull KxSMBErrorDomain;
typedef enum {
KxSMBErrorUnknown,
KxSMBErrorInvalidArg,
KxSMBErrorInvalidProtocol,
KxSMBErrorOutOfMemory,
KxSMBErrorAccessDenied,
KxSMBErrorInvalidPath,
KxSMBErrorPathIsNotDir,
KxSMBErrorPathIsDir,
KxSMBErrorWorkgroupNotFound,
KxSMBErrorShareDoesNotExist,
KxSMBErrorItemAlreadyExists,
KxSMBErrorDirNotEmpty,
KxSMBErrorFileIO,
KxSMBErrorConnRefused,
KxSMBErrorOpNotPermited,
} KxSMBError;
typedef enum {
KxSMBItemTypeUnknown,
KxSMBItemTypeWorkgroup,
KxSMBItemTypeServer,
KxSMBItemTypeFileShare,
KxSMBItemTypePrinter,
KxSMBItemTypeComms,
KxSMBItemTypeIPC,
KxSMBItemTypeDir,
KxSMBItemTypeFile,
KxSMBItemTypeLink,
} KxSMBItemType;
@class KxSMBItem;
@class KxSMBAuth;
typedef void (^KxSMBBlock)(id _Nullable result);
typedef void (^KxSMBBlockProgress)(KxSMBItem * _Nonnull item, long transferred, BOOL * _Nonnull stop);
@interface KxSMBItemStat : NSObject
@property(readonly, nonatomic, strong, nonnull) NSDate *lastModified;
@property(readonly, nonatomic, strong, nonnull) NSDate *lastAccess;
@property(readonly, nonatomic, strong, nonnull) NSDate *creationTime;
@property(readonly, nonatomic) SInt64 size;
@property(readonly, nonatomic) UInt16 mode;
@end
@interface KxSMBItem : NSObject
@property(readonly, nonatomic) KxSMBItemType type;
@property(readonly, nonatomic, strong, nonnull) NSString *path;
@property(readonly, nonatomic, strong, nonnull) KxSMBItemStat *stat;
@property(readonly, nonatomic, strong, nullable) KxSMBAuth *auth;
@end
@class KxSMBItemFile;
@interface KxSMBItemTree : KxSMBItem
- (void) fetchItems:(nullable KxSMBBlock)block;
- (nullable id) fetchItems;
- (void) createFileWithName:(nonnull NSString *)name
overwrite:(BOOL)overwrite
block:(nonnull KxSMBBlock)block;
- (nullable id) createFileWithName:(nonnull NSString *)name
overwrite:(BOOL)overwrite;
- (void) removeWithName:(nonnull NSString *)name
block:(nonnull KxSMBBlock)block;
- (nullable id) removeWithName:(nonnull NSString *)name;
@end
@interface KxSMBItemFile : KxSMBItem
- (void) close;
- (void)readDataOfLength:(NSUInteger)length
block:(nonnull KxSMBBlock)block;
- (nullable id)readDataOfLength:(NSUInteger)length;
- (void)readDataToEndOfFile:(nonnull KxSMBBlock)block;
- (nullable id)readDataToEndOfFile;
- (void)seekToFileOffset:(off_t)offset
whence:(NSInteger)whence
block:(nonnull KxSMBBlock)block;
- (nullable id)seekToFileOffset:(off_t)offset
whence:(NSInteger)whence;
- (void)writeData:(nonnull NSData *)data
block:(nonnull KxSMBBlock)block;
- (nullable id)writeData:(nonnull NSData *)data;
@end
@interface KxSMBAuth : NSObject
@property (readwrite, nonatomic, strong, nullable) NSString *workgroup;
@property (readwrite, nonatomic, strong, nullable) NSString *username;
@property (readwrite, nonatomic, strong, nullable) NSString *password;
+ (nullable instancetype) smbAuthWorkgroup:(nullable NSString *)workgroup
username:(nullable NSString *)username
password:(nullable NSString *)password;
@end
@protocol KxSMBProviderDelegate <NSObject>
- (nullable KxSMBAuth *) smbRequestAuthServer:(nonnull NSString *)server
share:(nonnull NSString *)share
workgroup:(nonnull NSString *)workgroup
username:(nonnull NSString *)username;
@end
// smbc_share_mode
typedef NS_ENUM(NSUInteger, KxSMBConfigShareMode) {
KxSMBConfigShareModeDenyDOS = 0,
KxSMBConfigShareModeDenyAll = 1,
KxSMBConfigShareModeDenyWrite = 2,
KxSMBConfigShareModeDenyRead = 3,
KxSMBConfigShareModeDenyNone = 4,
KxSMBConfigShareModeDenyFCB = 7,
};
// smbc_smb_encrypt_level
typedef NS_ENUM(NSUInteger, KxSMBConfigEncryptLevel) {
KxSMBConfigEncryptLevelNone = 0,
KxSMBConfigEncryptLevelRequest = 1,
KxSMBConfigEncryptLevelRequire = 2,
};
@interface KxSMBConfig : NSObject
@property (readwrite, nonatomic) NSUInteger timeout;
@property (readwrite, nonatomic) NSUInteger debugLevel;
@property (readwrite, nonatomic) BOOL debugToStderr;
@property (readwrite, nonatomic) BOOL fullTimeNames;
@property (readwrite, nonatomic) KxSMBConfigShareMode shareMode;
@property (readwrite, nonatomic) KxSMBConfigEncryptLevel encryptionLevel;
@property (readwrite, nonatomic) BOOL caseSensitive;
@property (readwrite, nonatomic) NSUInteger browseMaxLmbCount;
@property (readwrite, nonatomic) BOOL urlEncodeReaddirEntries;
@property (readwrite, nonatomic) BOOL oneSharePerServer;
@property (readwrite, nonatomic) BOOL useKerberos;
@property (readwrite, nonatomic) BOOL fallbackAfterKerberos;
@property (readwrite, nonatomic) BOOL noAutoAnonymousLogin;
@property (readwrite, nonatomic) BOOL useCCache;
@property (readwrite, nonatomic) BOOL useNTHash;
@property (readwrite, nonatomic, strong, nullable) NSString *netbiosName;
@property (readwrite, nonatomic, strong, nullable) NSString *workgroup;
@property (readwrite, nonatomic, strong, nullable) NSString *username;
@end
@interface KxSMBProvider : NSObject
@property (readwrite, nonatomic, weak) id<KxSMBProviderDelegate> delegate;
@property (readwrite, nonatomic, strong, nonnull) KxSMBConfig *config;
@property (readwrite, nonatomic, strong, nullable) dispatch_queue_t completionQueue;
+ (nullable instancetype) sharedSmbProvider;
- (void) fetchAtPath:(nonnull NSString *)path
auth:(nullable KxSMBAuth *)auth
block:(nonnull KxSMBBlock)block;
- (void) fetchAtPath:(nonnull NSString *)path
expandDir:(BOOL)expandDir
auth:(nullable KxSMBAuth *)auth
block:(nonnull KxSMBBlock)block;
- (nullable id) fetchAtPath:(nonnull NSString *)path
auth:(nullable KxSMBAuth *)auth;
- (nullable id) fetchAtPath:(nonnull NSString *)path
expandDir:(BOOL)expandDir
auth:(nullable KxSMBAuth *)auth;
- (void) createFileAtPath:(nonnull NSString *)path
overwrite:(BOOL)overwrite
auth:(nullable KxSMBAuth *)auth
block:(nonnull KxSMBBlock)block;
- (nullable id) createFileAtPath:(nonnull NSString *)path
overwrite:(BOOL)overwrite
auth:(nullable KxSMBAuth *)auth;
- (void) createFolderAtPath:(nonnull NSString *)path
auth:(nullable KxSMBAuth *)auth
block:(nonnull KxSMBBlock)block;
- (nullable id) createFolderAtPath:(nonnull NSString *)path
auth:(nullable KxSMBAuth *)auth;
- (void) removeAtPath:(nonnull NSString *)path
auth:(nullable KxSMBAuth *)auth
block:(nonnull KxSMBBlock)block;
- (nullable id) removeAtPath:(nonnull NSString *)path
auth:(nullable KxSMBAuth *)auth;
- (void) copySMBPath:(nonnull NSString *)smbPath
localPath:(nonnull NSString *)localPath
overwrite:(BOOL)overwrite
auth:(nullable KxSMBAuth *)auth
block:(nonnull KxSMBBlock)block;
- (void) copyLocalPath:(nonnull NSString *)localPath
smbPath:(nonnull NSString *)smbPath
overwrite:(BOOL)overwrite
auth:(nullable KxSMBAuth *)auth
block:(nonnull KxSMBBlock)block;
- (void) copySMBPath:(nonnull NSString *)smbPath
localPath:(nonnull NSString *)localPath
overwrite:(BOOL)overwrite
auth:(nullable KxSMBAuth *)auth
progress:(nullable KxSMBBlockProgress)progress
block:(nonnull KxSMBBlock)block;
- (void) copyLocalPath:(nonnull NSString *)localPath
smbPath:(nonnull NSString *)smbPath
overwrite:(BOOL)overwrite
auth:(nullable KxSMBAuth *)auth
progress:(nullable KxSMBBlockProgress)progress
block:(nonnull KxSMBBlock)block;
- (void) copyFromPath:(nonnull NSString *)oldPath
toPath:(nonnull NSString *)newPath
overwrite:(BOOL)overwrite
auth:(nullable KxSMBAuth *)auth
progress:(nullable KxSMBBlockProgress)progress
block:(nonnull KxSMBBlock)block;
- (void) removeFolderAtPath:(nonnull NSString *)path
auth:(nullable KxSMBAuth *)auth
block:(nonnull KxSMBBlock)block;
- (void) renameAtPath:(nonnull NSString *)oldPath
newPath:(nonnull NSString *)newPath
auth:(nullable KxSMBAuth *)auth
block:(nonnull KxSMBBlock)block;
// without auth (compatible)
- (void) fetchAtPath:(nonnull NSString *)path
block:(nullable KxSMBBlock)block;
- (nullable id) fetchAtPath:(nonnull NSString *)path;
- (void) createFileAtPath:(nonnull NSString *)path
overwrite:(BOOL)overwrite
block:(nonnull KxSMBBlock)block;
- (nullable id) createFileAtPath:(nonnull NSString *)path
overwrite:(BOOL)overwrite;
- (void) createFolderAtPath:(nonnull NSString *)path
block:(nonnull KxSMBBlock)block;
- (nullable id) createFolderAtPath:(nonnull NSString *)path;
- (void) removeAtPath:(nonnull NSString *)path
block:(nonnull KxSMBBlock)block;
- (nullable id) removeAtPath:(nonnull NSString *)path;
- (void) copySMBPath:(nonnull NSString *)smbPath
localPath:(nonnull NSString *)localPath
overwrite:(BOOL)overwrite
block:(nonnull KxSMBBlock)block;
- (void) copyLocalPath:(nonnull NSString *)localPath
smbPath:(nonnull NSString *)smbPath
overwrite:(BOOL)overwrite
block:(nonnull KxSMBBlock)block;
- (void) copySMBPath:(nonnull NSString *)smbPath
localPath:(nonnull NSString *)localPath
overwrite:(BOOL)overwrite
progress:(nullable KxSMBBlockProgress)progress
block:(nonnull KxSMBBlock)block;
- (void) copyLocalPath:(nonnull NSString *)localPath
smbPath:(nonnull NSString *)smbPath
overwrite:(BOOL)overwrite
progress:(nullable KxSMBBlockProgress)progress
block:(nonnull KxSMBBlock)block;
- (void) removeFolderAtPath:(nonnull NSString *)path
block:(nonnull KxSMBBlock)block;
- (void) renameAtPath:(nonnull NSString *)oldPath
newPath:(nonnull NSString *)newPath
block:(nonnull KxSMBBlock)block;
@end
@interface NSString (KxSMB)
- (nonnull NSString *) stringByAppendingSMBPathComponent:(nonnull NSString *)aString;
@end
================================================
FILE: KxSMBProvider.m
================================================
//
// KxSambaProvider.m
// kxsmb project
// https://github.com/kolyvan/kxsmb/
//
// Created by Kolyvan on 28.03.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "KxSMBProvider.h"
#import "libsmbclient.h"
#import "talloc_stack.h"
///////////////////////////////////////////////////////////////////////////////
NSString * const KxSMBErrorDomain = @"ru.kolyvan.KxSMB";
static NSString * KxSMBErrorMessage (KxSMBError errorCode)
{
switch (errorCode) {
case KxSMBErrorUnknown: return NSLocalizedString(@"SMB Error", nil);
case KxSMBErrorInvalidArg: return NSLocalizedString(@"SMB Invalid argument", nil);
case KxSMBErrorInvalidProtocol: return NSLocalizedString(@"SMB Invalid protocol", nil);
case KxSMBErrorOutOfMemory: return NSLocalizedString(@"SMB Out of memory", nil);
case KxSMBErrorAccessDenied: return NSLocalizedString(@"SMB Access Denied", nil);
case KxSMBErrorInvalidPath: return NSLocalizedString(@"SMB No such file or directory", nil);
case KxSMBErrorPathIsNotDir: return NSLocalizedString(@"SMB Not a directory", nil);
case KxSMBErrorPathIsDir: return NSLocalizedString(@"SMB Is a directory", nil);
case KxSMBErrorWorkgroupNotFound: return NSLocalizedString(@"SMB Workgroup not found", nil);
case KxSMBErrorShareDoesNotExist: return NSLocalizedString(@"SMB Share does not exist", nil);
case KxSMBErrorItemAlreadyExists: return NSLocalizedString(@"SMB Item already exists", nil);
case KxSMBErrorDirNotEmpty: return NSLocalizedString(@"SMB Directory not empty", nil);
case KxSMBErrorFileIO: return NSLocalizedString(@"SMB File I/O failure", nil);
case KxSMBErrorConnRefused: return NSLocalizedString(@"SMB Connection refused", nil);
case KxSMBErrorOpNotPermited: return NSLocalizedString(@"SMB Operation not permitted", nil);
}
}
static NSError * mkKxSMBError(KxSMBError error, NSString *format, ...)
{
NSDictionary *userInfo = nil;
NSString *reason = nil;
if (format) {
va_list args;
va_start(args, format);
reason = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
}
if (reason) {
userInfo = @{
NSLocalizedDescriptionKey : KxSMBErrorMessage(error),
NSLocalizedFailureReasonErrorKey : reason
};
} else {
userInfo = @{ NSLocalizedDescriptionKey : KxSMBErrorMessage(error) };
}
return [NSError errorWithDomain:KxSMBErrorDomain
code:error
userInfo:userInfo];
}
static KxSMBError errnoToSMBErr(int err)
{
switch (err) {
case EINVAL: return KxSMBErrorInvalidArg;
case ENOMEM: return KxSMBErrorOutOfMemory;
case EACCES: return KxSMBErrorAccessDenied;
case ENOENT: return KxSMBErrorInvalidPath;
case ENOTDIR: return KxSMBErrorPathIsNotDir;
case EISDIR: return KxSMBErrorPathIsDir;
case EPERM: return KxSMBErrorOpNotPermited;
case ENODEV: return KxSMBErrorShareDoesNotExist;
case EEXIST: return KxSMBErrorItemAlreadyExists;
case ENOTEMPTY: return KxSMBErrorDirNotEmpty;
case ECONNREFUSED: return KxSMBErrorConnRefused;
default: return KxSMBErrorUnknown;
}
}
///////////////////////////////////////////////////////////////////////////////
@implementation KxSMBAuth
+ (instancetype) smbAuthWorkgroup:(NSString *)workgroup
username:(NSString *)username
password:(NSString *)password
{
KxSMBAuth *auth = [[KxSMBAuth alloc] init];
auth.workgroup = workgroup;
auth.username = username;
auth.password = password;
return auth;
}
@end
///////////////////////////////////////////////////////////////////////////////
@interface KxSMBItemStat ()
@property(readwrite, nonatomic, strong) NSDate *lastModified;
@property(readwrite, nonatomic, strong) NSDate *lastAccess;
@property(readwrite, nonatomic, strong) NSDate *creationTime;
@property(readwrite, nonatomic) SInt64 size;
@property(readwrite, nonatomic) UInt16 mode;
@end
@implementation KxSMBItemStat
@end
@implementation KxSMBItem
- (id) initWithType:(KxSMBItemType) type
path:(NSString *) path
stat:(KxSMBItemStat *)stat
auth:(KxSMBAuth *)auth
{
self = [super init];
if (self) {
_type = type;
_path = path;
_stat = stat;
_auth = auth;
}
return self;
}
- (NSString *) description
{
NSString *stype = @"";
switch (_type) {
case KxSMBItemTypeUnknown: stype = @"?"; break;
case KxSMBItemTypeWorkgroup: stype = @"group"; break;
case KxSMBItemTypeServer: stype = @"server"; break;
case KxSMBItemTypeFileShare: stype = @"fileshare"; break;
case KxSMBItemTypePrinter: stype = @"printer"; break;
case KxSMBItemTypeComms: stype = @"comms"; break;
case KxSMBItemTypeIPC: stype = @"ipc"; break;
case KxSMBItemTypeDir: stype = @"dir"; break;
case KxSMBItemTypeFile: stype = @"file"; break;
case KxSMBItemTypeLink: stype = @"link"; break;
}
return [NSString stringWithFormat:@"<smb %@ '%@' %lld>",
stype, _path, _stat.size];
}
@end
///////////////////////////////////////////////////////////////////////////////
static void my_smbc_get_auth_data_fn(const char *srv,
const char *shr,
char *workgroup, int wglen,
char *username, int unlen,
char *password, int pwlen);
static void my_smbc_get_auth_data_with_context_fn(SMBCCTX *c,
const char *srv,
const char *shr,
char *wg, int wglen,
char *un, int unlen,
char *pw, int pwlen);
///////////////////////////////////////////////////////////////////////////////
@interface KxSMBItemFile()
- (id) createFile:(BOOL)overwrite;
@end
///////////////////////////////////////////////////////////////////////////////
@implementation KxSMBConfig
- (id) init
{
if ((self = [super init])) {
_timeout = 10000; // ms
#ifdef DEBUG
_debugLevel = 1;
#else
_debugLevel = 0;
#endif
_debugToStderr = YES;
_fullTimeNames = YES;
_shareMode = KxSMBConfigShareModeDenyNone;
_encryptionLevel = KxSMBConfigEncryptLevelNone;
_caseSensitive = NO;
_browseMaxLmbCount = 3;
_urlEncodeReaddirEntries = NO;
_oneSharePerServer = NO;
_useKerberos = NO;
_fallbackAfterKerberos = YES;
_noAutoAnonymousLogin = NO;
_useCCache = NO;
_useNTHash = NO;
}
return self;
}
- (void) configureSmbContext:(SMBCCTX *)smbContext
{
smbc_setTimeout(smbContext, (int)_timeout);
smbc_setDebug(smbContext, (int)_debugLevel);
smbc_setOptionDebugToStderr(smbContext, (smbc_bool)_debugToStderr);
smbc_setOptionFullTimeNames(smbContext, (smbc_bool)_fullTimeNames);
smbc_setOptionOpenShareMode(smbContext, (smbc_share_mode)_shareMode);
smbc_setOptionSmbEncryptionLevel(smbContext, (smbc_smb_encrypt_level)_encryptionLevel);
smbc_setOptionCaseSensitive(smbContext, (smbc_bool)_caseSensitive);
smbc_setOptionBrowseMaxLmbCount(smbContext, (int)_browseMaxLmbCount);
smbc_setOptionUrlEncodeReaddirEntries(smbContext, (smbc_bool)_urlEncodeReaddirEntries);
smbc_setOptionOneSharePerServer(smbContext, (smbc_bool)_oneSharePerServer);
smbc_setOptionUseKerberos(smbContext, (smbc_bool)_useKerberos);
smbc_setOptionFallbackAfterKerberos(smbContext, (smbc_bool)_fallbackAfterKerberos);
smbc_setOptionNoAutoAnonymousLogin(smbContext, (smbc_bool)_noAutoAnonymousLogin);
smbc_setOptionUseCCache(smbContext, (smbc_bool)_useCCache);
smbc_setOptionUseNTHash(smbContext, (smbc_bool)_useNTHash);
if (_netbiosName.length) {
smbc_setNetbiosName(smbContext, (char *)_netbiosName.UTF8String);
}
if (_workgroup.length) {
smbc_setWorkgroup(smbContext, (char *)_workgroup.UTF8String);
}
if (_username.length) {
smbc_setUser(smbContext, (char *)_username.UTF8String);
}
}
@end
///////////////////////////////////////////////////////////////////////////////
static KxSMBProvider *gSmbProvider;
@interface KxSMBProvider ()
@end
@implementation KxSMBProvider {
dispatch_queue_t _dispatchQueue;
}
+ (instancetype) sharedSmbProvider
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
gSmbProvider = [[KxSMBProvider alloc] init];
});
return gSmbProvider;
}
- (id) init
{
NSAssert(!gSmbProvider, @"singleton object");
self = [super init];
if (self) {
_config = [KxSMBConfig new];
_dispatchQueue = dispatch_queue_create("KxSMBProvider", DISPATCH_QUEUE_SERIAL);
_completionQueue = dispatch_get_main_queue();
}
return self;
}
- (void) dealloc
{
if (_dispatchQueue) {
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000
dispatch_release(_dispatchQueue);
#endif
_dispatchQueue = NULL;
}
}
#pragma mark - class methods
+ (SMBCCTX *) openSmbContext:(KxSMBAuth *)auth
{
//NSParameterAssert(auth);
SMBCCTX *smbContext = smbc_new_context();
if (!smbContext) {
return NULL;
}
if (auth) {
smbc_setFunctionAuthDataWithContext(smbContext, my_smbc_get_auth_data_with_context_fn);
smbc_setOptionUserData(smbContext, (void *)CFBridgingRetain(auth));
} else {
smbc_setFunctionAuthData(smbContext, my_smbc_get_auth_data_fn);
}
KxSMBConfig *cfg = [KxSMBProvider sharedSmbProvider].config;
[cfg configureSmbContext:smbContext];
if (!smbc_init_context(smbContext)) {
void *userdata = smbc_getOptionUserData(smbContext);
if (userdata) {
CFBridgingRelease(userdata);
}
smbc_free_context(smbContext, NO);
return NULL;
}
smbc_set_context(smbContext);
return smbContext;
}
+ (void) closeSmbContext:(SMBCCTX *)smbContext
{
if (smbContext) {
void *userdata = smbc_getOptionUserData(smbContext);
if (userdata) {
CFBridgingRelease(userdata);
}
// fixes warning: no talloc stackframe at libsmb/cliconnect.c:2637, leaking memory
TALLOC_CTX *frame = talloc_stackframe();
smbc_getFunctionPurgeCachedServers(smbContext)(smbContext);
TALLOC_FREE(frame);
smbc_free_context(smbContext, NO);
}
}
+ (id) fetchTreeAtPath:(NSString *)path
auth:(KxSMBAuth *)auth
{
NSParameterAssert(path);
SMBCCTX *smbContext = [self openSmbContext:auth];
if (!smbContext) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable init SMB context (errno:%d)", nil), err);
}
id result = nil;
SMBCFILE *smbFile = smbc_getFunctionOpendir(smbContext)(smbContext, path.UTF8String);
if (smbFile) {
NSMutableArray *ma = [NSMutableArray array];
struct smbc_dirent *dirent;
smbc_readdir_fn readdirFn = smbc_getFunctionReaddir(smbContext);
while((dirent = readdirFn(smbContext, smbFile)) != NULL) {
if (!dirent->name) continue;
if (!strlen(dirent->name)) continue;
if (!strcmp(dirent->name, ".") || !strcmp(dirent->name, "..") || !strcmp(dirent->name, "IPC$")) continue;
NSString *name = [NSString stringWithUTF8String:dirent->name];
NSString *itemPath;
if ([path characterAtIndex:path.length-1] == '/')
itemPath = [path stringByAppendingString:name] ;
else
itemPath = [NSString stringWithFormat:@"%@/%@", path, name];
KxSMBItemStat *stat = nil;
if (dirent->smbc_type != SMBC_WORKGROUP &&
dirent->smbc_type != SMBC_SERVER) {
id r = [self fetchStat:smbContext atPath:itemPath];
if ([r isKindOfClass:[KxSMBItemStat class]]) {
stat = r;
}
}
switch(dirent->smbc_type)
{
case SMBC_WORKGROUP:
case SMBC_SERVER: {
KxSMBItem *item = [[KxSMBItemTree alloc] initWithType:dirent->smbc_type
path:[NSString stringWithFormat:@"smb://%@", name]
stat:nil
auth:auth];
[ma addObject:item];
break;
}
case SMBC_FILE_SHARE:
case SMBC_IPC_SHARE:
case SMBC_DIR: {
KxSMBItem *item = [[KxSMBItemTree alloc] initWithType:dirent->smbc_type
path:itemPath
stat:stat
auth:auth];
[ma addObject:item];
break;
}
case SMBC_FILE: {
KxSMBItem *item = [[KxSMBItemFile alloc] initWithType:KxSMBItemTypeFile
path:itemPath
stat:stat
auth:auth];
[ma addObject:item];
break;
}
case SMBC_PRINTER_SHARE:
case SMBC_COMMS_SHARE:
case SMBC_LINK: {
KxSMBItem *item = [[KxSMBItem alloc] initWithType:dirent->smbc_type
path:itemPath
stat:stat
auth:auth];
[ma addObject:item];
break;
}
}
}
smbc_getFunctionClose(smbContext)(smbContext, smbFile);
result = [ma copy];
} else {
const int err = errno;
result = mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable open dir:%@ (errno:%d)", nil), path, err);
}
[self closeSmbContext:smbContext];
return result;
}
+ (id) fetchStat:(SMBCCTX *)smbContext
atPath:(NSString *)path
{
NSParameterAssert(smbContext);
NSParameterAssert(path);
struct stat st;
int r = smbc_getFunctionStat(smbContext)(smbContext, path.UTF8String, &st);
if (r < 0) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable get stat:%@ (errno:%d)", nil), path, err);
}
KxSMBItemStat *stat = [[KxSMBItemStat alloc] init];
stat.lastModified = [NSDate dateWithTimeIntervalSince1970: st.st_mtime];
stat.lastAccess = [NSDate dateWithTimeIntervalSince1970: st.st_atime];
stat.creationTime = [NSDate dateWithTimeIntervalSince1970: st.st_ctime];
stat.size = st.st_size;
stat.mode = st.st_mode;
return stat;
}
+ (id) fetchAtPath:(NSString *)path
expandDir:(BOOL)expandDir
auth:(KxSMBAuth *)auth
{
NSParameterAssert(path);
if (![path hasPrefix:@"smb://"]) {
return mkKxSMBError(KxSMBErrorInvalidProtocol,
NSLocalizedString(@"Path:%@", nil), path);
}
NSString *sPath = [path substringFromIndex:@"smb://".length];
if (!sPath.length) {
return [self fetchTreeAtPath:path auth:auth];
}
if ([sPath hasSuffix:@"/"]) {
sPath = [sPath substringToIndex:sPath.length - 1];
}
if (sPath.pathComponents.count == 1) {
// smb:// or smb://server/ or smb://workgroup/
return [self fetchTreeAtPath:path auth:auth];
}
id result = nil;
SMBCCTX *smbContext = [self openSmbContext:auth];
if (!smbContext) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable init SMB context (errno:%d)", nil), err);
}
result = [self fetchStat:smbContext atPath:path];
if ([result isKindOfClass:[KxSMBItemStat class]]) {
KxSMBItemStat *stat = result;
if (S_ISDIR(stat.mode)) {
if (expandDir) {
result = [self fetchTreeAtPath:path auth:auth];
} else {
result = [[KxSMBItemTree alloc] initWithType:KxSMBItemTypeDir
path:path
stat:stat
auth:auth];
}
} else if (S_ISREG(stat.mode)) {
result = [[KxSMBItemFile alloc] initWithType:KxSMBItemTypeFile
path:path
stat:stat
auth:auth];
} else {
result = [[KxSMBItem alloc] initWithType:S_ISLNK(stat.mode) ? KxSMBItemTypeLink : KxSMBItemTypeUnknown
path:path
stat:stat
auth:auth];
}
}
[self closeSmbContext:smbContext];
return result;
}
+ (id) removeAtPath:(NSString *)path
auth:(KxSMBAuth *)auth
{
NSParameterAssert(path);
if (![path hasPrefix:@"smb://"]) {
return mkKxSMBError(KxSMBErrorInvalidProtocol,
NSLocalizedString(@"Path:%@", nil), path);
}
SMBCCTX *smbContext = [self openSmbContext:auth];
if (!smbContext) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable init SMB context (errno:%d)", nil), err);
}
id result;
int r = smbc_getFunctionUnlink(smbContext)(smbContext, path.UTF8String);
if (r < 0) {
int err = errno;
if (err == EISDIR || err == EINVAL) {
r = smbc_getFunctionRmdir(smbContext)(smbContext, path.UTF8String);
if (r < 0) {
err = errno;
result = mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable rmdir file:%@ (errno:%d)", nil), path, err);
}
} else {
result = mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable unlink file:%@ (errno:%d)", nil), path, err);
}
}
[self closeSmbContext:smbContext];
return result;
}
+ (id) createFolderAtPath:(NSString *)path
auth:(KxSMBAuth *)auth
{
NSParameterAssert(path);
if (![path hasPrefix:@"smb://"]) {
return mkKxSMBError(KxSMBErrorInvalidProtocol,
NSLocalizedString(@"Path:%@", nil), path);
}
SMBCCTX *smbContext = [self openSmbContext:auth];
if (!smbContext) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable init SMB context (errno:%d)", nil), err);
}
id result;
int r = smbc_getFunctionMkdir(smbContext)(smbContext, path.UTF8String, 0);
if (r < 0) {
const int err = errno;
result = mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable mkdir:%@ (errno:%d)", nil), path, err);
} else {
id stat = [self fetchStat:smbContext atPath: path];
if ([stat isKindOfClass:[KxSMBItemStat class]]) {
result = [[KxSMBItemTree alloc] initWithType:KxSMBItemTypeDir
path:path
stat:stat
auth:auth];
} else {
result = stat;
}
}
[self closeSmbContext:smbContext];
return result;
}
+ (id) createFileAtPath:(NSString *)path
overwrite:(BOOL)overwrite
auth:(KxSMBAuth *)auth
{
NSParameterAssert(path);
if (![path hasPrefix:@"smb://"]) {
return mkKxSMBError(KxSMBErrorInvalidProtocol,
NSLocalizedString(@"Path:%@", nil), path);
}
KxSMBItemFile *itemFile = [[KxSMBItemFile alloc] initWithType:KxSMBItemTypeFile
path:path
stat:nil
auth:auth];
id result = [itemFile createFile:overwrite];
if ([result isKindOfClass:[NSError class]]) {
return result;
}
return itemFile;
}
+ (NSError *) ensureLocalFolderExists:(NSString *)folderPath
{
NSFileManager *fm = [[NSFileManager alloc] init];
BOOL isDir;
if ([fm fileExistsAtPath:folderPath isDirectory:&isDir]) {
if (!isDir) {
return mkKxSMBError(KxSMBErrorFileIO,
NSLocalizedString(@"Cannot overwrite file %@", nil),
folderPath);
}
} else {
NSError *error;
if (![fm createDirectoryAtPath:folderPath
withIntermediateDirectories:NO
attributes:nil
error:&error]) {
return error;
}
}
return nil;
}
+ (NSFileHandle *) createLocalFile:(NSString *)path
overwrite:(BOOL) overwrite
error:(NSError **)outError
{
NSFileManager *fm = [[NSFileManager alloc] init];
if ([fm fileExistsAtPath:path]) {
if (overwrite) {
if (![fm removeItemAtPath:path error:outError]) {
return nil;
}
} else {
return nil;
}
}
NSString *folder = path.stringByDeletingLastPathComponent;
if (![fm fileExistsAtPath:folder] &&
![fm createDirectoryAtPath:folder
withIntermediateDirectories:YES
attributes:nil
error:outError]) {
return nil;
}
if (![fm createFileAtPath:path
contents:nil
attributes:nil]) {
if (outError) {
*outError = mkKxSMBError(KxSMBErrorFileIO,
NSLocalizedString(@"Unable create file", nil),
path.lastPathComponent);
}
return nil;
}
return [NSFileHandle fileHandleForWritingToURL:[NSURL fileURLWithPath:path]
error:outError];
}
+ (void) readSMBFile:(KxSMBItemFile *)smbFile
fileHandle:(NSFileHandle *)fileHandle
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
[smbFile readDataOfLength:1024*1024
block:^(id result)
{
if ([result isKindOfClass:[NSData class]]) {
NSData *data = result;
if (data.length) {
[fileHandle writeData:data];
if (progress) {
BOOL stop = NO;
progress(smbFile, fileHandle.offsetInFile, &stop);
if (stop) {
// remove the local file from a disk
NSString *filePath;
char buffer[PATH_MAX] = {0};
if (fcntl(fileHandle.fileDescriptor, F_GETPATH, buffer) != -1) {
filePath = [[NSString alloc] initWithUTF8String:buffer];
}
//[fileHandle truncateFileAtOffset:0];
[fileHandle closeFile];
if (filePath.length) {
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
}
block(nil);
return;
}
}
[self readSMBFile:smbFile
fileHandle:fileHandle
progress:progress
block:block];
} else {
[fileHandle closeFile];
block(@(YES)); // complete
}
return;
}
[fileHandle closeFile];
block([result isKindOfClass:[NSError class]] ? result : nil);
}];
}
+ (void) copySMBFile:(KxSMBItemFile *)smbFile
localPath:(NSString *)localPath
overwrite:(BOOL)overwrite
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
NSError *error = nil;
NSFileHandle *fileHandle = [self createLocalFile:localPath overwrite:overwrite error:&error];
if (fileHandle) {
[self readSMBFile:smbFile
fileHandle:fileHandle
progress:progress
block:block];
} else {
if (!error) {
error = mkKxSMBError(KxSMBErrorFileIO,
NSLocalizedString(@"Cannot overwrite file %@", nil),
localPath.lastPathComponent);
}
block(error);
}
}
+ (void) enumerateSMBFolders:(NSArray *)folders
items:(NSMutableArray *)items
block:(KxSMBBlock)block
{
KxSMBItemTree *folder = folders[0];
NSMutableArray *mfolders = [folders mutableCopy];
[mfolders removeObjectAtIndex:0];
[folder fetchItems:^(id result)
{
if ([result isKindOfClass:[NSArray class]]) {
for (KxSMBItem *item in result ) {
if ([item isKindOfClass:[KxSMBItemFile class]]) {
[items addObject:item];
} else if ([item isKindOfClass:[KxSMBItemTree class]] &&
(item.type == KxSMBItemTypeDir ||
item.type == KxSMBItemTypeFileShare ||
item.type == KxSMBItemTypeServer))
{
[mfolders addObject:item];
[items addObject:item];
}
}
if (mfolders.count) {
[self enumerateSMBFolders:mfolders items:items block:block];
} else {
block(items);
}
} else {
block([result isKindOfClass:[NSError class]] ? result : nil);
}
}];
}
+ (void) copySMBItems:(NSArray *)smbItems
smbFolder:(NSString *)smbFolder
localFolder:(NSString *)localFolder
overwrite:(BOOL)overwrite
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
KxSMBItem *item = smbItems[0];
if (smbItems.count > 1) {
smbItems = [smbItems subarrayWithRange:NSMakeRange(1, smbItems.count - 1)];
} else {
smbItems = nil;
}
if ([item isKindOfClass:[KxSMBItemFile class]]) {
NSString *destPath = localFolder;
NSString *itemFolder = item.path.stringByDeletingLastPathComponent;
if (itemFolder.length > smbFolder.length) {
NSString *relPath = [itemFolder substringFromIndex:smbFolder.length];
destPath = [destPath stringByAppendingPathComponent:relPath];
}
destPath = [destPath stringByAppendingSMBPathComponent:item.path.lastPathComponent];
[self copySMBFile:(KxSMBItemFile *)item
localPath:destPath
overwrite:overwrite
progress:progress
block:^(id result)
{
if ([result isKindOfClass:[NSError class]]) {
block(result);
} else {
if (smbItems.count) {
[self copySMBItems:smbItems
smbFolder:smbFolder
localFolder:localFolder
overwrite:overwrite
progress:progress
block:block];
} else {
block(@(YES)); // complete
}
}
}];
} else if ([item isKindOfClass:[KxSMBItemTree class]]) {
NSString *destPath = localFolder;
NSString *itemFolder = item.path;
if (itemFolder.length > smbFolder.length) {
NSString *relPath = [itemFolder substringFromIndex:smbFolder.length];
destPath = [destPath stringByAppendingPathComponent:relPath];
}
NSError *error = [self ensureLocalFolderExists:destPath];
if (error) {
block(error);
return;
}
if (smbItems.count) {
[self copySMBItems:smbItems
smbFolder:smbFolder
localFolder:localFolder
overwrite:overwrite
progress:progress
block:block];
} else {
block(@(YES)); // complete
}
}
}
///
+ (void) writeSMBFile:(KxSMBItemFile *)smbFile
fileHandle:(NSFileHandle *)fileHandle
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
NSData *data;
@try {
data = [fileHandle readDataOfLength:1024*1024];
}
@catch (NSException *exception) {
[fileHandle closeFile];
block(mkKxSMBError(KxSMBErrorFileIO, [exception description]));
return;
}
if (data.length) {
[smbFile writeData:data block:^(id result) {
if ([result isKindOfClass:[NSNumber class]]) {
if (progress) {
BOOL stop = NO;
progress(smbFile, fileHandle.offsetInFile, &stop);
if (stop) {
[fileHandle closeFile];
// remove the smbfile from a share
NSString *smbPath = smbFile.path;
[smbFile close];
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchAsync:^{
[KxSMBProvider removeAtPath:smbPath auth:smbFile.auth];
}];
block(nil);
return;
}
}
[self writeSMBFile:smbFile
fileHandle:fileHandle
progress:progress
block:block];
return;
}
block([result isKindOfClass:[NSError class]] ? result : nil);
}];
} else {
[fileHandle closeFile];
block(smbFile);
}
}
+ (void) copyLocalFile:(NSString *)localPath
smbPath:(NSString *)smbPath
overwrite:(BOOL)overwrite
auth:(KxSMBAuth *)auth
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider createFileAtPath:smbPath
overwrite:overwrite
auth:auth
block:^(id result)
{
if ([result isKindOfClass:[KxSMBItemFile class]]) {
NSError *error = nil;
NSFileHandle *fileHandle;
NSURL *url =[NSURL fileURLWithPath:localPath];
fileHandle = [NSFileHandle fileHandleForReadingFromURL:url error:&error];
if (fileHandle) {
[self writeSMBFile:result
fileHandle:fileHandle
progress:progress
block:block];
} else {
block(error);
}
} else {
block([result isKindOfClass:[NSError class]] ? result : nil);
}
}];
}
+ (void) copyLocalFiles:(NSDirectoryEnumerator *)enumerator
localFolder:(NSString *)localFolder
smbFolder:(KxSMBItemTree *)smbFolder
overwrite:(BOOL)overwrite
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
NSString *path = [enumerator nextObject];
if (path) {
if (path.length && [path characterAtIndex:0] != '.') {
NSDictionary *attr = [enumerator fileAttributes];
if ([[attr fileType] isEqualToString:NSFileTypeDirectory]) {
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider createFolderAtPath:[smbFolder.path stringByAppendingSMBPathComponent:path]
auth:smbFolder.auth
block:^(id result)
{
if ([result isKindOfClass:[NSError class]]) {
block(result);
} else {
[self copyLocalFiles:enumerator
localFolder:localFolder
smbFolder:smbFolder
overwrite:overwrite
progress:progress
block:block];
}
}];
return;
} else if ([[attr fileType] isEqualToString:NSFileTypeRegular]) {
NSString *destFolder = smbFolder.path;
NSString *fileFolder = path.stringByDeletingLastPathComponent;
if (fileFolder.length) {
destFolder = [destFolder stringByAppendingSMBPathComponent:fileFolder];
}
[self copyLocalFile:[localFolder stringByAppendingPathComponent:path]
smbPath:[destFolder stringByAppendingSMBPathComponent:path.lastPathComponent]
overwrite:overwrite
auth:smbFolder.auth
progress:progress
block:^(id result)
{
if ([result isKindOfClass:[NSError class]]) {
block(result);
} else {
[self copyLocalFiles:enumerator
localFolder:localFolder
smbFolder:smbFolder
overwrite:overwrite
progress:progress
block:block];
}
}];
return;
}
}
[self copyLocalFiles:enumerator
localFolder:localFolder
smbFolder:smbFolder
overwrite:overwrite
progress:progress
block:block];
} else {
block(smbFolder);
}
}
+ (void) copyFileFromPath:(NSString *)oldPath
toPath:(NSString *)newPath
overwrite:(BOOL)overwrite
auth:(KxSMBAuth *)auth
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider fetchAtPath:oldPath
expandDir:NO
auth:auth
block:^(id result)
{
if ([result isKindOfClass:[KxSMBItemFile class]]) {
KxSMBItemFile *fromFile = result;
[provider createFileAtPath:newPath
overwrite:overwrite
auth:auth
block:^(id result)
{
if ([result isKindOfClass:[KxSMBItemFile class]]) {
KxSMBItemFile *toFile = result;
[self copyFromSMBFile:fromFile
toSMBFile:toFile
progress:progress
block:block];
} else {
block([result isKindOfClass:[NSError class]] ? result : nil);
}
}];
} else if ([result isKindOfClass:[KxSMBItemTree class]]) {
block(mkKxSMBError(KxSMBErrorPathIsDir, newPath, 0));
} else {
block([result isKindOfClass:[NSError class]] ? result : nil);
}
}];
}
+ (void) copyFromSMBFile:(KxSMBItemFile *)fromFile
toSMBFile:(KxSMBItemFile *)toFile
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
[fromFile readDataOfLength:1024*1024
block:^(id result)
{
if ([result isKindOfClass:[NSData class]]) {
NSData *data = result;
if (data.length) {
[toFile writeData:data block:^(id result) {
if ([result isKindOfClass:[NSNumber class]]) {
if (progress) {
BOOL stop = NO;
progress(fromFile, 0, &stop);
if (stop) {
// remove the dest smbfile from a share
NSString *smbPath = toFile.path;
[toFile close];
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchAsync:^{
[KxSMBProvider removeAtPath:smbPath auth:toFile.auth];
}];
block(nil);
return;
}
}
[self copyFromSMBFile:fromFile
toSMBFile:toFile
progress:progress
block:block];
return;
}
block([result isKindOfClass:[NSError class]] ? result : nil);
}];
} else {
block(toFile); // complete
}
return;
}
block([result isKindOfClass:[NSError class]] ? result : nil);
}];
}
///
+ (void) removeSMBItems:(NSArray *)smbItems
block:(KxSMBBlock)block
{
KxSMBItem *item = smbItems[0];
if (smbItems.count > 1) {
smbItems = [smbItems subarrayWithRange:NSMakeRange(1, smbItems.count - 1)];
} else {
smbItems = nil;
}
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider removeAtPath:item.path
auth:item.auth
block:^(id result) {
if ([result isKindOfClass:[NSError class]]) {
block(result);
} else if (smbItems.count) {
[self removeSMBItems:smbItems block:block];
} else {
block(@(YES));
}
}];
}
+ (id) renameAtPath:(NSString *)oldPath
newPath:(NSString *)newPath
auth:(KxSMBAuth *)auth
{
NSParameterAssert(oldPath);
NSParameterAssert(newPath);
if (![oldPath hasPrefix:@"smb://"]) {
return mkKxSMBError(KxSMBErrorInvalidProtocol,
NSLocalizedString(@"Path:%@", nil), oldPath);
}
if (![newPath hasPrefix:@"smb://"]) {
return mkKxSMBError(KxSMBErrorInvalidProtocol,
NSLocalizedString(@"Path:%@", nil), newPath);
}
SMBCCTX *smbContext = [self openSmbContext:auth];
if (!smbContext) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable init SMB context (errno:%d)", nil), err);
}
id result;
int r = smbc_getFunctionRename(smbContext)(smbContext, oldPath.UTF8String, smbContext, newPath.UTF8String);
if (r < 0) {
const int err = errno;
result = mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable rename file:%@ (errno:%d)", nil), oldPath, err);
} else {
result = [self fetchStat:smbContext atPath: newPath];
if ([result isKindOfClass:[KxSMBItemStat class]]) {
KxSMBItemStat *stat = result;
if (S_ISDIR(stat.mode)) {
result = [[KxSMBItemTree alloc] initWithType:KxSMBItemTypeDir
path:newPath
stat:stat
auth:auth];
} else if (S_ISREG(stat.mode)) {
result = [[KxSMBItemFile alloc] initWithType:KxSMBItemTypeFile
path:newPath
stat:stat
auth:auth];
} else {
result = nil;
}
}
}
[self closeSmbContext:smbContext];
return result;
}
+ (void) fireBlock:(KxSMBBlock)block withResult:(id)result
{
dispatch_queue_t queue = [KxSMBProvider sharedSmbProvider].completionQueue;
if (queue) {
dispatch_async(queue, ^{ block(result); });
} else {
block(result);
}
}
#pragma mark - internal methods
- (void) dispatchSync: (dispatch_block_t) block
{
dispatch_sync(_dispatchQueue, block);
}
- (void) dispatchAsync: (dispatch_block_t) block
{
dispatch_async(_dispatchQueue, block);
}
#pragma mark - public methods
- (void) fetchAtPath:(NSString *)path
expandDir:(BOOL)expandDir
auth:(KxSMBAuth *)auth
block:(KxSMBBlock)block
{
NSParameterAssert(path);
NSParameterAssert(block);
dispatch_async(_dispatchQueue, ^{
id result = [KxSMBProvider fetchAtPath:(path.length ? path : @"smb://")
expandDir:expandDir
auth:auth];
[KxSMBProvider fireBlock:block withResult:result];
});
}
- (void) fetchAtPath:(NSString *)path
auth:(KxSMBAuth *)auth
block:(KxSMBBlock)block
{
[self fetchAtPath:path
expandDir:YES
auth:auth
block:block];
}
- (id) fetchAtPath:(NSString *)path
expandDir:(BOOL)expandDir
auth:(KxSMBAuth *)auth
{
NSParameterAssert(path);
__block id result = nil;
dispatch_sync(_dispatchQueue, ^{
result = [KxSMBProvider fetchAtPath:(path.length ? path : @"smb://")
expandDir:expandDir
auth:auth];
});
return result;
}
- (id) fetchAtPath:(NSString *)path
auth:(KxSMBAuth *)auth
{
return [self fetchAtPath:path expandDir:YES auth:auth];
}
- (void) createFileAtPath:(NSString *)path
overwrite:(BOOL)overwrite
auth:(KxSMBAuth *)auth
block:(KxSMBBlock) block
{
NSParameterAssert(path);
NSParameterAssert(block);
dispatch_async(_dispatchQueue, ^{
id result = [KxSMBProvider createFileAtPath:path overwrite:overwrite auth:auth];
[KxSMBProvider fireBlock:block withResult:result];
});
}
- (id) createFileAtPath:(NSString *)path
overwrite:(BOOL)overwrite
auth:(KxSMBAuth *)auth
{
NSParameterAssert(path);
__block id result = nil;
dispatch_sync(_dispatchQueue, ^{
result = [KxSMBProvider createFileAtPath:path overwrite:overwrite auth:auth];
});
return result;
}
- (void) removeAtPath:(NSString *)path
auth:(KxSMBAuth *)auth
block:(KxSMBBlock)block
{
NSParameterAssert(path);
NSParameterAssert(block);
dispatch_async(_dispatchQueue, ^{
id result = [KxSMBProvider removeAtPath:path auth:auth];
[KxSMBProvider fireBlock:block withResult:result];
});
}
- (id) removeAtPath:(NSString *)path
auth:(KxSMBAuth *)auth
{
NSParameterAssert(path);
__block id result = nil;
dispatch_sync(_dispatchQueue, ^{
result = [KxSMBProvider removeAtPath:path auth:auth];
});
return result;
}
- (void) createFolderAtPath:(NSString *)path
auth:(KxSMBAuth *)auth
block:(KxSMBBlock)block
{
NSParameterAssert(path);
NSParameterAssert(block);
dispatch_async(_dispatchQueue, ^{
id result = [KxSMBProvider createFolderAtPath:path auth:auth];
[KxSMBProvider fireBlock:block withResult:result];
});
}
- (id) createFolderAtPath:(NSString *)path
auth:(KxSMBAuth *)auth
{
NSParameterAssert(path);
__block id result = nil;
dispatch_sync(_dispatchQueue, ^{
result = [KxSMBProvider createFolderAtPath:path auth:auth];
});
return result;
}
- (void) copySMBPath:(NSString *)smbPath
localPath:(NSString *)localPath
overwrite:(BOOL)overwrite
auth:(KxSMBAuth *)auth
block:(KxSMBBlock)block
{
[self copySMBPath:smbPath localPath:localPath overwrite:overwrite auth:auth progress:nil block:block];;
}
- (void) copyLocalPath:(NSString *)localPath
smbPath:(NSString *)smbPath
overwrite:(BOOL)overwrite
auth:(KxSMBAuth *)auth
block:(KxSMBBlock)block
{
[self copyLocalPath:localPath smbPath:smbPath overwrite:overwrite auth:auth progress:nil block:block];
}
- (void) copySMBPath:(NSString *)smbPath
localPath:(NSString *)localPath
overwrite:(BOOL)overwrite
auth:(KxSMBAuth *)auth
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
[self fetchAtPath:smbPath
expandDir:YES
auth:auth
block:^(id result) {
if ([result isKindOfClass:[KxSMBItemFile class]]) {
[KxSMBProvider copySMBFile:result
localPath:localPath
overwrite:overwrite
progress:progress
block:block];
} else if ([result isKindOfClass:[NSArray class]]) {
NSError *error = [KxSMBProvider ensureLocalFolderExists:localPath];
if (error) {
block(error);
return;
}
NSMutableArray *folders = [NSMutableArray array];
NSMutableArray *items = [NSMutableArray array];
for (KxSMBItem *item in result ) {
if ([item isKindOfClass:[KxSMBItemFile class]]) {
[items addObject:item];
} else if ([item isKindOfClass:[KxSMBItemTree class]] &&
(item.type == KxSMBItemTypeDir ||
item.type == KxSMBItemTypeFileShare ||
item.type == KxSMBItemTypeServer))
{
[items addObject:item];
[folders addObject:item];
}
}
if (folders.count) {
[KxSMBProvider enumerateSMBFolders:folders
items:items
block:^(id result)
{
if ([result isKindOfClass:[NSArray class]]) {
NSArray *items = result;
if (items.count) {
[KxSMBProvider copySMBItems:items
smbFolder:smbPath
localFolder:localPath
overwrite:overwrite
progress:progress
block:block];
} else {
block(@(YES));
}
} else {
block(result);
}
}];
} else if (items.count) {
[KxSMBProvider copySMBItems:items
smbFolder:smbPath
localFolder:localPath
overwrite:overwrite
progress:progress
block:block];
} else {
block(@(YES));
return;
}
} else {
block([result isKindOfClass:[NSError class]] ? result : nil);
}
}];
}
- (void) copyLocalPath:(NSString *)localPath
smbPath:(NSString *)smbPath
overwrite:(BOOL)overwrite
auth:(KxSMBAuth *)auth
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
NSFileManager *fm = [[NSFileManager alloc] init];
BOOL isDir;
if (![fm fileExistsAtPath:localPath isDirectory:&isDir]) {
block(mkKxSMBError(KxSMBErrorFileIO,
NSLocalizedString(@"File '%@' is not exist", nil),
localPath.lastPathComponent));
return;
}
if (isDir) {
[self createFolderAtPath:smbPath
auth:auth
block:^(id result)
{
if ([result isKindOfClass:[KxSMBItemTree class]]) {
[KxSMBProvider copyLocalFiles:[fm enumeratorAtPath:localPath]
localFolder:localPath
smbFolder:result
overwrite:overwrite
progress:progress
block:block];
} else {
block([result isKindOfClass:[NSError class]] ? result : nil);
}
}];
} else {
[KxSMBProvider copyLocalFile:localPath
smbPath:smbPath
overwrite:overwrite
auth:auth
progress:progress
block:block];
}
}
- (void) copyFromPath:(NSString *)oldPath
toPath:(NSString *)newPath
overwrite:(BOOL)overwrite
auth:(KxSMBAuth *)auth
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
[KxSMBProvider copyFileFromPath:oldPath
toPath:newPath
overwrite:overwrite
auth:auth
progress:progress
block:block];
}
- (void) removeFolderAtPath:(NSString *)path
auth:(KxSMBAuth *)auth
block:(KxSMBBlock)block
{
[self fetchAtPath:path
expandDir:YES
auth:auth
block:^(id result)
{
if ([result isKindOfClass:[NSArray class]]) {
NSMutableArray *folders = [NSMutableArray array];
NSMutableArray *items = [NSMutableArray array];
for (KxSMBItem *item in result) {
if ([item isKindOfClass:[KxSMBItemFile class]]) {
[items addObject:item];
} else if ([item isKindOfClass:[KxSMBItemTree class]] &&
(item.type == KxSMBItemTypeDir ||
item.type == KxSMBItemTypeFileShare ||
item.type == KxSMBItemTypeServer))
{
[items addObject:item];
[folders addObject:item];
}
}
if (folders.count) {
[KxSMBProvider enumerateSMBFolders:folders
items:items
block:^(id result)
{
if ([result isKindOfClass:[NSArray class]]) {
NSMutableArray *reversed = [NSMutableArray array];
for (id item in [result reverseObjectEnumerator]) {
[reversed addObject:item];
}
[KxSMBProvider removeSMBItems:reversed block:^(id result) {
if ([result isKindOfClass:[NSNumber class]]) {
[[KxSMBProvider sharedSmbProvider] removeAtPath:path
auth:auth
block:block];
} else {
block([result isKindOfClass:[NSError class]] ? result : nil);
}
}];
} else {
block([result isKindOfClass:[NSError class]] ? result : nil);
}
}];
} else if (items.count) {
[KxSMBProvider removeSMBItems:items block:^(id result) {
if ([result isKindOfClass:[NSNumber class]]) {
[[KxSMBProvider sharedSmbProvider] removeAtPath:path
auth:auth
block:block];
} else {
block([result isKindOfClass:[NSError class]] ? result : nil);
}
}];
} else {
[self removeAtPath:path auth:auth block:block];
}
} else if ([result isKindOfClass:[KxSMBItemFile class]]) {
block(mkKxSMBError(KxSMBErrorPathIsNotDir, path));
} else {
block([result isKindOfClass:[NSError class]] ? result : nil);
}
}];
}
- (void) renameAtPath:(NSString *)oldPath
newPath:(NSString *)newPath
auth:(KxSMBAuth *)auth
block:(KxSMBBlock)block
{
NSParameterAssert(oldPath);
NSParameterAssert(newPath);
NSParameterAssert(block);
dispatch_async(_dispatchQueue, ^{
id result = [KxSMBProvider renameAtPath:oldPath newPath:newPath auth:auth];
[KxSMBProvider fireBlock:block withResult:result];
});
}
#pragma mark - compatible (without auth)
// without auth (compatible)
- (void) fetchAtPath:(NSString *)path
block:(KxSMBBlock)block
{
[self fetchAtPath:path expandDir:YES auth:nil block:block];
}
- (id) fetchAtPath:(NSString *)path
{
return [self fetchAtPath:path expandDir:YES auth:nil];
}
- (void) createFileAtPath:(NSString *)path
overwrite:(BOOL)overwrite
block:(KxSMBBlock)block
{
[self createFileAtPath:path
overwrite:overwrite
auth:nil
block:block];
}
- (id) createFileAtPath:(NSString *)path
overwrite:(BOOL)overwrite
{
return [self createFileAtPath:path overwrite:overwrite auth:nil];
}
- (void) createFolderAtPath:(NSString *)path
block:(KxSMBBlock)block
{
[self createFolderAtPath:path
auth:nil
block:block];
}
- (id) createFolderAtPath:(NSString *)path
{
return [self createFolderAtPath:path auth:nil];
}
- (void) removeAtPath:(NSString *)path
block:(KxSMBBlock)block
{
[self removeAtPath:path
auth:nil
block:block];
}
- (id) removeAtPath:(NSString *)path
{
return [self removeAtPath:path auth:nil];
}
- (void) copySMBPath:(NSString *)smbPath
localPath:(NSString *)localPath
overwrite:(BOOL)overwrite
block:(KxSMBBlock)block
{
[self copySMBPath:smbPath
localPath:localPath
overwrite:overwrite
auth:nil
block:block];
}
- (void) copyLocalPath:(NSString *)localPath
smbPath:(NSString *)smbPath
overwrite:(BOOL)overwrite
block:(KxSMBBlock)block
{
[self copyLocalPath:localPath
smbPath:smbPath
overwrite:overwrite
auth:nil
block:block];
}
- (void) copySMBPath:(NSString *)smbPath
localPath:(NSString *)localPath
overwrite:(BOOL)overwrite
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
[self copySMBPath:smbPath
localPath:localPath
overwrite:overwrite
auth:nil
progress:progress
block:block];
}
- (void) copyLocalPath:(NSString *)localPath
smbPath:(NSString *)smbPath
overwrite:(BOOL)overwrite
progress:(KxSMBBlockProgress)progress
block:(KxSMBBlock)block
{
[self copyLocalPath:localPath
smbPath:smbPath
overwrite:overwrite
auth:nil
progress:progress
block:block];
}
- (void) removeFolderAtPath:(NSString *)path
block:(KxSMBBlock)block
{
[self removeFolderAtPath:path
auth:nil
block:block];
}
- (void) renameAtPath:(NSString *)oldPath
newPath:(NSString *)newPath
block:(KxSMBBlock)block
{
[self renameAtPath:oldPath
newPath:newPath
auth:nil
block:block];
}
#if 0
+ (void) dumpSmbcOptions:(SMBCCTX *)smbContext
{
NSLog(@"Debug: %d", smbc_getDebug(smbContext));
NSLog(@"NetbiosName: %s", smbc_getNetbiosName(smbContext));
NSLog(@"Workgroup: %s", smbc_getWorkgroup(smbContext));
NSLog(@"User: %s", smbc_getUser(smbContext));
NSLog(@"Timeout: %d", smbc_getTimeout(smbContext));
NSLog(@"DebugToStderr: %d", smbc_getOptionDebugToStderr(smbContext));
NSLog(@"FullTimeNames: %d", smbc_getOptionFullTimeNames(smbContext));
NSLog(@"OpenShareMode: %d", smbc_getOptionOpenShareMode(smbContext));
NSLog(@"EncryptionLevel: %d", smbc_getOptionSmbEncryptionLevel(smbContext));
NSLog(@"CaseSensitive: %d", smbc_getOptionCaseSensitive(smbContext));
NSLog(@"BrowseMaxLmbCount: %d", smbc_getOptionBrowseMaxLmbCount(smbContext));
NSLog(@"UrlEncodeReaddirEntries: %d", smbc_getOptionUrlEncodeReaddirEntries(smbContext));
NSLog(@"OneSharePerServer: %d", smbc_getOptionOneSharePerServer(smbContext));
NSLog(@"UseKerberos: %d", smbc_getOptionUseKerberos(smbContext));
NSLog(@"FallbackAfterKerberos: %d", smbc_getOptionFallbackAfterKerberos(smbContext));
NSLog(@"NoAutoAnonymousLogin: %d", smbc_getOptionNoAutoAnonymousLogin(smbContext));
NSLog(@"UseCCache: %d", smbc_getOptionUseCCache(smbContext));
NSLog(@"UseNTHash: %d", smbc_getOptionUseNTHash(smbContext));
}
#endif
@end
///////////////////////////////////////////////////////////////////////////////
@implementation KxSMBItemTree
- (void) fetchItems:(KxSMBBlock) block
{
NSParameterAssert(block);
NSString *path = self.path;
KxSMBAuth *auth = self.auth;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchAsync: ^{
id result = [KxSMBProvider fetchTreeAtPath:path auth:auth];
[KxSMBProvider fireBlock:block withResult:result];
}];
}
- (id) fetchItems
{
__block id result = nil;
NSString *path = self.path;
KxSMBAuth *auth = self.auth;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchSync: ^{
result = [KxSMBProvider fetchTreeAtPath:path auth:auth];
}];
return result;
}
- (void) createFileWithName:(NSString *)name
overwrite:(BOOL)overwrite
block:(KxSMBBlock)block
{
NSParameterAssert(name.length);
if (self.type != KxSMBItemTypeDir ||
self.type != KxSMBItemTypeFileShare)
{
block(mkKxSMBError(KxSMBErrorPathIsNotDir, nil));
return;
}
[[KxSMBProvider sharedSmbProvider] createFileAtPath:[self.path stringByAppendingSMBPathComponent:name]
overwrite:overwrite
auth:self.auth
block:block];
}
- (id) createFileWithName:(NSString *)name
overwrite:(BOOL)overwrite
{
NSParameterAssert(name.length);
if (self.type != KxSMBItemTypeDir ||
self.type != KxSMBItemTypeFileShare )
{
return mkKxSMBError(KxSMBErrorPathIsNotDir, nil);
}
NSString *path = [self.path stringByAppendingSMBPathComponent:name];
return [[KxSMBProvider sharedSmbProvider] createFileAtPath:path
overwrite:overwrite
auth:self.auth];
}
- (void) removeWithName:(NSString *)name
block:(KxSMBBlock)block
{
if (self.type != KxSMBItemTypeDir ||
self.type != KxSMBItemTypeFileShare)
{
block(mkKxSMBError(KxSMBErrorPathIsNotDir, nil));
return;
}
NSString *path = [self.path stringByAppendingSMBPathComponent:name];
[[KxSMBProvider sharedSmbProvider] removeAtPath:path
auth:self.auth
block:block];
}
- (id) removeWithName:(NSString *)name
{
if (self.type != KxSMBItemTypeDir ||
self.type != KxSMBItemTypeFileShare )
{
return mkKxSMBError(KxSMBErrorPathIsNotDir, nil);
}
NSString *path = [self.path stringByAppendingSMBPathComponent:name];
return [[KxSMBProvider sharedSmbProvider] removeAtPath:path
auth:self.auth];
}
@end
///////////////////////////////////////////////////////////////////////////////
@interface KxSMBFileImpl : NSObject
@end
@implementation KxSMBFileImpl {
SMBCCTX *_context;
SMBCFILE *_file;
NSString *_path;
KxSMBAuth *_auth;
}
- (id) initWithPath:(NSString *)path
auth:(KxSMBAuth *)auth
{
self = [super init];
if (self) {
_path = path;
_auth = auth;
}
return self;
}
- (NSError *) openFile
{
_context = [KxSMBProvider openSmbContext:_auth];
if (!_context) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable init SMB context (errno:%d)", nil), err);
}
_file = smbc_getFunctionOpen(_context)(_context,
_path.UTF8String,
O_RDONLY,
0);
if (!_file) {
[KxSMBProvider closeSmbContext:_context];
_context = NULL;
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable open file:%@ (errno:%d)", nil), _path, err);
}
return nil;
}
- (NSError *) createFile:(BOOL)overwrite
{
_context = [KxSMBProvider openSmbContext:_auth];
if (!_context) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable init SMB context (errno:%d)", nil), err);
}
_file = smbc_getFunctionCreat(_context)(_context,
_path.UTF8String,
O_WRONLY|O_CREAT|(overwrite ? O_TRUNC : O_EXCL));
if (!_file) {
[KxSMBProvider closeSmbContext:_context];
_context = NULL;
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable open file:%@ (errno:%d)", nil), _path, err);
}
return nil;
}
- (void) closeFile
{
if (_file) {
smbc_getFunctionClose(_context)(_context, _file);
_file = NULL;
}
if (_context) {
[KxSMBProvider closeSmbContext:_context];
_context = NULL;
}
}
- (id)readDataOfLength:(NSUInteger)length
{
if (!_file) {
NSError *error = [self openFile];
if (error) return error;
}
// it seems 512 kb is an optimal buffer size
const size_t bufferSize = MIN(length, 512*1024);
Byte *buffer = malloc(bufferSize);
if (!buffer) {
return mkKxSMBError(KxSMBErrorOutOfMemory, nil);
}
smbc_read_fn readFn = smbc_getFunctionRead(_context);
NSMutableData *md = [NSMutableData data];
NSInteger bytesToRead = length;
while (bytesToRead > 0) {
ssize_t r = readFn(_context, _file, buffer, MIN(bytesToRead, bufferSize));
if (r == 0)
break;
if (r < 0) {
const int err = errno;
free(buffer);
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable read file:%@ (errno:%d)", nil), _path, err);
}
[md appendBytes:buffer length:r];
bytesToRead -= r;
}
free(buffer);
return md;
}
- (id)readDataToEndOfFile
{
if (!_file) {
NSError *error = [self openFile];
if (error) return error;
}
Byte buffer[32768];
smbc_read_fn readFn = smbc_getFunctionRead(_context);
NSMutableData *md = [NSMutableData data];
while (1) {
ssize_t r = readFn(_context, _file, buffer, sizeof(buffer));
if (r == 0)
break;
if (r < 0) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable read file:%@ (errno:%d)", nil), _path, err);
}
[md appendBytes:buffer length:r];
}
return md;
}
- (id)seekToFileOffset:(off_t)offset
whence:(NSInteger)whence
{
if (!_file) {
NSError *error = [self openFile];
if (error) return error;
}
off_t r = smbc_getFunctionLseek(_context)(_context, _file, offset, (int)whence);
if (r < 0) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable seek to file:%@ (errno:%d)", nil), _path, errno);
}
return @(r);
}
- (id)writeData:(NSData *)data
{
if (!_file) {
NSError *error = [self createFile:NO];
if (error) return error;
}
smbc_write_fn writeFn = smbc_getFunctionWrite(_context);
NSInteger bytesToWrite = data.length;
const Byte *bytes = data.bytes;
while (bytesToWrite > 0) {
ssize_t r = writeFn(_context, _file, bytes, bytesToWrite);
if (r == 0)
break;
if (r < 0) {
const int err = errno;
return mkKxSMBError(errnoToSMBErr(err),
NSLocalizedString(@"Unable write file:%@ (errno:%d)", nil), _path, err);
}
bytesToWrite -= r;
bytes += r;
}
return @(data.length - bytesToWrite);
}
@end
@implementation KxSMBItemFile {
KxSMBFileImpl *_impl;
}
- (void) dealloc
{
[self close];
}
- (void) close
{
if (_impl) {
KxSMBFileImpl *p = _impl;
_impl = nil;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchAsync:^{ [p closeFile]; }];
}
}
- (KxSMBFileImpl *)theImpl
{
if (!_impl) {
_impl = [[KxSMBFileImpl alloc] initWithPath:self.path auth:self.auth];
}
return _impl;
}
- (void)readDataOfLength:(NSUInteger)length
block:(KxSMBBlock)block
{
NSParameterAssert(block);
KxSMBFileImpl *p = self.theImpl;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchAsync:^{
id result = [p readDataOfLength:length];
[KxSMBProvider fireBlock:block withResult:result];
}];
}
- (id)readDataOfLength:(NSUInteger)length
{
__block id result = nil;
KxSMBFileImpl *p = self.theImpl;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchSync:^{
result = [p readDataOfLength:length];
}];
return result;
}
- (void)readDataToEndOfFile:(KxSMBBlock)block
{
NSParameterAssert(block);
KxSMBFileImpl *p = self.theImpl;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchAsync:^{
id result = [p readDataToEndOfFile];
[KxSMBProvider fireBlock:block withResult:result];
}];
}
- (id)readDataToEndOfFile
{
__block id result = nil;
KxSMBFileImpl *p = self.theImpl;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchSync:^{
result = [p readDataToEndOfFile];
}];
return result;
}
- (void)seekToFileOffset:(off_t)offset
whence:(NSInteger)whence
block:(KxSMBBlock) block
{
NSParameterAssert(block);
KxSMBFileImpl *p = self.theImpl;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchAsync:^{
id result = [p seekToFileOffset:offset whence:whence];
[KxSMBProvider fireBlock:block withResult:result];
}];
}
- (id)seekToFileOffset:(off_t)offset
whence:(NSInteger)whence
{
__block id result = nil;
KxSMBFileImpl *p = self.theImpl;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchSync:^{
result = [p seekToFileOffset:offset whence:whence];
}];
return result;
}
- (void)writeData:(NSData *)data
block:(KxSMBBlock) block
{
NSParameterAssert(block);
KxSMBFileImpl *p = self.theImpl;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchAsync:^{
id result = [p writeData:data];
[KxSMBProvider fireBlock:block withResult:result];
}];
}
- (id)writeData:(NSData *)data
{
__block id result = nil;
KxSMBFileImpl *p = self.theImpl;
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider dispatchSync:^{
result = [p writeData:data];
}];
return result;
}
#pragma mark - internal
- (id) createFile:(BOOL)overwrite
{
return [self.theImpl createFile:overwrite];
}
@end
///////////////////////////////////////////////////////////////////////////////
static void my_smbc_get_auth_data_fn(const char *srv,
const char *shr,
char *workgroup, int wglen,
char *username, int unlen,
char *password, int pwlen)
{
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
KxSMBAuth *auth = nil;
__strong id<KxSMBProviderDelegate> delegate = provider.delegate;
if (delegate) {
auth = [delegate smbRequestAuthServer:[NSString stringWithUTF8String:srv]
share:[NSString stringWithUTF8String:shr]
workgroup:[NSString stringWithUTF8String:workgroup]
username:[NSString stringWithUTF8String:username]];
}
if (username) {
if (auth.username.length) {
strncpy(username, auth.username.UTF8String, unlen - 1);
} else {
strncpy(username, "guest", unlen - 1);
}
}
if (password) {
if (auth.password.length) {
strncpy(password, auth.password.UTF8String, pwlen - 1);
} else {
password[0] = 0;
}
}
if (workgroup) {
if (auth.workgroup.length) {
strncpy(workgroup, auth.workgroup.UTF8String, wglen - 1);
} else {
workgroup[0] = 0;
}
}
// NSLog(@"smb get auth for %s/%s -> %s/%s:%s", srv, shr, workgroup, username, password);
}
static void my_smbc_get_auth_data_with_context_fn(SMBCCTX *c,
const char *srv,
const char *shr,
char *workgroup, int wglen,
char *username, int unlen,
char *password, int pwlen)
{
void *userdata = smbc_getOptionUserData(c);
if (userdata) {
KxSMBAuth *auth = (__bridge KxSMBAuth *)userdata;
if (username) {
if (auth.username.length) {
strncpy(username, auth.username.UTF8String, unlen - 1);
} else {
strncpy(username, "guest", unlen - 1);
}
}
if (password) {
if (auth.password.length) {
strncpy(password, auth.password.UTF8String, pwlen - 1);
} else {
password[0] = 0;
}
}
if (workgroup) {
if (auth.workgroup.length) {
strncpy(workgroup, auth.workgroup.UTF8String, wglen - 1);
} else {
workgroup[0] = 0;
}
}
} else {
my_smbc_get_auth_data_fn(srv, shr, workgroup, wglen, userdata, unlen, password, pwlen);
}
}
///////////////////////////////////////////////////////////////////////////////
@implementation NSString (KxSMB)
// unfortunately, [NSString stringByAppendingPathComponent] brokes smb:// pathes
// so need to use custom version
- (NSString *) stringByAppendingSMBPathComponent: (NSString *) aString
{
NSString *path = self;
if (![path hasSuffix:@"/"]) {
path = [path stringByAppendingString:@"/"];
}
return [path stringByAppendingString:aString];
}
@end
================================================
FILE: KxSMBSample/AppDelegate.h
================================================
//
// AppDelegate.h
// kxsmb project
// https://github.com/kolyvan/kxsmb/
//
// Created by Kolyvan on 27.03.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
================================================
FILE: KxSMBSample/AppDelegate.m
================================================
//
// AppDelegate.m
// kxsmb project
// https://github.com/kolyvan/kxsmb/
//
// Created by Kolyvan on 27.03.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "AppDelegate.h"
#import "TreeViewController.h"
#import "SmbAuthViewController.h"
#import "KxSMBProvider.h"
@interface AppDelegate() <KxSMBProviderDelegate, SmbAuthViewControllerDelegate>
@end
@implementation AppDelegate {
TreeViewController *_headVC;
NSMutableDictionary *_cachedAuths;
SmbAuthViewController *_smbAuthViewController;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_headVC = [[TreeViewController alloc] initAsHeadViewController];
//_headVC.defaultAuth = [KxSMBAuth smbAuthWorkgroup:@"" username:@"guest" password:@""];
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:_headVC];
[self.window makeKeyAndVisible];
_cachedAuths = [NSMutableDictionary dictionary];
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
provider.delegate = self;
provider.config.browseMaxLmbCount = 0;
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
}
#pragma mark - KxSMBProviderDelegate
- (void) presentSmbAuthViewControllerForServer:(NSString *)server
share:(NSString *)share
workgroup:(NSString *)workgroup
username:(NSString *)username
{
if (!_smbAuthViewController) {
_smbAuthViewController = [[SmbAuthViewController alloc] init];
_smbAuthViewController.delegate = self;
_smbAuthViewController.username = @"guest";
}
UINavigationController *nav = (UINavigationController *)self.window.rootViewController;
if (nav.presentedViewController)
return;
_smbAuthViewController.server = server;
_smbAuthViewController.workgroup = workgroup;
_smbAuthViewController.username = username;
UIViewController *vc = [[UINavigationController alloc] initWithRootViewController:_smbAuthViewController];
[nav.topViewController presentViewController:vc
animated:NO
completion:nil];
}
- (void) couldSmbAuthViewController:(SmbAuthViewController *) controller
done:(BOOL) done
{
if (done) {
KxSMBAuth *auth = [KxSMBAuth smbAuthWorkgroup:controller.workgroup
username:controller.username
password:controller.password];
_cachedAuths[controller.server.uppercaseString] = auth;
NSLog(@"store auth %@ -> (%@) %@:%@", controller.server, controller.workgroup, controller.username, controller.password);
}
UINavigationController *nav = (UINavigationController *)self.window.rootViewController;
[nav dismissViewControllerAnimated:YES completion:nil];
[_headVC reloadPath];
}
- (KxSMBAuth *) smbRequestAuthServer:(NSString *)server
share:(NSString *)share
workgroup:(NSString *)workgroup
username:(NSString *)username
{
if ([share isEqualToString:@"IPC$"] ||
[share hasSuffix:@"$"])
{
// return nil;
}
KxSMBAuth *auth = _cachedAuths[server.uppercaseString];
if (auth) {
// NSLog(@"cached auth for %@ -> %@ (%@) %@:%@", server, share, auth.workgroup, auth.username, auth.password);
return auth;
}
NSLog(@"ask auth for %@/%@ (%@)", server, share, workgroup);
dispatch_async(dispatch_get_main_queue(), ^{
[self presentSmbAuthViewControllerForServer:server
share:share
workgroup:workgroup
username:username];
});
return nil;
}
@end
================================================
FILE: KxSMBSample/FileViewController.h
================================================
//
// FileViewController.h
// kxsmb project
// https://github.com/kolyvan/kxsmb/
//
// Created by Kolyvan on 29.03.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
@class KxSMBItemFile;
@interface FileViewController : UIViewController
@property (readwrite, nonatomic, strong) KxSMBItemFile* smbFile;
@end
================================================
FILE: KxSMBSample/FileViewController.m
================================================
//
// FileViewController.m
// kxsmb project
// https://github.com/kolyvan/kxsmb/
//
// Created by Kolyvan on 29.03.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "FileViewController.h"
#import "KxSMBProvider.h"
#import <QuickLook/QuickLook.h>
@interface FileViewController () <QLPreviewControllerDelegate, QLPreviewControllerDataSource>
@end
@implementation FileViewController {
UIView *_container;
UILabel *_nameLabel;
UILabel *_sizeLabel;
UILabel *_modifiedLabel;
UILabel *_createdLabel;
UIButton *_downloadButton;
UIProgressView *_downloadProgress;
UILabel *_downloadLabel;
NSString *_filePath;
NSFileHandle *_fileHandle;
long _downloadedBytes;
NSDate *_timestamp;
}
- (id)init
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
}
return self;
}
- (void) dealloc
{
[self closeFiles];
}
- (void)viewDidLoad
{
[super viewDidLoad];
const CGSize size = self.view.bounds.size;
const CGFloat W = size.width;
_container = [[UIView alloc] initWithFrame:(CGRect){0,0,size}];
_container.autoresizingMask = UIViewAutoresizingNone;
_container.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_container];
_nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, W - 20, 25)];
_nameLabel.font = [UIFont boldSystemFontOfSize:16];
_nameLabel.textColor = [UIColor darkTextColor];
_nameLabel.opaque = NO;
_nameLabel.backgroundColor = [UIColor clearColor];
_nameLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_sizeLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 35, W - 20, 25)];
_sizeLabel.font = [UIFont systemFontOfSize:14];
_sizeLabel.textColor = [UIColor darkTextColor];
_sizeLabel.opaque = NO;
_sizeLabel.backgroundColor = [UIColor clearColor];
_sizeLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_modifiedLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 60, W - 20, 25)];
_modifiedLabel.font = [UIFont systemFontOfSize:14];;
_modifiedLabel.textColor = [UIColor darkTextColor];
_modifiedLabel.opaque = NO;
_modifiedLabel.backgroundColor = [UIColor clearColor];
_modifiedLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_createdLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 85, W - 20, 25)];
_createdLabel.font = [UIFont systemFontOfSize:14];;
_createdLabel.textColor = [UIColor darkTextColor];
_createdLabel.opaque = NO;
_createdLabel.backgroundColor = [UIColor clearColor];
_createdLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_downloadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
_downloadButton.frame = CGRectMake(10, 120, 100, 30);
_downloadButton.titleLabel.font = [UIFont boldSystemFontOfSize:16];
[_downloadButton setTitle:@"Download" forState:UIControlStateNormal];
[_downloadButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[_downloadButton addTarget:self action:@selector(downloadAction) forControlEvents:UIControlEventTouchUpInside];
_downloadLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 150, W - 20, 40)];
_downloadLabel.font = [UIFont systemFontOfSize:14];;
_downloadLabel.textColor = [UIColor darkTextColor];
_downloadLabel.opaque = NO;
_downloadLabel.backgroundColor = [UIColor clearColor];
_downloadLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_downloadLabel.numberOfLines = 2;
_downloadProgress = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
_downloadProgress.frame = CGRectMake(10, 190, W - 20, 30);
_downloadProgress.hidden = YES;
[_container addSubview:_nameLabel];
[_container addSubview:_sizeLabel];
[_container addSubview:_modifiedLabel];
[_container addSubview:_createdLabel];
[_container addSubview:_downloadButton];
[_container addSubview:_downloadLabel];
[_container addSubview:_downloadProgress];
}
- (void) viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
const CGSize size = self.view.bounds.size;
const CGFloat top = [self.topLayoutGuide length];
_container.frame = (CGRect){0, top, size.width, size.height - top};
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
_nameLabel.text = _smbFile.path;
_sizeLabel.text = [NSString stringWithFormat:@"size: %lld", _smbFile.stat.size];
_modifiedLabel.text = [NSString stringWithFormat:@"modified: %@", _smbFile.stat.lastModified];
_createdLabel.text = [NSString stringWithFormat:@"created: %@", _smbFile.stat.creationTime];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
//[self closeFiles];
}
- (void) closeFiles
{
if (_fileHandle) {
[_fileHandle closeFile];
_fileHandle = nil;
}
[_smbFile close];
}
- (void) downloadAction
{
if (!_fileHandle) {
NSString *folder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES) lastObject];
NSString *filename = _smbFile.path.lastPathComponent;
_filePath = [folder stringByAppendingPathComponent:filename];
NSFileManager *fm = [[NSFileManager alloc] init];
if ([fm fileExistsAtPath:_filePath])
[fm removeItemAtPath:_filePath error:nil];
[fm createFileAtPath:_filePath contents:nil attributes:nil];
NSError *error;
_fileHandle = [NSFileHandle fileHandleForWritingToURL:[NSURL fileURLWithPath:_filePath]
error:&error];
if (_fileHandle) {
[_downloadButton setTitle:@"Cancel" forState:UIControlStateNormal];
_downloadLabel.text = @"starting ..";
_downloadedBytes = 0;
_downloadProgress.progress = 0;
_downloadProgress.hidden = NO;
_timestamp = [NSDate date];
[self download];
} else {
_downloadLabel.text = [NSString stringWithFormat:@"failed: %@", error.localizedDescription];
}
} else {
[_downloadButton setTitle:@"Download" forState:UIControlStateNormal];
_downloadLabel.text = @"cancelled";
[self closeFiles];
}
}
-(void) updateDownloadStatus: (id) result
{
if ([result isKindOfClass:[NSError class]]) {
NSError *error = result;
[_downloadButton setTitle:@"Download" forState:UIControlStateNormal];
_downloadLabel.text = [NSString stringWithFormat:@"failed: %@", error.localizedDescription];
_downloadProgress.hidden = YES;
[self closeFiles];
} else if ([result isKindOfClass:[NSData class]]) {
NSData *data = result;
if (data.length == 0) {
[_downloadButton setTitle:@"Download" forState:UIControlStateNormal];
[self closeFiles];
} else {
NSTimeInterval time = -[_timestamp timeIntervalSinceNow];
_downloadedBytes += data.length;
_downloadProgress.progress = (float)_downloadedBytes / (float)_smbFile.stat.size;
CGFloat value;
NSString *unit;
if (_downloadedBytes < 1024) {
value = _downloadedBytes;
unit = @"B";
} else if (_downloadedBytes < 1048576) {
value = _downloadedBytes / 1024.f;
unit = @"KB";
} else {
value = _downloadedBytes / 1048576.f;
unit = @"MB";
}
_downloadLabel.text = [NSString stringWithFormat:@"downloaded %.1f%@ (%.1f%%) %.2f%@s",
value, unit,
_downloadProgress.progress * 100.f,
value / time, unit];
if (_fileHandle) {
[_fileHandle writeData:data];
if(_downloadedBytes == _smbFile.stat.size) {
[self closeFiles];
[_downloadButton setTitle:@"Done" forState:UIControlStateNormal];
_downloadButton.enabled = NO;
if ([QLPreviewController canPreviewItem:[NSURL fileURLWithPath:_filePath]]) {
QLPreviewController *vc = [QLPreviewController new];
vc.delegate = self;
vc.dataSource = self;
[self.navigationController pushViewController:vc animated:YES];
}
} else {
[self download];
}
}
}
} else {
NSAssert(false, @"bugcheck");
}
}
- (void) download
{
__weak __typeof(self) weakSelf = self;
[_smbFile readDataOfLength:1024*1024
block:^(id result)
{
FileViewController *p = weakSelf;
//if (p && p.isViewLoaded && p.view.window) {
if (p) {
[p updateDownloadStatus:result];
}
}];
}
#pragma mark - QLPreviewController
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller
{
return 1;
}
- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
return [NSURL fileURLWithPath:_filePath];
}
@end
================================================
FILE: KxSMBSample/KxSMBSample-Info.plist
================================================
<?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>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>ru.kolyvan.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIFileSharingEnabled</key>
<false/>
</dict>
</plist>
================================================
FILE: KxSMBSample/KxSMBSample-Prefix.pch
================================================
//
// Prefix header for all source files of the 'KxSMBSample' target in the 'KxSMBSample' project
//
#import <Availability.h>
#ifndef __IPHONE_4_0
#warning "This project uses features only available in iOS SDK 4.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif
================================================
FILE: KxSMBSample/SmbAuthViewController.h
================================================
//
// SmbAuthViewController.h
// kxsmb project
// https://github.com/kolyvan/kxsmb/
//
// Created by Kolyvan on 29.03.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
@class SmbAuthViewController;
@protocol SmbAuthViewControllerDelegate
@optional
- (void) couldSmbAuthViewController: (SmbAuthViewController *) controller
done: (BOOL) done;
@end
@interface SmbAuthViewController : UIViewController
@property (readwrite, nonatomic, weak) id delegate;
@property (readwrite, nonatomic, strong) NSString *server;
@property (readwrite, nonatomic, strong) NSString *workgroup;
@property (readwrite, nonatomic, strong) NSString *username;
@property (readwrite, nonatomic, strong) NSString *password;
@end
================================================
FILE: KxSMBSample/SmbAuthViewController.m
================================================
//
// SmbAuthViewController.m
// kxsmb project
// https://github.com/kolyvan/kxsmb/
//
// Created by Kolyvan on 29.03.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "SmbAuthViewController.h"
@interface SmbAuthViewController ()
@end
@implementation SmbAuthViewController {
UIView *_container;
UILabel *_pathLabel;
UITextField *_workgroupField;
UITextField *_usernameField;
UITextField *_passwordField;
}
- (id)init
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
self.title = NSLocalizedString(@"SMB Authorization", nil);
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
const CGSize size = self.view.bounds.size;
const CGFloat W = size.width;
//const CGFloat H = size.height;
_container = [[UIView alloc] initWithFrame:(CGRect){0,0,size}];
_container.autoresizingMask = UIViewAutoresizingNone;
_container.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_container];
_pathLabel = [[UILabel alloc] initWithFrame:CGRectMake(10,10,W-20,30)];
_pathLabel.backgroundColor = [UIColor clearColor];
_pathLabel.textColor = [UIColor darkTextColor];
_pathLabel.font = [UIFont systemFontOfSize:16];
[_container addSubview:_pathLabel];
UILabel *workgroupLabel;
workgroupLabel = [[UILabel alloc] initWithFrame:CGRectMake(10,40,90,30)];
workgroupLabel.backgroundColor = [UIColor clearColor];
workgroupLabel.textColor = [UIColor darkTextColor];
workgroupLabel.font = [UIFont boldSystemFontOfSize:16];
workgroupLabel.text = NSLocalizedString(@"Workgroup", nil);
[_container addSubview:workgroupLabel];
UILabel *usernameLabel;
usernameLabel = [[UILabel alloc] initWithFrame:CGRectMake(10,90,90,30)];
usernameLabel.backgroundColor = [UIColor clearColor];
usernameLabel.textColor = [UIColor darkTextColor];
usernameLabel.font = [UIFont boldSystemFontOfSize:16];
usernameLabel.text = NSLocalizedString(@"Username", nil);
[_container addSubview:usernameLabel];
UILabel *passwordLabel;
passwordLabel = [[UILabel alloc] initWithFrame:CGRectMake(10,140,90,30)];
passwordLabel.backgroundColor = [UIColor clearColor];
passwordLabel.textColor = [UIColor darkTextColor];
passwordLabel.font = [UIFont boldSystemFontOfSize:16];
passwordLabel.text = NSLocalizedString(@"Password", nil);
[_container addSubview:passwordLabel];
_workgroupField = [[UITextField alloc] initWithFrame:CGRectMake(100, 41, W - 110, 30)];
_workgroupField.autocapitalizationType = UITextAutocapitalizationTypeNone;
_workgroupField.autocorrectionType = UITextAutocorrectionTypeNo;
_workgroupField.spellCheckingType = UITextSpellCheckingTypeNo;
_workgroupField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_workgroupField.clearButtonMode = UITextFieldViewModeWhileEditing;
_workgroupField.textColor = [UIColor blueColor];
_workgroupField.font = [UIFont systemFontOfSize:16];
_workgroupField.borderStyle = UITextBorderStyleRoundedRect;
_workgroupField.backgroundColor = [UIColor lightGrayColor];
_workgroupField.returnKeyType = UIReturnKeyNext;
[_workgroupField addTarget:self
action:@selector(textFieldDoneEditing:)
forControlEvents:UIControlEventEditingDidEndOnExit];
[_container addSubview:_workgroupField];
_usernameField = [[UITextField alloc] initWithFrame:CGRectMake(100, 91, W - 110, 30)];
_usernameField.autocapitalizationType = UITextAutocapitalizationTypeNone;
_usernameField.autocorrectionType = UITextAutocorrectionTypeNo;
_usernameField.spellCheckingType = UITextSpellCheckingTypeNo;
_usernameField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_usernameField.clearButtonMode = UITextFieldViewModeWhileEditing;
_usernameField.textColor = [UIColor blueColor];
_usernameField.font = [UIFont systemFontOfSize:16];
_usernameField.borderStyle = UITextBorderStyleRoundedRect;
_usernameField.backgroundColor = [UIColor lightGrayColor];
_usernameField.returnKeyType = UIReturnKeyDone;
[_usernameField addTarget:self
action:@selector(textFieldDoneEditing:)
forControlEvents:UIControlEventEditingDidEndOnExit];
[_container addSubview:_usernameField];
_passwordField = [[UITextField alloc] initWithFrame:CGRectMake(100, 141, W - 110, 30)];
_passwordField.autocapitalizationType = UITextAutocapitalizationTypeNone;
_passwordField.autocorrectionType = UITextAutocorrectionTypeNo;
_passwordField.spellCheckingType = UITextSpellCheckingTypeNo;
_passwordField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_passwordField.clearButtonMode = UITextFieldViewModeWhileEditing;
_passwordField.textColor = [UIColor blueColor];
_passwordField.font = [UIFont systemFontOfSize:16];
_passwordField.borderStyle = UITextBorderStyleRoundedRect;
_passwordField.backgroundColor = [UIColor lightGrayColor];
_passwordField.returnKeyType = UIReturnKeyDone;
_passwordField.secureTextEntry = YES;
[_passwordField addTarget:self
action:@selector(textFieldDoneEditing:)
forControlEvents:UIControlEventEditingDidEndOnExit];
[_container addSubview:_passwordField];
UIBarButtonItem *bbi;
bbi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(doneAction)];
self.navigationItem.rightBarButtonItem = bbi;
bbi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:@selector(cancelAction)];
self.navigationItem.leftBarButtonItem = bbi;
}
- (void) viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
const CGSize size = self.view.bounds.size;
const CGFloat top = [self.topLayoutGuide length];
_container.frame = (CGRect){0, top, size.width, size.height - top};
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
_pathLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Server: %@", nil), _server];
_workgroupField.text = _workgroup;
_usernameField.text = _username;
_passwordField.text = _password;
[_workgroupField becomeFirstResponder];
}
- (void) textFieldDoneEditing: (id) sender
{
}
- (void) cancelAction
{
__strong id p = self.delegate;
if (p && [p respondsToSelector:@selector(couldSmbAuthViewController:done:)])
[p couldSmbAuthViewController:self done:NO];
}
- (void) doneAction
{
_workgroup = _workgroupField.text;
_username = _usernameField.text;
_password = _passwordField.text;
__strong id p = self.delegate;
if (p && [p respondsToSelector:@selector(couldSmbAuthViewController:done:)])
[p couldSmbAuthViewController:self done:YES];
}
@end
================================================
FILE: KxSMBSample/TreeViewController.h
================================================
//
// TreeViewController.h
// kxsmb project
// https://github.com/kolyvan/kxsmb/
//
// Created by Kolyvan on 27.03.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <UIKit/UIKit.h>
@class KxSMBAuth;
@interface TreeViewController : UITableViewController <UIAlertViewDelegate>
- (id)initAsHeadViewController;
- (void) reloadPath;
@property (readwrite, nonatomic, strong) NSString *path;
@property (readwrite, nonatomic, strong) KxSMBAuth *defaultAuth;
@end
================================================
FILE: KxSMBSample/TreeViewController.m
================================================
//
// TreeViewController.m
// kxsmb project
// https://github.com/kolyvan/kxsmb/
//
// Created by Kolyvan on 27.03.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "TreeViewController.h"
#import "FileViewController.h"
#import "KxSMBProvider.h"
@interface TreeViewController () <UITableViewDataSource, UITableViewDelegate>
@end
@implementation TreeViewController {
BOOL _isHeadVC;
NSArray *_items;
BOOL _loading;
BOOL _needNewPath;
UITextField *_newPathField;
}
- (void) setPath:(NSString *)path
{
_path = path;
[self reloadPath];
}
- (id)init
{
self = [super init];
if (self) {
self.title = @"";
_needNewPath = YES;
_isHeadVC = NO;
}
return self;
}
- (id)initAsHeadViewController {
if((self = [self init])) {
_isHeadVC = YES;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if(NSClassFromString(@"UIRefreshControl")) {
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(reloadPath) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
}
if(_isHeadVC) {
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch
target:self
action:@selector(requestNewPath)];
}
self.navigationItem.rightBarButtonItems =
@[
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:@selector(actionMkDir:)],
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self
action:@selector(actionCopyFile:)],
];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.navigationController.childViewControllers.count == 1 && _needNewPath) {
_needNewPath = NO;
[self requestNewPath];
}
}
- (void) reloadPath
{
NSString *path;
if (_path.length) {
path = _path;
self.title = path.lastPathComponent;
} else {
path = @"smb://";
self.title = @"smb://";
}
_items = nil;
[self.tableView reloadData];
[self updateStatus:[NSString stringWithFormat: @"Fetching %@..", path]];
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider fetchAtPath:path
auth:_defaultAuth
block:^(id result)
{
if ([result isKindOfClass:[NSError class]]) {
[self updateStatus:result];
} else {
[self updateStatus:nil];
if ([result isKindOfClass:[NSArray class]]) {
_items = [result copy];
} else if ([result isKindOfClass:[KxSMBItem class]]) {
_items = @[result];
}
[self.tableView reloadData];
}
}];
}
- (void) requestNewPath
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Connect to Host"
message:nil
preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField * textField) {
textField.text = [[NSUserDefaults standardUserDefaults] objectForKey:@"LastServer"] ?: @"smb://";
textField.placeholder = @"smb://";
textField.clearButtonMode = UITextFieldViewModeAlways;
}];
[alert addAction:[UIAlertAction actionWithTitle:@"Go"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action)
{
self.path = alert.textFields[0].text;
[[NSUserDefaults standardUserDefaults] setObject:_newPathField.text forKey:@"LastServer"];
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
}
- (void) updateStatus: (id) status
{
UIFont *font = [UIFont boldSystemFontOfSize:16];
if ([status isKindOfClass:[NSString class]]) {
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
CGSize sz = activityIndicator.frame.size;
const float H = font.lineHeight + sz.height + 10;
const float W = self.tableView.frame.size.width;
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, W, H)];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 5, W, font.lineHeight)];
label.text = status;
label.font = font;
label.textColor = [UIColor grayColor];
label.textAlignment = NSTextAlignmentCenter;
label.opaque = NO;
label.backgroundColor = [UIColor clearColor];
label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[v addSubview:label];
if(![self.refreshControl isRefreshing])
[self.refreshControl beginRefreshing];
self.tableView.tableHeaderView = v;
} else if ([status isKindOfClass:[NSError class]]) {
const float W = self.tableView.frame.size.width;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 5, W, font.lineHeight)];
label.text = ((NSError *)status).localizedDescription;
label.font = font;
label.textColor = [UIColor redColor];
label.textAlignment = NSTextAlignmentCenter;
label.opaque = NO;
label.backgroundColor = [UIColor clearColor];
label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.tableView.tableHeaderView = label;
[self.refreshControl endRefreshing];
} else {
self.tableView.tableHeaderView = nil;
[self.refreshControl endRefreshing];
}
}
- (void) actionCopyFile:(id)sender
{
NSString *name = [NSString stringWithFormat:@"%u.tmp", (unsigned)[NSDate timeIntervalSinceReferenceDate]];
NSString *path = [_path stringByAppendingSMBPathComponent:name];
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
[provider createFileAtPath:path overwrite:YES auth:_defaultAuth block:^(id result) {
if ([result isKindOfClass:[KxSMBItemFile class]]) {
NSData *data = [@"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." dataUsingEncoding:NSUTF8StringEncoding];
KxSMBItemFile *itemFile = result;
[itemFile writeData:data block:^(id result) {
NSLog(@"completed:%@", result);
if (![result isKindOfClass:[NSError class]]) {
[self reloadPath];
}
}];
} else {
NSLog(@"%@", result);
}
}];
}
- (void) actionMkDir:(id)sender
{
NSString *path = [_path stringByAppendingSMBPathComponent:@"NewFolder"];
KxSMBProvider *provider = [KxSMBProvider sharedSmbProvider];
id result = [provider createFolderAtPath:path auth:_defaultAuth];
if ([result isKindOfClass:[KxSMBItemTree class]]) {
NSMutableArray *ma = [_items mutableCopy];
[ma addObject:result];
_items = [ma copy];
[self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:_items.count-1 inSection:0]]
withRowAnimation:UITableViewRowAnimationAutomatic];
} else {
NSLog(@"%@", result);
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:cellIdentifier];
}
KxSMBItem *item = _items[indexPath.row];
cell.textLabel.text = item.path.lastPathComponent;
if ([item isKindOfClass:[KxSMBItemTree class]]) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.detailTextLabel.text = @"";
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%lld", item.stat.size];
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
KxSMBItem *item = _items[indexPath.row];
if ([item isKindOfClass:[KxSMBItemTree class]]) {
TreeViewController *vc = [[TreeViewController alloc] init];
vc.defaultAuth = _defaultAuth;
vc.path = item.path;
[self.navigationController pushViewController:vc animated:YES];
} else if ([item isKindOfClass:[KxSMBItemFile class]]) {
FileViewController *vc = [[FileViewController alloc] init];
vc.smbFile = (KxSMBItemFile *)item;
[self.navigationController pushViewController:vc animated:YES];
}
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
KxSMBItem *item = _items[indexPath.row];
[[KxSMBProvider sharedSmbProvider] removeAtPath:item.path auth:_defaultAuth block:^(id result) {
NSLog(@"completed:%@", result);
if (![result isKindOfClass:[NSError class]]) {
[self reloadPath];
}
}];
}
}
#pragma mark - Alert view delegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if(buttonIndex == 1) {
self.path = _newPathField.text;
[[NSUserDefaults standardUserDefaults] setObject:_newPathField.text forKey:@"LastServer"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
@end
================================================
FILE: KxSMBSample/en.lproj/InfoPlist.strings
================================================
/* Localized versions of Info.plist keys */
================================================
FILE: KxSMBSample/main.m
================================================
//
// main.m
// KxSMBSample
//
// Created by Kolyvan on 30.03.13.
// Copyright (c) 2013 Konstantin Bukreev. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
================================================
FILE: KxSMBSample.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
87085F8D1705D46C009CD258 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085F8C1705D46C009CD258 /* UIKit.framework */; };
87085F8F1705D46C009CD258 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085F8E1705D46C009CD258 /* Foundation.framework */; };
87085F911705D46C009CD258 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085F901705D46C009CD258 /* CoreGraphics.framework */; };
87085F971705D46C009CD258 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 87085F951705D46C009CD258 /* InfoPlist.strings */; };
87085F991705D46C009CD258 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 87085F981705D46C009CD258 /* main.m */; };
87085F9D1705D46C009CD258 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 87085F9C1705D46C009CD258 /* AppDelegate.m */; };
87085F9F1705D46C009CD258 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 87085F9E1705D46C009CD258 /* Default.png */; };
87085FA11705D46C009CD258 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 87085FA01705D46C009CD258 /* Default@2x.png */; };
87085FA31705D46C009CD258 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 87085FA21705D46C009CD258 /* Default-568h@2x.png */; };
87085FB41705D494009CD258 /* KxSMBProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 87085FB31705D494009CD258 /* KxSMBProvider.m */; };
87085FBB1705D4AB009CD258 /* FileViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87085FB61705D4AB009CD258 /* FileViewController.m */; };
87085FBC1705D4AB009CD258 /* SmbAuthViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87085FB81705D4AB009CD258 /* SmbAuthViewController.m */; };
87085FBD1705D4AB009CD258 /* TreeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87085FBA1705D4AB009CD258 /* TreeViewController.m */; };
87085FC41705D4CA009CD258 /* libsmbclient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085FBF1705D4CA009CD258 /* libsmbclient.a */; };
87085FC51705D4CA009CD258 /* libtalloc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085FC11705D4CA009CD258 /* libtalloc.a */; };
87085FC61705D4CA009CD258 /* libtdb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085FC21705D4CA009CD258 /* libtdb.a */; };
87085FC71705D4CA009CD258 /* libwbclient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085FC31705D4CA009CD258 /* libwbclient.a */; };
87085FC91705D4FD009CD258 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085FC81705D4FD009CD258 /* libz.dylib */; };
87085FCB1705D503009CD258 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085FCA1705D503009CD258 /* libiconv.dylib */; };
87085FCD1705D509009CD258 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085FCC1705D509009CD258 /* libresolv.dylib */; };
871CC5751774589C00EDD76D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 87085F8E1705D46C009CD258 /* Foundation.framework */; };
871CC580177458AD00EDD76D /* KxSMBProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 87085FB31705D494009CD258 /* KxSMBProvider.m */; };
EAC6EFEE179A4133005AC807 /* libtevent.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EAC6EFED179A4133005AC807 /* libtevent.a */; };
F992AF0C1BC3D3CC0063A4B3 /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F992AF0B1BC3D3CC0063A4B3 /* QuickLook.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
871CC5721774589C00EDD76D /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/${PRODUCT_NAME}";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
87085F891705D46C009CD258 /* KxSMBSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KxSMBSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
87085F8C1705D46C009CD258 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
87085F8E1705D46C009CD258 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
87085F901705D46C009CD258 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
87085F941705D46C009CD258 /* KxSMBSample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "KxSMBSample-Info.plist"; sourceTree = "<group>"; };
87085F961705D46C009CD258 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
87085F981705D46C009CD258 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
87085F9A1705D46C009CD258 /* KxSMBSample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "KxSMBSample-Prefix.pch"; sourceTree = "<group>"; };
87085F9B1705D46C009CD258 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
87085F9C1705D46C009CD258 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AppDelegate.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
87085F9E1705D46C009CD258 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
87085FA01705D46C009CD258 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = "<group>"; };
87085FA21705D46C009CD258 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
87085FB21705D494009CD258 /* KxSMBProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KxSMBProvider.h; sourceTree = "<group>"; };
87085FB31705D494009CD258 /* KxSMBProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KxSMBProvider.m; sourceTree = "<group>"; };
87085FB51705D4AB009CD258 /* FileViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = FileViewController.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
87085FB61705D4AB009CD258 /* FileViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileViewController.m; sourceTree = "<group>"; };
87085FB71705D4AB009CD258 /* SmbAuthViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmbAuthViewController.h; sourceTree = "<group>"; };
87085FB81705D4AB009CD258 /* SmbAuthViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SmbAuthViewController.m; sourceTree = "<group>"; };
87085FB91705D4AB009CD258 /* TreeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TreeViewController.h; sourceTree = "<group>"; };
87085FBA1705D4AB009CD258 /* TreeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TreeViewController.m; sourceTree = "<group>"; };
87085FBF1705D4CA009CD258 /* libsmbclient.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsmbclient.a; path = libs/libsmbclient.a; sourceTree = "<group>"; };
87085FC01705D4CA009CD258 /* libsmbclient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libsmbclient.h; path = libs/libsmbclient.h; sourceTree = "<group>"; };
87085FC11705D4CA009CD258 /* libtalloc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtalloc.a; path = libs/libtalloc.a; sourceTree = "<group>"; };
87085FC21705D4CA009CD258 /* libtdb.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtdb.a; path = libs/libtdb.a; sourceTree = "<group>"; };
87085FC31705D4CA009CD258 /* libwbclient.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libwbclient.a; path = libs/libwbclient.a; sourceTree = "<group>"; };
87085FC81705D4FD009CD258 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
87085FCA1705D503009CD258 /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = usr/lib/libiconv.dylib; sourceTree = SDKROOT; };
87085FCC1705D509009CD258 /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = usr/lib/libresolv.dylib; sourceTree = SDKROOT; };
871CC5581774489A00EDD76D /* talloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = talloc.h; path = libs/talloc.h; sourceTree = "<group>"; };
871CC5591774491A00EDD76D /* talloc_stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = talloc_stack.h; path = libs/talloc_stack.h; sourceTree = "<group>"; };
871CC5741774589C00EDD76D /* libKxSMB.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libKxSMB.a; sourceTree = BUILT_PRODUCTS_DIR; };
871CC5781774589C00EDD76D /* KxSMB-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "KxSMB-Prefix.pch"; sourceTree = "<group>"; };
EAC6EFED179A4133005AC807 /* libtevent.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtevent.a; path = libs/libtevent.a; sourceTree = "<group>"; };
F992AF0B1BC3D3CC0063A4B3 /* QuickLook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLook.framework; path = System/Library/Frameworks/QuickLook.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
87085F861705D46C009CD258 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F992AF0C1BC3D3CC0063A4B3 /* QuickLook.framework in Frameworks */,
87085FCD1705D509009CD258 /* libresolv.dylib in Frameworks */,
87085FCB1705D503009CD258 /* libiconv.dylib in Frameworks */,
87085FC91705D4FD009CD258 /* libz.dylib in Frameworks */,
87085F8D1705D46C009CD258 /* UIKit.framework in Frameworks */,
87085F8F1705D46C009CD258 /* Foundation.framework in Frameworks */,
87085F911705D46C009CD258 /* CoreGraphics.framework in Frameworks */,
EAC6EFEE179A4133005AC807 /* libtevent.a in Frameworks */,
87085FC41705D4CA009CD258 /* libsmbclient.a in Frameworks */,
87085FC51705D4CA009CD258 /* libtalloc.a in Frameworks */,
87085FC61705D4CA009CD258 /* libtdb.a in Frameworks */,
87085FC71705D4CA009CD258 /* libwbclient.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
871CC5711774589C00EDD76D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
871CC5751774589C00EDD76D /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
87085F801705D46B009CD258 = {
isa = PBXGroup;
children = (
87085FB21705D494009CD258 /* KxSMBProvider.h */,
87085FB31705D494009CD258 /* KxSMBProvider.m */,
87085FBE1705D4BE009CD258 /* libs */,
87085F921705D46C009CD258 /* KxSMBSample */,
871CC5761774589C00EDD76D /* KxSMB */,
87085F8B1705D46C009CD258 /* Frameworks */,
87085F8A1705D46C009CD258 /* Products */,
);
sourceTree = "<group>";
};
87085F8A1705D46C009CD258 /* Products */ = {
isa = PBXGroup;
children = (
87085F891705D46C009CD258 /* KxSMBSample.app */,
871CC5741774589C00EDD76D /* libKxSMB.a */,
);
name = Products;
sourceTree = "<group>";
};
87085F8B1705D46C009CD258 /* Frameworks */ = {
isa = PBXGroup;
children = (
F992AF0B1BC3D3CC0063A4B3 /* QuickLook.framework */,
87085FCC1705D509009CD258 /* libresolv.dylib */,
87085FCA1705D503009CD258 /* libiconv.dylib */,
87085FC81705D4FD009CD258 /* libz.dylib */,
87085F8C1705D46C009CD258 /* UIKit.framework */,
87085F8E1705D46C009CD258 /* Foundation.framework */,
87085F901705D46C009CD258 /* CoreGraphics.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
87085F921705D46C009CD258 /* KxSMBSample */ = {
isa = PBXGroup;
children = (
87085FB51705D4AB009CD258 /* FileViewController.h */,
87085FB61705D4AB009CD258 /* FileViewController.m */,
87085FB71705D4AB009CD258 /* SmbAuthViewController.h */,
87085FB81705D4AB009CD258 /* SmbAuthViewController.m */,
87085FB91705D4AB009CD258 /* TreeViewController.h */,
87085FBA1705D4AB009CD258 /* TreeViewController.m */,
87085F9B1705D46C009CD258 /* AppDelegate.h */,
87085F9C1705D46C009CD258 /* AppDelegate.m */,
87085F931705D46C009CD258 /* Supporting Files */,
);
path = KxSMBSample;
sourceTree = "<group>";
};
87085F931705D46C009CD258 /* Supporting Files */ = {
isa = PBXGroup;
children = (
87085F941705D46C009CD258 /* KxSMBSample-Info.plist */,
87085F951705D46C009CD258 /* InfoPlist.strings */,
87085F981705D46C009CD258 /* main.m */,
87085F9A1705D46C009CD258 /* KxSMBSample-Prefix.pch */,
87085F9E1705D46C009CD258 /* Default.png */,
87085FA01705D46C009CD258 /* Default@2x.png */,
87085FA21705D46C009CD258 /* Default-568h@2x.png */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
87085FBE1705D4BE009CD258 /* libs */ = {
isa = PBXGroup;
children = (
871CC5591774491A00EDD76D /* talloc_stack.h */,
871CC5581774489A00EDD76D /* talloc.h */,
87085FC01705D4CA009CD258 /* libsmbclient.h */,
87085FBF1705D4CA009CD258 /* libsmbclient.a */,
87085FC11705D4CA009CD258 /* libtalloc.a */,
87085FC21705D4CA009CD258 /* libtdb.a */,
87085FC31705D4CA009CD258 /* libwbclient.a */,
EAC6EFED179A4133005AC807 /* libtevent.a */,
);
name = libs;
sourceTree = "<group>";
};
871CC5761774589C00EDD76D /* KxSMB */ = {
isa = PBXGroup;
children = (
871CC5771774589C00EDD76D /* Supporting Files */,
);
path = KxSMB;
sourceTree = "<group>";
};
871CC5771774589C00EDD76D /* Supporting Files */ = {
isa = PBXGroup;
children = (
871CC5781774589C00EDD76D /* KxSMB-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
87085F881705D46C009CD258 /* KxSMBSample */ = {
isa = PBXNativeTarget;
buildConfigurationList = 87085FAF1705D46C009CD258 /* Build configuration list for PBXNativeTarget "KxSMBSample" */;
buildPhases = (
87085F851705D46C009CD258 /* Sources */,
87085F861705D46C009CD258 /* Frameworks */,
87085F871705D46C009CD258 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = KxSMBSample;
productName = KxSMBSample;
productReference = 87085F891705D46C009CD258 /* KxSMBSample.app */;
productType = "com.apple.product-type.application";
};
871CC5731774589C00EDD76D /* KxSMB */ = {
isa = PBXNativeTarget;
buildConfigurationList = 871CC57F1774589C00EDD76D /* Build configuration list for PBXNativeTarget "KxSMB" */;
buildPhases = (
871CC5701774589C00EDD76D /* Sources */,
871CC5711774589C00EDD76D /* Frameworks */,
871CC5721774589C00EDD76D /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = KxSMB;
productName = KxSMB;
productReference = 871CC5741774589C00EDD76D /* libKxSMB.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
87085F811705D46B009CD258 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0460;
ORGANIZATIONNAME = "Konstantin Bukreev";
};
buildConfigurationList = 87085F841705D46B009CD258 /* Build configuration list for PBXProject "KxSMBSample" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 87085F801705D46B009CD258;
productRefGroup = 87085F8A1705D46C009CD258 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
87085F881705D46C009CD258 /* KxSMBSample */,
871CC5731774589C00EDD76D /* KxSMB */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
87085F871705D46C009CD258 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
87085F971705D46C009CD258 /* InfoPlist.strings in Resources */,
87085F9F1705D46C009CD258 /* Default.png in Resources */,
87085FA11705D46C009CD258 /* Default@2x.png in Resources */,
87085FA31705D46C009CD258 /* Default-568h@2x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
87085F851705D46C009CD258 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
87085F991705D46C009CD258 /* main.m in Sources */,
87085F9D1705D46C009CD258 /* AppDelegate.m in Sources */,
87085FB41705D494009CD258 /* KxSMBProvider.m in Sources */,
87085FBB1705D4AB009CD258 /* FileViewController.m in Sources */,
87085FBC1705D4AB009CD258 /* SmbAuthViewController.m in Sources */,
87085FBD1705D4AB009CD258 /* TreeViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
871CC5701774589C00EDD76D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
871CC580177458AD00EDD76D /* KxSMBProvider.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
87085F951705D46C009CD258 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
87085F961705D46C009CD258 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
87085FAD1705D46C009CD258 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
87085FAE1705D46C009CD258 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
87085FB01705D46C009CD258 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "KxSMBSample/KxSMBSample-Prefix.pch";
HEADER_SEARCH_PATHS = "\"$(SRCROOT)/libs\"";
INFOPLIST_FILE = "KxSMBSample/KxSMBSample-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/libs\"",
);
PRODUCT_NAME = "$(TARGET_NAME)";
USER_HEADER_SEARCH_PATHS = "";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
87085FB11705D46C009CD258 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "KxSMBSample/KxSMBSample-Prefix.pch";
HEADER_SEARCH_PATHS = "\"$(SRCROOT)/libs\"";
INFOPLIST_FILE = "KxSMBSample/KxSMBSample-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/libs\"",
);
PRODUCT_NAME = "$(TARGET_NAME)";
USER_HEADER_SEARCH_PATHS = "";
WRAPPER_EXTENSION = app;
};
name = Release;
};
871CC57D1774589C00EDD76D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DSTROOT = /tmp/KxSMB.dst;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "KxSMB/KxSMB-Prefix.pch";
HEADER_SEARCH_PATHS = "\"$(SRCROOT)/libs\"";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
USER_HEADER_SEARCH_PATHS = "\"$(SRCROOT)/libs\"";
};
name = Debug;
};
871CC57E1774589C00EDD76D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DSTROOT = /tmp/KxSMB.dst;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "KxSMB/KxSMB-Prefix.pch";
HEADER_SEARCH_PATHS = "\"$(SRCROOT)/libs\"";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
USER_HEADER_SEARCH_PATHS = "\"$(SRCROOT)/libs\"";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
87085F841705D46B009CD258 /* Build configuration list for PBXProject "KxSMBSample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
87085FAD1705D46C009CD258 /* Debug */,
87085FAE1705D46C009CD258 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
87085FAF1705D46C009CD258 /* Build configuration list for PBXNativeTarget "KxSMBSample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
87085FB01705D46C009CD258 /* Debug */,
87085FB11705D46C009CD258 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
871CC57F1774589C00EDD76D /* Build configuration list for PBXNativeTarget "KxSMB" */ = {
isa = XCConfigurationList;
buildConfigurations = (
871CC57D1774589C00EDD76D /* Debug */,
871CC57E1774589C00EDD76D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 87085F811705D46B009CD258 /* Project object */;
}
================================================
FILE: LICENSE
================================================
Copyright (c) 2013 Konstantin Bukreev. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: Rakefile
================================================
#
# Rakefile
# kxsmb project
# https://github.com/kolyvan/kxsmb/
#
# Created by Kolyvan on 29.03.13.
#
#
# Copyright (c) 2013 Konstantin Bukreev All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# - Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
require "pathname"
require "fileutils"
# utils
def system_or_exit(cmd, stdout = nil)
puts "Executing #{cmd}"
cmd += " >#{stdout}" if stdout
system(cmd) or raise "******** Build failed ********"
end
def copyIfNotExists(file, from, to)
dest = Pathname.new(to)
dest.mkdir unless dest.exist?
unless (dest + file).exist?
source = Pathname.new(from) + file
FileUtils.copy source, dest
p "copy #{source} -> #{dest}"
end
end
def cleanOrMkDir(path)
dest = Pathname.new path
if dest.exist?
FileUtils.rm Dir.glob("#{path}/*.a")
else
dest.mkdir
end
end
def cleanDir(path)
dest = Pathname.new path
if dest.exist?
FileUtils.rm Dir.glob("#{path}/*.a")
end
end
# versions
IOS_MIN_VERSION='8.0'
SAMBA_VERSION='4.0.26'
# samba source
SAMBA_BASE_URL="http://ftp.samba.org/pub/samba/stable/"
#pathes
XCODE_PATH=%x{ /usr/bin/xcode-select --print-path }.delete("\n")
SIM_SDK_PATH=XCODE_PATH + "/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"
IOS_SDK_PATH=XCODE_PATH + "/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
#SAMBA_PATH="samba-#{SAMBA_VERSION}/source3"
SAMBA_FOLDER="samba"
SAMBA_SOURCE_PATH="#{SAMBA_FOLDER}/source3"
EXT_INCLUDE_PATH='tmp/include'
# configure arguments
CF_FLAGS='-pipe -Wno-trigraphs -fpascal-strings -Os -fembed-bitcode -g'
IOS_CF_FLAGS='-ftree-vectorize'
IOS_LD_FLAGS=''
ARM7_CF_FLAGS="-arch armv7 -mcpu=cortex-a8 -mfpu=neon #{IOS_CF_FLAGS} #{CF_FLAGS}"
ARM7_LD_FLAGS="-arch armv7 #{IOS_LD_FLAGS}"
ARM7s_CF_FLAGS="-arch armv7s -mcpu=cortex-a8 -mfpu=neon #{IOS_CF_FLAGS} #{CF_FLAGS}"
ARM7s_LD_FLAGS="-arch armv7s #{IOS_LD_FLAGS}"
ARM64_CF_FLAGS="-arch arm64 -Wno-error=implicit-function-declaration #{IOS_CF_FLAGS} #{CF_FLAGS}"
ARM64_LD_FLAGS="-arch arm64 #{IOS_LD_FLAGS}"
I386_CF_FLAGS="-arch i386 #{CF_FLAGS}"
I386_LD_FLAGS='-arch i386'
X86_64_CF_FLAGS="-arch x86_64 -Wno-error=implicit-function-declaration #{CF_FLAGS}"
X86_64_LD_FLAGS='-arch x86_64'
SMB_ARGS = [
'--prefix=/private',
'--disable-shared',
'--enable-static',
'--without-readline',
'--with-libsmbclient',
'--without-libnetapi',
'--without-libsmbsharemodes',
'--without-cluster-support',
'--without-ldap',
'--disable-swat',
'--disable-cups',
'--disable-iprint',
'libreplace_cv_HAVE_C99_VSNPRINTF=yes',
'samba_cv_CC_NEGATIVE_ENUM_VALUES=yes',
]
SIM_SMB_ARGS = [
'--enable-debug',
'samba_cv_HAVE_FCNTL_LOCK=yes'
]
IOS_SMB_ARGS = [
'ac_cv_header_libunwind_h=no',
'ac_cv_header_execinfo_h=no',
'ac_cv_header_rpcsvc_ypclnt_h=no',
'ac_cv_file__proc_sys_kernel_core_pattern=no',
'ac_cv_func_fdatasync=no',
'libreplace_cv_HAVE_GETADDRINFO=no',
'samba_cv_SYSCONF_SC_NPROCESSORS_ONLN=no',
'samba_cv_big_endian=no',
'samba_cv_little_endian=yes',
]
ARM7_SMB_ARGS = [
'--host=arm-apple-darwin',
]
ARM7s_SMB_ARGS = [
'--host=arm-apple-darwin',
]
ARM64_SMB_ARGS = [
'--host=arm-apple-darwin',
]
I386_SMB_ARGS = [
'--host=i686-apple-darwin',
]
X86_64_SMB_ARGS = [
'--host=x86_64-apple-darwin',
]
# libs
SMB_LIBS = [
'libsmbclient',
'libtalloc',
'libtevent',
'libtdb',
'libwbclient',
]
# functions
def mkArgs(sdkPath, platformArgs, procArgs, cfFlags, ldFlags)
extInclude = Pathname.new(EXT_INCLUDE_PATH).realpath
args = SMB_ARGS + platformArgs + procArgs
ENV['AR']="xcrun ar"
ENV['CC']="xcrun clang"
ENV['CPP']="xcrun clang -E"
ENV['LD']="xcrun ld"
ENV['CFLAGS']="-std=gnu99 -no-cpp-precomp -miphoneos-version-min=#{IOS_MIN_VERSION} -isysroot #{sdkPath} -I#{sdkPath}/usr/include #{cfFlags}"
ENV['CPPFLAGS']="-std=gnu99 -no-cpp-precomp -miphoneos-version-min=#{IOS_MIN_VERSION} -isysroot #{sdkPath} -I#{sdkPath}/usr/include #{cfFlags} -I#{extInclude}"
ENV['LDFLAGS']="-miphoneos-version-min=#{IOS_MIN_VERSION} -isysroot #{sdkPath} -L#{sdkPath}/usr/lib #{ldFlags}"
args.join(' ')
end
def buildArch(arch)
case arch
when 'i386'
args = mkArgs(SIM_SDK_PATH, SIM_SMB_ARGS, I386_SMB_ARGS, I386_CF_FLAGS, I386_LD_FLAGS)
when 'armv7'
args = mkArgs(IOS_SDK_PATH, IOS_SMB_ARGS, ARM7_SMB_ARGS, ARM7_CF_FLAGS, ARM7_LD_FLAGS)
when 'armv7s'
args = mkArgs(IOS_SDK_PATH, IOS_SMB_ARGS, ARM7s_SMB_ARGS, ARM7s_CF_FLAGS, ARM7s_LD_FLAGS)
when 'arm64'
args = mkArgs(IOS_SDK_PATH, IOS_SMB_ARGS, ARM64_SMB_ARGS, ARM64_CF_FLAGS, ARM64_LD_FLAGS)
when 'x86_64'
args = mkArgs(SIM_SDK_PATH, SIM_SMB_ARGS, X86_64_SMB_ARGS, X86_64_CF_FLAGS, X86_64_LD_FLAGS)
else
raise "Build failed: unknown arch: #{arch}"
end
p args
system_or_exit "cd #{SAMBA_SOURCE_PATH}; ./autogen.sh"
system_or_exit "cd #{SAMBA_SOURCE_PATH}; ./configure #{args}"
SMB_LIBS.each do |x|
system_or_exit "cd #{SAMBA_SOURCE_PATH}; make #{x}"
end
dest = Pathname.new("#{SAMBA_SOURCE_PATH}/bin/#{arch}")
cleanOrMkDir(dest)
SMB_LIBS.each do |x|
FileUtils.move Pathname.new("#{SAMBA_SOURCE_PATH}/bin/#{x}.a"), dest
end
system_or_exit "cd #{SAMBA_SOURCE_PATH}; make clean"
end
def checkExtInclude
extInclude = Pathname.new(EXT_INCLUDE_PATH)
extInclude.mkpath unless extInclude.exist?
copyIfNotExists('crt_externs.h', "#{SIM_SDK_PATH}/usr/include/", extInclude.realpath)
end
# tasks
desc "Build smb armv7 libs"
task :build_smb_armv7 do
checkExtInclude
buildArch('armv7')
end
desc "Build smb armv7s libs"
task :build_smb_armv7s do
checkExtInclude
buildArch('armv7s')
end
desc "Build smb arm64 libs"
task :build_smb_arm64 do
checkExtInclude
buildArch('arm64')
end
desc "Build smb i386 libs"
task :build_smb_i386 do
buildArch('i386')
end
desc "Build smb x86_64 libs"
task :build_smb_x86_64 do
buildArch('x86_64')
end
desc "Build smb universal libs (full)"
task :build_smb_universal_full do
dest = Pathname.new("#{SAMBA_SOURCE_PATH}/bin/universal")
dest.mkdir unless dest.exist?
SMB_LIBS.each do |x|
args = "-create -arch armv7 #{SAMBA_SOURCE_PATH}/bin/armv7/#{x}.a -arch armv7s #{SAMBA_SOURCE_PATH}/bin/armv7s/#{x}.a -arch arm64 #{SAMBA_SOURCE_PATH}/bin/arm64/#{x}.a -arch i386 #{SAMBA_SOURCE_PATH}/bin/i386/#{x}.a -arch x86_64 #{SAMBA_SOURCE_PATH}/bin/x86_64/#{x}.a -output #{dest}/#{x}.a"
system_or_exit "xcrun lipo #{args}"
end
end
desc "Build smb universal libs"
task :build_smb_universal do
dest = Pathname.new("#{SAMBA_SOURCE_PATH}/bin/universal")
dest.mkdir unless dest.exist?
SMB_LIBS.each do |x|
args = "-create -arch armv7 #{SAMBA_SOURCE_PATH}/bin/armv7/#{x}.a -arch arm64 #{SAMBA_SOURCE_PATH}/bin/arm64/#{x}.a -arch i386 #{SAMBA_SOURCE_PATH}/bin/i386/#{x}.a -arch x86_64 #{SAMBA_SOURCE_PATH}/bin/x86_64/#{x}.a -output #{dest}/#{x}.a"
system_or_exit "xcrun lipo #{args}"
end
end
desc "Copy smb headers"
task :copy_headers do
copyIfNotExists('libsmbclient.h', "#{SAMBA_SOURCE_PATH}/include/", 'libs')
copyIfNotExists('talloc.h', "#{SAMBA_FOLDER}/lib/talloc/", 'libs')
copyIfNotExists('talloc_stack.h', "#{SAMBA_FOLDER}/lib/util/", 'libs')
end
desc "Copy smb libs"
task :copy_libs do
dest = Pathname.new('libs')
dest.mkdir unless dest.exist?
from = Pathname.new("#{SAMBA_SOURCE_PATH}/bin/universal")
SMB_LIBS.each do |x|
source = from + "#{x}.a"
FileUtils.move source, dest
p "copy #{source} -> #{dest}"
end
end
desc "Clean"
task :clean do
cleanDir("#{SAMBA_SOURCE_PATH}/bin/armv7")
cleanDir("#{SAMBA_SOURCE_PATH}/bin/armv7s")
cleanDir("#{SAMBA_SOURCE_PATH}/bin/arm64")
cleanDir("#{SAMBA_SOURCE_PATH}/bin/i386")
cleanDir("#{SAMBA_SOURCE_PATH}/bin/x86_64")
cleanDir("#{SAMBA_SOURCE_PATH}/bin/universal")
system_or_exit "cd #{SAMBA_SOURCE_PATH}; make clean"
end
desc "Retrieve samble archive"
task :retrieve_samba do
p = Pathname.new "#{SAMBA_SOURCE_PATH}"
unless p.exist?
name = "samba-#{SAMBA_VERSION}"
file = "#{name}.tar.gz"
url = "#{SAMBA_BASE_URL}#{file}"
p "retrieving samba from #{url}"
system_or_exit "/usr/bin/curl -L --output #{file} #{url}"
p "extracting samba from archive"
system_or_exit "tar -zxf #{file}"
Pathname.new(file).delete
Pathname.new(name).rename SAMBA_FOLDER
end
end
task :build_full => [:retrieve_samba, :build_smb_armv7, :build_smb_armv7s, :build_smb_arm64, :build_smb_i386, :build_smb_x86_64, :build_smb_universal_full, :copy_libs, :copy_headers]
task :build_all => [:retrieve_samba, :build_smb_armv7, :build_smb_arm64, :build_smb_i386, :build_smb_x86_64, :build_smb_universal, :copy_libs, :copy_headers]
task :default => [:build_all]
================================================
FILE: readme.md
================================================
KxSMB is objective-c wrapper for libsmbclient lib.
===========================================
For now KxSMB supports a limited set of SMB operations.
It mostly was designed for browsing local net and retrieving files.
### Build instructions:
First you need download, configure and build [samba](http://www.samba.org).
For this open console and type in
cd kxsmb
rake
### Usage
1. Drop files from kxsmb/libs folder in your project.
2. Add libs: libz.dylib, libresolv.dylib and liconv.dylib.
Fetching a folder content:
NSArray *items = [[KxSMBProvider sharedSmbProvider] fetchAtPath: @"smb://server/share/"];
Reading a file:
KxSMBItemFile *file = [[KxSMBProvider sharedSmbProvider] fetchAtPath: @"smb://server/share/file"];
NSData *data = [file readDataToEndOfFile];
Look at kxSMBSample demo project as example of using.
### Requirements
at least iOS 5.0 and Xcode 4.5.0
### License
kxsmb is open source and covered by a standard 2-clause BSD license. See the LICENSE file for more info.
[Samba](http://www.samba.org) is [Free Software](http://www.gnu.org/philosophy/free-sw.html) licensed under the [GNU General Public License](http://www.samba.org/samba/docs/GPL.html).
### Feedback
Tweet me — [@kolyvan_ru](http://twitter.com/kolyvan_ru).
gitextract_3ps15m81/ ├── .gitignore ├── KxSMB/ │ └── KxSMB-Prefix.pch ├── KxSMBProvider.h ├── KxSMBProvider.m ├── KxSMBSample/ │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── FileViewController.h │ ├── FileViewController.m │ ├── KxSMBSample-Info.plist │ ├── KxSMBSample-Prefix.pch │ ├── SmbAuthViewController.h │ ├── SmbAuthViewController.m │ ├── TreeViewController.h │ ├── TreeViewController.m │ ├── en.lproj/ │ │ └── InfoPlist.strings │ └── main.m ├── KxSMBSample.xcodeproj/ │ └── project.pbxproj ├── LICENSE ├── Rakefile └── readme.md
SYMBOL INDEX (2 symbols across 1 files)
FILE: KxSMBProvider.h
type KxSMBError (line 38) | typedef enum {
type KxSMBItemType (line 58) | typedef enum {
Condensed preview — 20 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (187K chars).
[
{
"path": ".gitignore",
"chars": 285,
"preview": "\n## xcode specific\nbuild/*\n*.pbxuser\n*.mode2v3\n*.mode1v3\n*.perspective\n*.perspectivev3\n*~.nib\n\n## ignore private workspa"
},
{
"path": "KxSMB/KxSMB-Prefix.pch",
"chars": 151,
"preview": "//\n// Prefix header for all source files of the 'KxSMB' target in the 'KxSMB' project\n//\n\n#ifdef __OBJC__\n #import <F"
},
{
"path": "KxSMBProvider.h",
"chars": 12404,
"preview": "//\n// KxSambaProvider.h\n// kxsmb project\n// https://github.com/kolyvan/kxsmb/\n//\n// Created by Kolyvan on 28.03.13.\n"
},
{
"path": "KxSMBProvider.m",
"chars": 81104,
"preview": "//\n// KxSambaProvider.m\n// kxsmb project\n// https://github.com/kolyvan/kxsmb/\n//\n// Created by Kolyvan on 28.03.13.\n"
},
{
"path": "KxSMBSample/AppDelegate.h",
"chars": 1585,
"preview": "//\n// AppDelegate.h\n// kxsmb project\n// https://github.com/kolyvan/kxsmb/\n//\n// Created by Kolyvan on 27.03.13.\n//\n\n"
},
{
"path": "KxSMBSample/AppDelegate.m",
"chars": 5756,
"preview": "//\n// AppDelegate.m\n// kxsmb project\n// https://github.com/kolyvan/kxsmb/\n//\n// Created by Kolyvan on 27.03.13.\n//\n\n"
},
{
"path": "KxSMBSample/FileViewController.h",
"chars": 1617,
"preview": "//\n// FileViewController.h\n// kxsmb project\n// https://github.com/kolyvan/kxsmb/\n//\n// Created by Kolyvan on 29.03.1"
},
{
"path": "KxSMBSample/FileViewController.m",
"chars": 11421,
"preview": "//\n// FileViewController.m\n// kxsmb project\n// https://github.com/kolyvan/kxsmb/\n//\n// Created by Kolyvan on 29.03.1"
},
{
"path": "KxSMBSample/KxSMBSample-Info.plist",
"chars": 1500,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "KxSMBSample/KxSMBSample-Prefix.pch",
"chars": 325,
"preview": "//\n// Prefix header for all source files of the 'KxSMBSample' target in the 'KxSMBSample' project\n//\n\n#import <Availabil"
},
{
"path": "KxSMBSample/SmbAuthViewController.h",
"chars": 2041,
"preview": "//\n// SmbAuthViewController.h\n// kxsmb project\n// https://github.com/kolyvan/kxsmb/\n//\n// Created by Kolyvan on 29.0"
},
{
"path": "KxSMBSample/SmbAuthViewController.m",
"chars": 8476,
"preview": "//\n// SmbAuthViewController.m\n// kxsmb project\n// https://github.com/kolyvan/kxsmb/\n//\n// Created by Kolyvan on 29.0"
},
{
"path": "KxSMBSample/TreeViewController.h",
"chars": 1751,
"preview": "//\n// TreeViewController.h\n// kxsmb project\n// https://github.com/kolyvan/kxsmb/\n//\n// Created by Kolyvan on 27.03.1"
},
{
"path": "KxSMBSample/TreeViewController.m",
"chars": 13537,
"preview": "//\n// TreeViewController.m\n// kxsmb project\n// https://github.com/kolyvan/kxsmb/\n//\n// Created by Kolyvan on 27.03.1"
},
{
"path": "KxSMBSample/en.lproj/InfoPlist.strings",
"chars": 45,
"preview": "/* Localized versions of Info.plist keys */\n\n"
},
{
"path": "KxSMBSample/main.m",
"chars": 344,
"preview": "//\n// main.m\n// KxSMBSample\n//\n// Created by Kolyvan on 30.03.13.\n// Copyright (c) 2013 Konstantin Bukreev. All righ"
},
{
"path": "KxSMBSample.xcodeproj/project.pbxproj",
"chars": 24191,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "LICENSE",
"chars": 1298,
"preview": "Copyright (c) 2013 Konstantin Bukreev. All rights reserved.\n\nRedistribution and use in source and binary forms, with or "
},
{
"path": "Rakefile",
"chars": 9696,
"preview": "# \n# Rakefile\n# kxsmb project\n# https://github.com/kolyvan/kxsmb/\n#\n# Created by Kolyvan on 29.03.13.\n#\n\n#\n# Copyright ("
},
{
"path": "readme.md",
"chars": 1265,
"preview": "KxSMB is objective-c wrapper for libsmbclient lib. \n===========================================\n\nFor now KxSMB supports "
}
]
About this extraction
This page contains the full source code of the kolyvan/kxsmb GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 20 files (174.6 KB), approximately 43.7k tokens, and a symbol index with 2 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.