mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-03-23 01:09:42 +01:00
Add mac FileHelpers
This commit is contained in:
parent
27eb1b51f1
commit
8aae86cf16
40
src/libtomahawk/mac/FileHelpers.h
Normal file
40
src/libtomahawk/mac/FileHelpers.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2012, Leo Franchi <lfranchi@kde.org
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MAC_FILE_HELPERS_H
|
||||
#define MAC_FILE_HELPERS_H
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// Implement this delegate protocol to get notified about the result of your copy attempt
|
||||
@interface NSObject (SUInstallerDelegateInformalProtocol)
|
||||
- (void)moveFinished;
|
||||
- (void)moveFailedWithError:(NSError *)error;
|
||||
@end
|
||||
|
||||
@interface FileHelpers : NSObject
|
||||
{}
|
||||
// Move a file from point A to point B, asking for authentication if necessary
|
||||
// Will be asynchronous: Implement the delegate protocol know about the completion
|
||||
+ (void) moveFile:(NSString *)source to:(NSString*)dest withDelegate:delegate;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
226
src/libtomahawk/mac/FileHelpers.mm
Normal file
226
src/libtomahawk/mac/FileHelpers.mm
Normal file
@ -0,0 +1,226 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2012, Leo Franchi <lfranchi@kde.org
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import "FileHelpers.h"
|
||||
|
||||
#import <CoreServices/CoreServices.h>
|
||||
#import <Security/Security.h>
|
||||
#import <sys/stat.h>
|
||||
#import <sys/wait.h>
|
||||
#import <dirent.h>
|
||||
#import <unistd.h>
|
||||
#import <sys/param.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
static NSString * const TKCopySourceKey = @"TKInstallerSourcePath";
|
||||
static NSString * const TKCopyDestinationKey = @"TKInstallerDestinationPath";
|
||||
static NSString * const TKInstallerDelegateKey = @"TKInstallerDelegate";
|
||||
static NSString * const TKInstallerResultKey = @"TKInstallerResult";
|
||||
static NSString * const TKInstallerErrorKey = @"TKInstallerError";
|
||||
|
||||
class CAutoreleasePool
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
|
||||
public:
|
||||
CAutoreleasePool()
|
||||
{
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
~CAutoreleasePool()
|
||||
{
|
||||
[pool drain];
|
||||
}
|
||||
};
|
||||
|
||||
// Authorization code based on generous contribution from Allan Odgaard. Thanks, Allan!
|
||||
static BOOL AuthorizationExecuteWithPrivilegesAndWait(AuthorizationRef authorization, const char* executablePath, AuthorizationFlags options, const char* const* arguments)
|
||||
{
|
||||
// *** MUST BE SAFE TO CALL ON NON-MAIN THREAD!
|
||||
|
||||
sig_t oldSigChildHandler = signal(SIGCHLD, SIG_DFL);
|
||||
BOOL returnValue = YES;
|
||||
|
||||
if (AuthorizationExecuteWithPrivileges(authorization, executablePath, options, (char* const*)arguments, NULL) == errAuthorizationSuccess)
|
||||
{
|
||||
int status;
|
||||
pid_t pid = wait(&status);
|
||||
if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
returnValue = NO;
|
||||
}
|
||||
else
|
||||
returnValue = NO;
|
||||
|
||||
signal(SIGCHLD, oldSigChildHandler);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
@implementation FileHelpers
|
||||
|
||||
+ (void) moveFile:(NSString *)source to:(NSString*)dest withDelegate:delegate
|
||||
{
|
||||
NSLog(@"FileHelpers moving file from %@ to %@", source, dest);
|
||||
|
||||
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:source, TKCopySourceKey, dest, TKCopyDestinationKey, delegate, TKInstallerDelegateKey, nil];
|
||||
[NSThread detachNewThreadSelector:@selector(performMoveWithInfo:) toTarget:self withObject:info];
|
||||
}
|
||||
|
||||
|
||||
+ (void)performMoveWithInfo:(NSDictionary *)info
|
||||
{
|
||||
// *** GETS CALLED ON NON-MAIN THREAD!
|
||||
|
||||
CAutoreleasePool _p;
|
||||
|
||||
NSString* fromPath = [info objectForKey: TKCopySourceKey];
|
||||
NSString* toPath = [info objectForKey: TKCopyDestinationKey];
|
||||
|
||||
AuthorizationRef auth = NULL;
|
||||
OSStatus authStat = errAuthorizationDenied;
|
||||
|
||||
NSLog(@"FileHelpers moving file from %@ to %@", fromPath, toPath);
|
||||
BOOL haveOld = [[NSFileManager defaultManager] fileExistsAtPath: toPath];
|
||||
|
||||
if (haveOld == YES) { // delete the old file if it's there
|
||||
if (0 != access([[toPath stringByDeletingLastPathComponent] fileSystemRepresentation], W_OK)
|
||||
|| 0 != access([[[toPath stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] fileSystemRepresentation], W_OK))
|
||||
{
|
||||
const char* rmParams[] = { [toPath fileSystemRepresentation], NULL };
|
||||
// NSLog( @"WOULD DELETE: %@", [toPath fileSystemRepresentation] );
|
||||
|
||||
while( authStat == errAuthorizationDenied )
|
||||
{
|
||||
authStat = AuthorizationCreate(NULL,
|
||||
kAuthorizationEmptyEnvironment,
|
||||
kAuthorizationFlagDefaults,
|
||||
&auth);
|
||||
}
|
||||
if (authStat == errAuthorizationSuccess)
|
||||
{
|
||||
BOOL res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/bin/rm", kAuthorizationFlagDefaults, rmParams );
|
||||
if (!res)
|
||||
NSLog(@"Could not delete: %@", toPath);
|
||||
} else {
|
||||
qDebug() << "Failed to authenticate to delete file under target to move, aborting";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// We can delete it ourselves w/out authenticating
|
||||
NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
|
||||
NSError* error;
|
||||
BOOL success = [manager removeItemAtPath:toPath error:&error];
|
||||
|
||||
if (!success) {
|
||||
NSLog(@"Failed to delete file (w/out perms) underneath copy!: %@", [[error userInfo] objectForKey: NSLocalizedDescriptionKey]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FSRef dstRef, dstDirRef;
|
||||
OSStatus err = FSPathMakeRefWithOptions((UInt8 *)[toPath fileSystemRepresentation], kFSPathMakeRefDoNotFollowLeafSymlink, &dstRef, NULL);
|
||||
|
||||
if (err != noErr && err != fnfErr) { // If the file is not found that's fine, we're moving to there after all
|
||||
qDebug() << "GOT AN ERROR DOING FSPathMakeRefWithOptions!!!!! aborting move";
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 != access([[toPath stringByDeletingLastPathComponent] fileSystemRepresentation], W_OK)
|
||||
|| 0 != access([[[toPath stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] fileSystemRepresentation], W_OK))
|
||||
{
|
||||
// Not writeable by user, so authenticate
|
||||
if (!auth) {
|
||||
while( authStat == errAuthorizationDenied )
|
||||
{
|
||||
authStat = AuthorizationCreate(NULL,
|
||||
kAuthorizationEmptyEnvironment,
|
||||
kAuthorizationFlagDefaults,
|
||||
&auth);
|
||||
}
|
||||
}
|
||||
|
||||
if (authStat == errAuthorizationSuccess)
|
||||
{
|
||||
// Fix perms before moving so we have them correct when they arrive
|
||||
struct stat dstSB;
|
||||
stat([[toPath stringByDeletingLastPathComponent] fileSystemRepresentation], &dstSB);
|
||||
char uidgid[42];
|
||||
snprintf(uidgid, sizeof(uidgid), "%d:%d",
|
||||
dstSB.st_uid, dstSB.st_gid);
|
||||
|
||||
const char* coParams[] = { "-R", uidgid, [fromPath fileSystemRepresentation], NULL };
|
||||
BOOL res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/usr/sbin/chown", kAuthorizationFlagDefaults, coParams );
|
||||
if( !res )
|
||||
qDebug() << "Failed to set permissions before moving";
|
||||
|
||||
// Do the move
|
||||
const char* mvParams[] = { "-f", [fromPath fileSystemRepresentation], [toPath fileSystemRepresentation], NULL };
|
||||
res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/bin/mv", kAuthorizationFlagDefaults, mvParams );
|
||||
if( !res )
|
||||
NSLog(@"Failed to move source file from %@ to %@ with error %@", fromPath, toPath, res );
|
||||
|
||||
AuthorizationFree(auth, 0);
|
||||
auth = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
AuthorizationFree(auth, 0);
|
||||
auth = NULL;
|
||||
}
|
||||
|
||||
err = FSPathMakeRef((UInt8 *)[[toPath stringByDeletingLastPathComponent] fileSystemRepresentation], &dstDirRef, NULL);
|
||||
|
||||
if (err != noErr) {
|
||||
qDebug() << "GOT AN ERROR DOING FSPathMakeRef to get dir to copy into!!!!! aborting move";
|
||||
return;
|
||||
}
|
||||
|
||||
NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
|
||||
NSError* error;
|
||||
BOOL success = [manager moveItemAtPath:fromPath toPath:toPath error:&error];
|
||||
if (!success) {
|
||||
NSLog( @"Failed to do non-authenticated move! Help! %@", [[error userInfo] objectForKey: NSLocalizedDescriptionKey] );
|
||||
}
|
||||
[self notifyDelegate:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:success], TKInstallerResultKey, [info objectForKey:TKInstallerDelegateKey], TKInstallerDelegateKey, error, TKInstallerErrorKey, nil]];
|
||||
}
|
||||
|
||||
|
||||
+ (void)notifyDelegate:(NSDictionary *)info
|
||||
{
|
||||
// *** GETS CALLED ON NON-MAIN THREAD!
|
||||
BOOL result = [[info objectForKey:TKInstallerResultKey] boolValue];
|
||||
if (result)
|
||||
{
|
||||
if ([[info objectForKey:TKInstallerDelegateKey] respondsToSelector:@selector(moveFinished)])
|
||||
[[info objectForKey:TKInstallerDelegateKey] performSelectorOnMainThread: @selector(moveFinished) withObject:nil waitUntilDone: NO];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([[info objectForKey:TKInstallerDelegateKey] respondsToSelector:@selector(moveFailedWithError:)])
|
||||
{
|
||||
[[info objectForKey:TKInstallerDelegateKey] performSelectorOnMainThread: @selector(moveFailedWithError) withObject:[NSDictionary dictionaryWithObjectsAndKeys:[info objectForKey:TKInstallerErrorKey], TKInstallerErrorKey, nil] waitUntilDone: NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
Loading…
x
Reference in New Issue
Block a user