如何像 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
示例代码所述,使用 launchd
、SMJobBless
和 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 删除项目。
我正在编写一个工具,提供将所选项目(文件、文件夹)丢弃的选项。通常,我会为这些项目中的每一项调用 -[NSFileManager trashItemAtURL:...]
,因为它也在
但是,当尝试从不同用户拥有的目录中删除文件时,这些方法不起作用,例如 root。在这种情况下,我的工具应提供与 Finder 相同的选项,即要求用户通过提供管理员用户的凭据来授权操作,然后我的应用程序将像 Finder 一样将项目移至垃圾箱。
我已经尝试通过使用特权助手来解决这个问题,如 EvenBetterAuthorizationSample
示例代码所述,使用 launchd
、SMJobBless
和 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 删除项目。