12

I have a security scope bookmark for a directory, provided by a user via an openDialog request.

I'm trying to create another security scope bookmark for a file inside this directory:

NSURL *musicFolder = /* Secured URL Resolved from a NSData, bookmark not stale */;

if (![musicFolder startAccessingSecurityScopedResource]) {
    NSLog(@"Error accessing bookmark.");
}

NSString *file = @"myfile.txt"; /* This file exists inside the directory */
NSURL *pathURL = [musicFolder URLByAppendingPathComponent:file];

NSError *systemError;
NSData *bookmarkData = [pathURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                         includingResourceValuesForKeys:nil
                                          relativeToURL:nil
                                                  error:&systemError];

[musicFolder stopAccessingSecurityScopedResource];

if (!bookmarkData) {
    NSLog(@"%@", systemError);
}

Both bookmarkData and systemError end up nil which is not very useful...

Is this even supported or can you only get valid secured scope bookmarks from the system?

Didier Malenfant
  • 729
  • 1
  • 10
  • 25

3 Answers3

6

In my test program this works fine. I suspect the append of the file name to the URL is failing in your case (but that's a huge guess) because it's the only thing that seems materially different.

I notice that the url for a security resolved location is: file://localhost/Users/dad/Desktop/TestFolder?applesecurityscope=343335323030663066393432306234363030346263613464636464643130663635353065373030373b30303030303030303b303030303030303030303030303032303b636f6d2e6170706c652e6170702d73616e64626f782e726561642d77726974653b30303030303030313b30313030303030323b303030303030303030326461363838663b2f75736572732f74796c65722f6465736b746f702f74657374666f6c646572

which is the other reason I wonder if the append is the issue.

In my test I have the user choose the folder, create the security scoped bookmark and then save that in user defaults.

Then I quit & relaunch the app and via a menu command I get that bookmark and then resolve it. Then I added a case where I use the resolved bookmark to a folder and make a new bookmark to the file within the folder.

It seems to work fine.


In my test where it's working I'm getting the path to the file like this:

NSURL * resolvedURL = [NSURL URLByResolvingBookmarkData: data
                        options: NSURLBookmarkResolutionWithSecurityScope
                        relativeToURL: nil
                        bookmarkDataIsStale: &isStale
                        error: &error];
... // (error checking)

[resolvedURL startAccessingSecurityScopedResource];

NSArray * files = [[NSFileManager defaultManager] 
                     contentsOfDirectoryAtURL: resolvedURL
                     includingPropertiesForKeys: @[NSURLLocalizedNameKey, NSURLCreationDateKey]
                     options:  NSDirectoryEnumerationSkipsHiddenFiles
                     error: &error];
if ( files != nil )
{
    NSURL * fileURL = [files objectAtIndex: 0]; // hard coded for my quick test
    NSData * newData = [fileURL bookmarkDataWithOptions: NSURLBookmarkCreationWithSecurityScope
                          includingResourceValuesForKeys: nil
                          relativeToURL: nil
                          error: &error];

   if ( newData != nil )
   {
       NSLog(@"it's good!");
   }
   .... // error checking and logging.

if that doesn't get you on the right track, I'm going to need to see more code (you'll probably need to make a simple example).

Note that in my case I'm resolving the bookmark and calling startAccessingSecurityScopedResource even when I just got the url & created the bookmark (when I tried to create a bookmark from the path I'd just acquired from PowerBox (openPanel) it failed with an error 256).

Some configuration details: OS X 10.8.4, Xcode 5 (first public release from today 9/18/2013).

Dad
  • 6,388
  • 2
  • 28
  • 34
  • I plugged in similar code as yours, the file manager can read the directory and gives me an array of all the files in it. When I try to create a bookmark on the first file, I get an error 256. I have the `startAccessingSecurityScopedResource` on the directory URL before I start accessing it. – Didier Malenfant Sep 19 '13 at 17:20
  • Let me see if I can narrow it down to a simple example and still get it to fail or not, rule out any other factor in my code. – Didier Malenfant Sep 19 '13 at 17:26
  • 1
    Found the issue but not the solution. The issue is that the file it's trying to make a bookmark to is locked. If the file is unlocked it works fine. Not sure why this would affect it but it seems like it does. – Didier Malenfant Sep 19 '13 at 18:09
  • interesting. I got the 256 error at one point and it had to do with not resolving the folder bookmark and then startAccessing… it before using the resolved url to create the file bookmark. – Dad Sep 20 '13 at 00:30
  • I can confirm that creating a security bookmark to a locked file fails and an unlocked on succeeds. This should probably be reported as a bug since I one can get read-only access to a locked file which might be all the app needs (BBedit can open the locked file fine, for example). – Dad Sep 20 '13 at 00:34
  • It does seem like a bug. I only need read access so I hope this is indeed fixable. Will file a bug on radar.Thanks! – Didier Malenfant Sep 20 '13 at 03:54
  • sure thing! Interesting problem. – Dad Sep 21 '13 at 07:06
  • Hey fellas did you figure this out? I have a similar issue, but simply trying to confirm if the path is writable, would you have any thoughts on that? http://stackoverflow.com/q/35307603/458356 – Ian Bytchek Feb 10 '16 at 05:48
4

For creating bookmarks for locked files, use NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess flag combined with NSURLBookmarkCreationWithSecurityScope flag in API call for creating bookmark.

For example:

NSURL* fileURL = [NSURL fileURLWithPath:filePath];
NSError* error = NULL;

NSData* bookmarkData = [fileURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope|NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess includingResourceValuesForKeys:nil relativeToURL:nil error:&error];

I have tried this in Mac OS 10.9.5

technophile
  • 141
  • 2
2

Following up after reporting the problem with security-scoped bookmarks and locked-files, this is the reply from Apple:

"Also, as you've noticed, creating a security-scoped bookmark requires write access to the target file. That should no longer be the case in OS X Mavericks."

Which would indicate that it is a bug in version of OS X pre-10.9.

Didier Malenfant
  • 729
  • 1
  • 10
  • 25
  • I do need to, in Mavericks, create the bookmark with "write" permission. Otherwise, when the bookmark becomes stale, the app can't recreate the bookmark to point to the current locations – billibala Oct 08 '14 at 10:57
  • AFAIK bookmarks don't store permissions so there shouldn't be a specific 'write permissions' one. If the bookmark goes stale, it's because something happened to the file that was being bookmarked. Either it got deleted or overwritten. You are correct that there is no way to recreate a bookmark in that case but that is by design. The file it pointed to is gone. – Didier Malenfant Oct 08 '14 at 16:42