Hi all,

I’m having trouble with security-scoped bookmarks in a sandboxed app.

I have an object which has a URL as a property, being a folder the user chooses 
to save stuff to. This object is persistent, due to NSCoding. When I archive 
the URL, I use a security-scoped bookmark to save the data. When I dearchive, I 
resolve the security-scoped bookmark to recover the folder URL. Before I start 
to write files to this folder, I use the -startAccessingSecurityScopedResource, 
and when I’m done writing the files, I balance that with a call to 
-stopAccessingSecurityScopedResource. The app has the necessary entitlements 
for user selected files, and for app-scope bookmarks.

The problem reveals itself only over a series of launches, which cause the 
object above to be archived and dearchived.

Launch 1:

Normal. The user chooses a new Folder using the sandboxed NSOpenPanel. Files 
are written to this folder normally.

Launch 2:

The archived bookmark data is resolved and the URL is restored. Access to the 
resource appears to be normal (returns YES) and the files are written. Shortly 
afterwards the following is written to the console:

2016-09-07 13:34:48.052 MyApp[8602:1574205] CFStringRef 
__CFPasteboardIssueSandboxExtensionForPath(CFStringRef) : sandbox extension 
creation failed: client lacks entitlements? for path: 
[/Users/grahamcox/Desktop/Exports/Snorkel0001-16.jpg]
2016-09-07 13:34:48.052 MyApp[8602:1574205] CFDataRef 
__CFPasteboardCreateSandboxExtensionDataFromCFData(CFDataRef) : failed to 
obtain sandbox extension data for url 
[file:///Users/grahamcox/Desktop/Exports/Snorkel0001-16.jpg]

It’s not clear where this message is being posted from - my code has finished 
writing the files (successfully) and has called 
-stopAccessingSecurityScopedResource before this is emitted. The URL in the 
message is the file I’ve written, and the folder that contains it is the one 
the user chose previously. I do appear to have the necessary entitlements:

com.apple.security.files.bookmarks.app-scope YES
com.apple.security.files.user-selected.read-write YES

Once this has occurred, when the object is archived, the method 
-bookmarkDataWithOptions:… fails, with the error:

Error Domain=NSCocoaErrorDomain Code=256 "Could not open() the item" 
UserInfo={NSURL=file:///Users/grahamcox/Desktop/Exports/, 
NSDebugDescription=Could not open() the item}

If this occurs, my code skips the saving of the bookmark data, which is nil 
anyway. That leaves the archive without an entry for the URL.


Launch 3:

Because there’s no bookmark data, on dearchiving the URL is reverted to a 
default one that is within the user’s ‘Documents’ folder, which the app can 
write to. The call to -startAccessingSecurityScopedResource with this default 
URL returns NO, but files are written normally without any problems. The 
default URL is obtained by:

        NSURL* docFolder = [[NSFileManager defaultManager] 
URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask 
appropriateForURL:nil create:YES error:&error];

And then appending a default subfolder to it (and creating it if necessary). 
This URL subsequently gets archived as a security-scoped bookmark as normal. 
Subsequent launches with this folder URL work fine.


So the issue seems to be with the state in Launch 2, that, despite appearing to 
work, spits out some console messages from somewhere, and then fails to create 
the bookmark data. AFAICS, I’m using all the correct APIs and option flags.

The code:

- (instancetype) initWithCoder:(NSCoder*) aDecoder
{
        self = [super init];
        if( self )
        {
                //[other dearchived properties omitted for brevity]

                NSData* bookmark = [aDecoder 
decodeObjectForKey:@"Exp_folderBookmark"];
                NSError* error = nil;
                BOOL stale = NO;
                
                self.folderURL = [NSURL URLByResolvingBookmarkData:bookmark 
options:NSURLBookmarkResolutionWithoutUI | 
NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil 
bookmarkDataIsStale:&stale error:&error];
                
                if( self.folderURL )
                {
                        if( stale )
                        {
                                bookmark = [self.folderURL 
bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope 
includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
                        }
                }
                else
                {
                        NSLog(@"saved URL could not be resolved, restoring to 
default ~/Documents/<app name>/Exported Files/ error=%@", error );
                        
                        self.folderURL = [MDABExportController 
defaultExportLocation];
                }
        }
        
        return self;
}


- (void)        encodeWithCoder:(NSCoder*) aCoder
{
        //[other archived properties omitted for brevity]

        NSError* error = nil;
        NSData* bookmark = [self.folderURL 
bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope 
includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
        
        if( bookmark )
                [aCoder encodeObject:bookmark forKey:@"Exp_folderBookmark"];
        else
        {
                NSLog(@"unable to archive URL bookmark data for Export 
operation, error=%@", error);
        }
}


This kind of thing has always worked for me in the past, so I’m not sure why 
this particular case is giving me these problems.

Can anyone suggest anything I’ve overlooked?

—Graham






_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to