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.
Related
I want to move a file from a folder to another folder
I used
[[NSFileManager defaultManager]moveItemAtPath:#"Folder/Filename.fileExtension" toPath:#"FolderToMoveTheFile" error:nil];
Is there something else to type in error: ?
Why it isn't move my file?
You would get the error by doing this:
NSError* error;
if (![[NSFileManager defaultManager]moveItemAtPath:#"Folder/Filename.fileExtension" toPath:#"FolderToMoveTheFile" error:&error])
{
// handle error, typically using the NSError object pointed to by the error variable
// In an app, you might want to pass it to a -presentError:... method of a convenient responder
// This is good enough for debugging:
NSLog(#"failed to move file: %#", error);
}
The second path that goes after toPath: must be the path including the file name at the destination. It is not correct to just specify the path to the directory into which you want to move the file.
Also, you should typically use absolute paths, not relative paths. You can use relative paths but that then depends on the current working directory for the process. That's arbitrary for apps launched from the Finder or Dock. It's really only meaningful for command-line tools launched from a shell (e.g. a Terminal window) where the user might be expected to cd to a directory and then provide relative paths as command-line arguments.
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.
I need to share information from a plist with someone who is not technically inclined. Is there a common free editor that one can use to view plist info in a similar way in which it is presented in Xcode? Or is there a way to print it out?
In other words I would like to view the plist without all the xml-like mark up and without the use of Xcode.
Command-line options for viewing Plist files:
For viewing only: Use plutil -p, which prints the content of a property-list in JSON-like format (the format is meant for human consumption only).
Example (append | open -tf to view output in a text editor):
plutil -p ~/Library/Preferences/com.apple.sidebarlists.plist
Alternative: Use /usr/libexec/PlistBuddy -c print, which outputs in JavaScript-object-literal-like format:
Example:
/usr/libexec/PlistBuddy -c print ~/Library/Preferences/com.apple.airplay.plist
Caveat:
If the plist has properties containing binary data, PlistBuddy will include it in raw form (by contrast, non-binary properties in the same file are printed properly). If XML output is desired, add option -x.
Note that PlistBuddy:
can be used to extract properties selectively using :-separated, case-sensitive property paths; e.g., /usr/libexec/PlistBuddy -c 'print :favorites:ShowRemovable' ~/Library/Preferences/com.apple.sidebarlists.plist
is also capable of modifying Plist files from the command line (including, with limitations, importing from previously exported-to XML files).
See /usr/libexec/PlistBuddy -h for details.
The standalone "Property List Editor" is gone since Xcode 4, you can use Pref Setter which is free but last updated 4 years ago.
To save the contents without the xml tags see this example:
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:[#"~/Library/Preferences/loginwindow.plist" stringByExpandingTildeInPath]];
[[dict description] writeToURL:[NSURL fileURLWithPath:[#"~/Desktop/loginwindow.txt" stringByExpandingTildeInPath]] atomically:YES encoding:NSUTF8StringEncoding error:nil];
You can use visual studio code to open and edit Plist files.
Just need to install an extension in the visual studio code called Binary Plist:
Binary Plist
Publisher: David Nicolson
Marketplace Link: https://marketplace.visualstudio.com/items?itemName=dnicolson.binary-plist
There is a way to get the old Property List Editor working on Mac OS X Lion, if you don't want to use bloated XCode 4 for this.
There is a "Property List Editor" app as part of OS X (or there used to be, I'm away from my machine at the moment so can't check).
Failing that, you could write one in about half an hour!
My program pulls in a C style string from a file, converts it to an NSString and places it in an NSMutableArray. Every time I run the program, either Debug or Release version, in XCode it runs perfectly. However every time I run it outside of XCode it crashes and the report says "-[NSPlaceholderString initWithString:]: nil argument'". This is the line of code where the problem occurs.
input = [[[NSString alloc] initWithString:[NSString stringWithUTF8String:data->acctNames]] mutableCopy];
I have also tried this:
input = [NSString stringWithUTF8String:data->acctNames];
Can anyone explain what is wrong with this?
Sounds like the file you are opening doesn't exist and the string is not being initialized. You should look at the file path and see if it is an absolute path. Maybe you are trying to open the file in a local directory and the file doesn't exist in the run directory after you have built the binary.
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];