首页 > 解决方案 > 如何像 Finder 一样丢弃当前用户不拥有的项目?

问题描述

我正在编写一个工具,它提供了删除选定项目(文件、文件夹)的选项。通常,我会要求-[NSFileManager trashItemAtURL:...]这些项目中的每一个,因为它也在thisthis SO question 中进行了解释。

但是,当尝试从其他用户(例如 root )拥有的目录中删除文件时,这些方法不起作用。在这种情况下,我的工具应提供与 Finder 相同的选项,即要求用户通过提供管理员用户的凭据来授权操作,然后我的应用程序会像 Finder 一样将项目移动到垃圾箱。

我已经尝试通过使用特权助手来解决这个问题,如EvenBetterAuthorizationSample示例代码中的概述,使用launchdSMJobBlessXPC 服务。

然而,问题在于,特权助手以 root 用户身份运行,而不知道我的应用程序在其下运行的当前用户。结果是,当它删除一个文件时,它最终会出现在 root 用户的 Trash 文件夹中,而不是像 Finder 那样在用户的 Trash 文件夹中。

我该如何解决这个问题,即如何将不属于用户的项目移动到当前用户的垃圾箱而不是根用户的垃圾箱?

有什么技巧可以让我继续使用现有的垃圾回收功能之一吗?

自己做这个动作不会正常工作,因为要让 Put Back.DS_Store正常工作,需要更新垃圾箱的文件,而且没有 API 来做这件事,AFAIK。

标签: macosfilesystemsnsfilemanagernsworkspace

解决方案


几乎找到了解决方案:

分析

当帮助程序运行时,例如 fromlaunchd或 via AuthorizationExecuteWithPrivileges(在 macOS 10.15 下),它可能以 root 身份运行,不知道登录用户,因此它无法确定用户的垃圾文件夹。

奇怪的是,环境变量(请参阅 参考资料man env)甚至可以显示当前用户的名称和主目录,但可以使用 查询的真实用户 idgetuid()将返回 0(root),这也会导致NSUserName()NSHomeDirectory()返回 root 用户的信息。而且看起来trashItemAtURL和相关的功能依赖于NSHomeDirectory()确定垃圾箱文件夹的位置。

半成品解决方案

幸运的是,有一种方法可以更改真实的用户 id,使用setreuid.

因此,在我的测试中,当我调用setreuid (501, 0)(501 是当前登录用户的 uid)时,trashItemAtURL确实会将文件移动到用户的垃圾箱文件夹,并在必要时自动重命名。

但是,这不会像使用 Finder 删除同一文件时那样使“放回”工作。

使放回工作

看起来Put Back不起作用的原因来自更深层次的问题:它似乎是 macOS 框架中长期存在的错误,请参阅此错误报告

这基本上意味着:在 Apple 修复潜在错误之前,这是我们能从中得到的最好的结果。

使Put Back工作的唯一可行替代方法是要求 Finder 使用 AppleEvents / AppleScript 删除项目。


推荐阅读