mirror of https://github.com/perkeep/perkeep.git
235 lines
7.4 KiB
Objective-C
235 lines
7.4 KiB
Objective-C
/*
|
|
Copyright 2013 The Perkeep Authors
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
#import <Foundation/NSFileManager.h>
|
|
|
|
#import "FUSEManager.h"
|
|
|
|
@implementation FUSEManager
|
|
|
|
- (BOOL) isMounted
|
|
{
|
|
return mounted;
|
|
}
|
|
|
|
- (void)justMounted
|
|
{
|
|
mounted = YES;
|
|
[delegate fuseMounted];
|
|
[mountMenu setState:NSOnState];
|
|
}
|
|
|
|
- (void)justUnmounted
|
|
{
|
|
mounted = NO;
|
|
[delegate fuseDismounted];
|
|
[mountMenu setState:NSOffState];
|
|
}
|
|
|
|
- (NSString*) mountPath
|
|
{
|
|
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES );
|
|
return [NSString stringWithFormat: @"%@/perkeep", [paths objectAtIndex:0]];
|
|
}
|
|
|
|
- (void) mount
|
|
{
|
|
shouldBeMounted = YES;
|
|
|
|
in = [[NSPipe alloc] init];
|
|
out = [[NSPipe alloc] init];
|
|
task = [[NSTask alloc] init];
|
|
|
|
startTime = time(NULL);
|
|
|
|
NSMutableString *launchPath = [NSMutableString string];
|
|
[launchPath appendString:[[NSBundle mainBundle] resourcePath]];
|
|
[task setCurrentDirectoryPath:launchPath];
|
|
|
|
[launchPath appendString:@"/pk-mount"];
|
|
|
|
NSString *mountDir = [self mountPath];
|
|
[[NSFileManager defaultManager] createDirectoryAtPath:mountDir
|
|
withIntermediateDirectories:YES
|
|
attributes:nil
|
|
error:nil];
|
|
|
|
NSDictionary *env = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
NSHomeDirectory(), @"HOME",
|
|
NSUserName(), @"USER",
|
|
@"/bin:/usr/bin:/sbin:/usr/sbin", @"PATH",
|
|
nil, nil];
|
|
[task setEnvironment:env];
|
|
|
|
NSLog(@"Launching '%@'\n", launchPath);
|
|
[task setLaunchPath:launchPath];
|
|
[task setArguments:[NSArray arrayWithObjects:@"-open", [self mountPath], nil]];
|
|
[task setStandardInput:in];
|
|
[task setStandardOutput:out];
|
|
[task setStandardError:out];
|
|
|
|
NSFileHandle *fh = [out fileHandleForReading];
|
|
NSNotificationCenter *nc;
|
|
nc = [NSNotificationCenter defaultCenter];
|
|
|
|
[nc addObserver:self
|
|
selector:@selector(dataReady:)
|
|
name:NSFileHandleReadCompletionNotification
|
|
object:fh];
|
|
|
|
[nc addObserver:self
|
|
selector:@selector(taskTerminated:)
|
|
name:NSTaskDidTerminateNotification
|
|
object:task];
|
|
|
|
[task launch];
|
|
[fh readInBackgroundAndNotify];
|
|
NSLog(@"Launched server task -- pid = %d", task.processIdentifier);
|
|
|
|
[self justMounted];
|
|
}
|
|
|
|
- (void)dataReady:(NSNotification *)n
|
|
{
|
|
NSData *d;
|
|
d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
|
|
if ([d length]) {
|
|
NSString *s = [[NSString alloc] initWithData: d
|
|
encoding: NSUTF8StringEncoding];
|
|
NSLog(@"%@", s);
|
|
}
|
|
if (task) {
|
|
[[out fileHandleForReading] readInBackgroundAndNotify];
|
|
}
|
|
}
|
|
|
|
- (void)cleanup
|
|
{
|
|
task = nil;
|
|
|
|
in = nil;
|
|
out = nil;
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
}
|
|
|
|
- (BOOL)hasFUSE
|
|
{
|
|
return [[NSFileManager defaultManager] fileExistsAtPath:@"/Library/Filesystems/osxfusefs.fs"];
|
|
}
|
|
|
|
- (BOOL)hasClientConfig
|
|
{
|
|
NSString *confFile = [NSString stringWithFormat:@"%@/.config/perkeep/client-config.json", NSHomeDirectory()];
|
|
return [[NSFileManager defaultManager] fileExistsAtPath:confFile];
|
|
}
|
|
|
|
- (void)createClientConfig
|
|
{
|
|
NSTask *put = [[NSTask alloc] init];
|
|
|
|
NSMutableString *launchPath = [NSMutableString string];
|
|
[launchPath appendString:[[NSBundle mainBundle] resourcePath]];
|
|
[put setCurrentDirectoryPath:launchPath];
|
|
[launchPath appendString:@"/pk-put"];
|
|
NSDictionary *env = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
NSHomeDirectory(), @"HOME",
|
|
NSUserName(), @"USER",
|
|
@"/bin:/usr/bin:/sbin:/usr/sbin", @"PATH",
|
|
nil, nil];
|
|
[put setEnvironment:env];
|
|
[put setLaunchPath:launchPath];
|
|
[put setArguments:[NSArray arrayWithObjects:@"init", nil]];
|
|
[put launch];
|
|
[put waitUntilExit];
|
|
}
|
|
|
|
// If YES is returned, try to remount, otherwise stop
|
|
- (BOOL)resolveMountProblemAndRemount
|
|
{
|
|
time_t now = time(NULL);
|
|
if (now - startTime < MIN_FUSE_LIFETIME) {
|
|
// See if we can guide the user to a solution
|
|
if (![self hasFUSE]) {
|
|
NSRunAlertPanel(@"Problem Mounting Perkeep FUSE",
|
|
@"You don't seem to have osxfuse installed. "
|
|
@"Please go here, install, and try again:\n\n"
|
|
@"http://osxfuse.github.io/", @"OK", nil, nil);
|
|
return NO;
|
|
} else if (![self hasClientConfig]) {
|
|
NSInteger b = NSRunAlertPanel(@"Problem Mounting Perkeep FUSE",
|
|
@"You don't have a camlistore client config. "
|
|
@"Would you like me to make you one?",
|
|
@"Make Client Config", @"Don't Mount", nil);
|
|
if (b == NSAlertDefaultReturn) {
|
|
[self createClientConfig];
|
|
} else {
|
|
return NO;
|
|
}
|
|
} else {
|
|
NSInteger b = NSRunAlertPanel(@"Problem Mounting Perkeep FUSE",
|
|
@"I'm having trouble mounting the FUSE filesystem. "
|
|
@"Check Console logs for more details.",
|
|
@"Retry", @"Don't Mount", nil);
|
|
return b == NSAlertDefaultReturn;
|
|
}
|
|
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
- (void)taskTerminated:(NSNotification *)note
|
|
{
|
|
int status = [[note object] terminationStatus];
|
|
NSLog(@"Task terminated with status %d", status);
|
|
[self cleanup];
|
|
[self justUnmounted];
|
|
NSLog(@"Terminated with status %d\n", status);
|
|
|
|
if (shouldBeMounted) {
|
|
// Relaunch the server task...
|
|
if ([self resolveMountProblemAndRemount]) {
|
|
NSLog(@"Remounting");
|
|
[NSTimer scheduledTimerWithTimeInterval:1.0
|
|
target:self selector:@selector(mount)
|
|
userInfo:nil
|
|
repeats:NO];
|
|
} else {
|
|
NSLog(@"Should no longer be mounted");
|
|
shouldBeMounted = NO;
|
|
}
|
|
}
|
|
if (!shouldBeMounted) {
|
|
[[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation
|
|
source:[[self mountPath] stringByDeletingLastPathComponent]
|
|
destination:@""
|
|
files:[NSArray arrayWithObject:[[self mountPath] lastPathComponent]]
|
|
tag:nil];
|
|
}
|
|
}
|
|
|
|
- (void) dismount
|
|
{
|
|
NSLog(@"Unmounting");
|
|
shouldBeMounted = NO;
|
|
NSFileHandle *writer;
|
|
writer = [in fileHandleForWriting];
|
|
[writer writeData:[@"q\n" dataUsingEncoding:NSASCIIStringEncoding]];
|
|
[writer closeFile];
|
|
}
|
|
|
|
@end
|