如何像 Finder 一样回收不属于当前用户的项目?

How to Trash items that are not owned by the current user, the same way the Finder does?

我正在编写一个工具,提供将所选项目(文件、文件夹)丢弃的选项。通常,我会为这些项目中的每一项调用 -[NSFileManager trashItemAtURL:...],因为它也在 and in SO 问题中进行了解释。

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

我已经尝试通过使用特权助手来解决这个问题,如 EvenBetterAuthorizationSample 示例代码所述,使用 launchdSMJobBless 和 XPC 服务。

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

我该如何解决这个问题,即 我如何将不属于该用户的项目移动到当前用户的回收站而不是 root 用户的回收站?

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

我自己进行移动不会正常工作,因为要使 Put Back 工作,垃圾桶的 .DS_Store 文件需要更新,并且没有 API 为此,据我所知。

几乎找到了解决方案:

分析

当助手是 运行 时,例如来自 launchd,或通过 AuthorizationExecuteWithPrivileges(在 macOS 10.15 下),它可能 运行ning 作为 root,不知道 logged-in 用户,因此它无法确定用户的垃圾文件夹。

奇怪的是,环境变量(参见 man env)甚至可能显示当前用户的名称和主目录,但真实用户 ID,可以用getuid(), 将 return 0 (root), 这也会导致 NSUserName()NSHomeDirectory() returning root 用户的信息。 trashItemAtURL 和相关函数似乎依赖于 NSHomeDirectory() 来确定回收站文件夹的位置。

Half-working解决方案

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

因此,在我的测试中,当我调用 setreuid (501, 0)(501 是当前 logged-in 用户的 uid)时,trashItemAtURL 确实将文件移动到用户的回收站文件夹,确实,以及必要时的自动重命名。

但是,这 不会 使 Put Back 起作用,就像使用 Finder 删除同一个文件时那样。

让 Put Back 发挥作用

看起来 Put Back 不起作用的原因来自更深层次的问题:它似乎是 macOS 框架中的一个 long-standing 错误,请参阅 this bug report.

这基本上意味着:在 Apple 修复底层错误之前,这是我们能摆脱的最好结果。

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