OS X 沙盒中的非就地保存
Posted
技术标签:
【中文标题】OS X 沙盒中的非就地保存【英文标题】:Non in-place saving in OS X sandbox 【发布时间】:2011-11-26 16:53:27 【问题描述】:我正在为 Mac OS X 10.7 开发一个沙盒应用程序,我正在尝试以类似于 NSDocument
的方式实现文件保存:
-
将文件的新内容重写为临时文件
用临时文件覆盖原始文件
我遇到的问题是沙盒拒绝第 2 步。我在控制台中看到以下行:
sandboxd: XXXX deny file-write-create /Volumes/Home/sbooth/Test Files/Test
我已经打开此文件进行读写,并且我启用了文件系统读/写访问权限。我知道 NSDocument 这样做没有特殊权利,所以我试图找出我错过了什么。
这是我现在的工作方式(应用程序的这一部分是 C++,而不是 Objective-C/C++):
FSRef tempFileFSRef;
if(noErr != FSPathMakeRef((const UInt8 *)tempFileName, &tempFileFSRef, NULL))
; // Handle it
CFURLRef destinationDirURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mURL);
FSRef destinationDirFSRef;
if(!CFURLGetFSRef(destinationDirURL, &destinationDirFSRef))
; // Handle it
CFRelease(destinationDirURL), destinationDirURL = NULL;
CFStringRef destinationName = CFURLCopyLastPathComponent(mURL);
FSRef target;
OSStatus result = FSCopyObjectSync(&tempFileFSRef, &destinationDirFSRef, destinationName, &target, kFSFileOperationOverwrite | kFSFileOperationSkipSourcePermissionErrors);
if(noErr != result)
; // Handle it
如果我禁用沙盒,代码可以正常工作。
编辑:Femi 要求提供更多信息。我使用 C stdio 打开文件:
FILE *f = fopen(reinterpret_cast<const char *>(buf), "r");
并在创建临时文件之前使用fclose
关闭。
我的权利是:
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.assets.music.read-write</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
还值得注意的是,Apple 在其App Sandbox Design Guide 中表示:
如果您使用除 NSDocument 类,你必须转换为使用这个类。 NSDocument 类自动与 Powerbox 一起使用。 NSDocument 还提供 如果用户移动,支持将文档保留在沙箱中 他们使用 Finder。
【问题讨论】:
除了控制台中的沙盒行,FSCopyObjectSync
是否返回错误?
它确实返回一个错误:-54 | permErr
这也不足为奇,但 FSMoveObjectSync 表现出相同的行为
好奇:你能在你打开原始文件的地方包含代码吗?以及您要求的权利?
IIRC 沙箱跟踪用户在沙箱中选择的文件...在关闭文件后和打开写入之前再次尝试通过对话框选择文件...跨度>
【参考方案1】:
沙盒仅允许您从应用程序的容器中读取和写入。如果您启用了读/写权利,那么您只能访问通过 OpenSavePanel 打开的文件(或某些方法,例如将图标拖到用户专门打开文件的 Dock 上)。这将严重限制应用程序处理文件系统上文件的方式。
因此,只要您的应用程序有权改写相关文档,您就可以将临时文件写入应用程序容器,然后检索临时文件内容,然后保存到原始位置。但是,这假设您的应用在整个过程中保持对原始文件的权限。
因此,我的建议是确保您所做的任何写入都在应用程序容器中完成,然后在调用保存函数之前验证您的应用程序仍然有权写入真实文件位置。
我最近写了一个类似的问题,其中我的应用程序无法访问已打开的文件,因为另一个(非沙盒)应用程序保存到同一文件。然后沙盒授予该应用访问我的文档的权限,并从该应用中删除了权限。
【讨论】:
我可能遗漏了一条重要信息:原始文件是由用户通过打开对话框选择的。使用这种方法,内容将被复制,而不是移动临时文件。这否定了简单地移动文件而不是复制文件的好处(我不想使用原子这个词)。 不幸的是,您必须绕过沙盒的规则。由于您的代码试图访问它有权限之外的文件系统,因此在沙盒权利处于活动状态时这是不可能的。 我了解沙盒规则,但我认为我并没有真正打破它们。原始文件由用户(通过 powerbox)选择,临时文件在适当的临时目录中创建,作为对 save 命令的响应。本质上,我试图在不使用 NSDocument 的情况下复制 NSDocument 的保存行为,因为我不需要它的全部功能。我认为 Yahia 击中了头部 - 当我close
文件时,它可能已从 powerbox 的允许文件列表中删除。
是的,我认为从允许文件列表中删除该文件是正确的。但是,如果您正在关闭文档,然后在关闭文档后尝试保存,那么您实际上违反了规则。
我听到你所说的违反规则。不过我知道NSDocument
有这种行为,所以一定有办法。以上是关于OS X 沙盒中的非就地保存的主要内容,如果未能解决你的问题,请参考以下文章
沙盒中的 OAuthPermissionsException Instagram API
沙盒中的经典 API NVP、经典 ASP DoDirectPayment
Storekit - 仅限生产环境 - SKProduct 本地化标题和本地化描述是不是仅依赖于沙盒中的 iTunes Store 位置?