Renaming a mounted disc image - cocoa

The "source" below is a mounted disc image (dmg), named "New." I'm trying to rename it with a textField string and action. When I complete the action the rename fails and I am unable to eject it. The code works with standard files and folders.
Also - if I do a "Get Info" of the mounted disc image and rename it there, everything works fine.
Bottom line is I want to rename a mounted disc image using a textField string. Can someone explain?
NSString *source = [#"~/Desktop/New" stringByExpandingTildeInPath];
NSString *newFile = [input stringValue];
NSString *newPath = [[source stringByDeletingLastPathComponent] stringByAppendingPathComponent:newFile];
[[NSFileManager defaultManager] moveItemAtPath:source toPath:newPath error:NULL];
NSLog(#"File renamed to %#", newFile);

You'll need to use the disk arbitration framework.

Related

Letting macOS sandboxed apps write file created by my non-sandboxed app

I have a macOS/Objective-C/Cocoa application. We want to spawn external applications, like TextEdit, to edit files created by this app. I'm creating these files by copying it into my ~/Documents directory (eventually I'd like to put it elsewhere, but I'm trying to simplify) with:
NSFileManager *defaultManager = [NSFileManager defaultManager];
[defaultManager copyItemAtPath:srcPath toPath:destPath error:&err];
NSDate *sourceModified = [self lastModificationOfFile:srcPath];
NSDictionary * attr = #{ NSFileModificationDate : sourceModified,
NSFileImmutable : [NSNumber numberWithBool:NO],
NSFilePosixPermissions : [NSNumber numberWithUnsignedLong:0666],
};
[defaultManager setAttributes:attr ofItemAtPath:destPath error:nil];
When I open this file in TextEdit, the window header says "filename.txt - Locked". Editing the document gives me the "Are you sure you want to modify the document in place?" dialog. I select "Overwrite", but then attempts to save give me "The document "filename.txt" could not be saved. You don't have permission."
However, this writes a "filename.txt.sb-a69dcdc5-7V6D2g" (or similarly named) file into my Documents directory. And files created from the bash shell with "echo blablabla > filename.txt" in that same directory open just fine.
I have tried many variations on those attributes. I cannot see any difference between the files which work and those which display "... - Locked" using "ls -la# filename.txt" or "xattr", even side-by-side in the same directory.
Clearly I'm up against some sandboxing issue with the files I create, but all of my search results are about the other side of this problem.
Argh. I found this: Why does TextEdit open HTML files as locked. Apparently because of the content of my .txt file, TextEdit was interpreting it as an HTML document and treating it differently based on that. Replaced the content of the file with things that didn't look like HTML and I'm able to edit the document now.

NSFileManager's currentDirectoryPath returns root directory when .app is run at Desktop

I'm developing a basic web service, and am working on the login screen. When the user presses the "login" button, I want it to activate a NSTask that runs a binary which is bundled with the application (which performs the login with the given credentials). Right now, I get the working directory, and append the relative location of the binary to the working directory to run it. The binary runs fine when I just place the binary in a static location on my computer, but I would prefer to bundle the binary in the app's resources instead (unless this is a bad idea).
The gist of my code is available here.
Where is the best place to put a binary in the XCode project directory, so that I can bundle it in the folder "X.app/Contents"?
Currently, I am just getting the current working directory, and then appending the relative location of the binaries to this string. The following code is contained in an override of the - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil method:
NSFileManager *filemgr = [[NSFileManager alloc] init];
self.pathString = [[NSString alloc] initWithString:filemgr.currentDirectoryPath];
I launch the task with the following code (wrapped in a method in a subclassed NSViewController):
NSString *launchPath = [self.pathString stringByAppendingString:#"/X.app/Contents/Resources/loginFromClient"];
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: launchPath];
NSArray *arguments;
arguments = [NSArray arrayWithObjects:username, nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
This works when the application is run in the Debug folder.
HOWEVER, when I try to move it to a different location (ie, copying the X.app to Desktop), the filemgr reports that the currentDirectoryPath is the root directory ("/").
This brings me to two questions:
Why is the NSFileManager reporting that the current directory is "/", when it should be "/Users/stevenschmatz/Desktop/X.app"?
Is there any way just to refer to a subdirectory in the .app folder directly, so you can run a binary regardless of the app's location without finding the working directory at all?
Thank you in advance!
The currentDirectoryPath is dependent on the launch environment and has nothing to do with the location of your application.
To get data inside your app bundle, look at [NSBundle mainBundle]. An equivalent to your code above would be:
NSString *launchPath=[NSBundle.mainBundle
pathForResource:#"loginFromClient"
ofType:nil
];

Copy files to and from Application Support

I deal a lot with Lotus Notes in my company. I wrote a great application in C# to copy specific files to and from the user's Lotus Notes directory. Now I am wanting to write that application for OSX in Objective C. I have a handful of different files that need to be copied from ~/Library/Application Support/Lotus Notes Data/.
I am running into admin issues when I run a test to copy a single file. What is the best/easiest way(I am a beginner) to prompt the user for admin credentials and execute the file copy code with the newly acquired rights?
I did try implementing the BLAuthentication Class I found online, but it would not compile. I currently don't have access to my work computer to post the code.
Try like this below:-
NSString *path=[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)lastObject];
NSString *testUrl =[path stringByAppendingPathComponent:#"/LotusNotesData/source.rtf"];
//
if ([[NSFileManager defaultManager]fileExistsAtPath:testUrl]) {
NSLog(#"yes");
}
//Below destination is folder name which should be exist on your machine or else you can create programmatically as well
NSString *testUrl2 = #"/Users/home/Documents/destination";
NSLog(#"%#",testUrl);
NSLog(#"%#",testUrl2);
NSError *err=nil;
//Now we are copying the souce path to destination folder with appending file name (it can be any your name becuase file manager copy source file contents to your destination file contents)
//Here given file name is a source.rtf where you can give any your name. Also this is for copying source contents to destination contents
NSFileManager *fm=[NSFileManager defaultManager];
if ([fm copyItemAtPath:testUrl toPath:[testUrl2 stringByAppendingPathComponent:#"source.rtf"] error:&err])
{
NSLog(#"success");
}
else
{
NSLog(#"%#",[err localizedDescription]);
}
Use Apple Script to copy files with privilege access.
do shell script "cp source_path destination_path" with administrator privileges
where source path is path of file to be copied.
You may call the Apple script by adding a ".scpt" file with above script in your bundle and using code below:
- (void) runEmbeddedScriptFile: (NSString*)fileName
{
NSString* path = [[NSBundle bundleForClass:[self class]] pathForResource:fileName ofType:#"scpt"];
NSURL* url = [NSURL fileURLWithPath:path];
NSDictionary* errors = [NSDictionary dictionary];
NSAppleScript* appleScript = [[NSAppleScript alloc] initWithContentsOfURL:url error:&errors];
[appleScript executeAndReturnError:nil];
[appleScript release];
}

Enumerating over a directory gives me an error when I try to follow aliases

I want my users to be able to drop a folder into my OSX app. I then look at all the files in the directory and its subdirectories. That works fine but not when there is an alias in the directory. The alias is resolved correctly (Thanks to Matt Gallagher, shame on you Apple) but the enumerator does not allow me to do enumerate the target directory (it just returns no elements and the error below). Here is some sample code:
-(void)enumDirAtPath:(NSString*)path {
NSString* file_enum = nil;
NSDirectoryEnumerator* enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path];
while (file_enum = [enumerator nextObject])
{
NSString* file = [[NSString stringWithFormat:#"%#/%#",path,file_enum] stringByResolvingSymlinksAndAliases];
BOOL isDirectory = NO;
[[NSFileManager defaultManager] fileExistsAtPath:file isDirectory: &isDirectory];
if (!isDirectory) {
NSLog(#"Adding file: %#",file);
} else {
NSLog(#"Found dir: %#",file);
[self enumDirAtPath: file];
}
}
}
the same code with enumeratorAtURL:includingPropertiesForKeys:options:errorHandler: gives me this error:
error: Error Domain=NSCocoaErrorDomain Code=257 "The file “Musik”
couldn’t be opened because you don’t have permission to view it."
UserInfo=0x1094cf670
{NSURL=file://localhost/Users/david/Desktop/Musik,
NSFilePath=/Users/david/Desktop/Musik, NSUnderlyingError=0x1094d43f0
"The operation couldn’t be completed. Operation not permitted"}
Even If I just dispatch_async the recursive call it won't let me do it. Is there any way I can just iterate over a directory and get all the content?
Note: I am fully aware that this could result in infinite loops. This code is just to illustrate the problem.
I‘m pretty damn sure the answer is right there in the error message:
The file “Musik” couldn’t be opened because you don’t have permission to view it.
Reveal the destination of the alias in the Finder application and check its permission via “Get Info” or ls -l# in the Terminal — I’d bet that your user account david is not being granted one of the following permissions:
read
execute
list
The last one will typically not be visible on the command line except in combination with an explicit deny-access-control-entry.

Cocoa - Open File Package in Finder

I am trying to open the Finder in a certain package.
I got this file, Example.backup, which is just a folder with an extension. In the finder, you can right click it (Show Package Contents) and I will be presented with the files. (there is no Contents folder).
I've tried opening it with NSWorkspace's methods but none open the finder at that directory, they either select the file or open it with the associated program.
Is there a way to do this in AppleScript maybe? Or Cocoa?
Thanks
Since no one answered yet, there might not be a one line solution.
All I could think of was a workaround: call /usr/bin/open with the -R option, which will reveal the given file in Finder. Since you want to show the contents of the package, you will have to reveal any file that is inside (not the package itself).
Downsides: won't work on empty package (but then you could just reveal the package), also the Finder window will show a selection on the last item.
NSString *pathToBundle = #"/tmp/test.app";
NSFileManager *fm = [[[NSFileManager alloc] init] autorelease];
// get the last file/directory in the package
// TODO: error handling / empty package
NSString *lastItemInBundle = [[fm contentsOfDirectoryAtPath:pathToBundle error:NULL] lastObject];
// reveal this file in Finder, by using /usr/bin/open
// see -R option in the manpage
NSTask *open = [[[NSTask alloc] init] autorelease];
[open setLaunchPath:#"/usr/bin/open"];
[open setCurrentDirectoryPath:pathToBundle];
[open setArguments:[NSArray arrayWithObjects:#"-R", lastItemInBundle, nil]];
[open launch];

Resources