【问题标题】:Electron app can't access files on only one network driveElectron 应用程序无法访问仅一个网络驱动器上的文件
【发布时间】:2021-06-24 06:47:32
【问题描述】:

我正在构建一个 Electron 应用程序,用于管理 NAS 上的照片集合。该 NAS 有两个逻辑卷,名为“alpha”和“beta”。由于我想了解(并修复!)的原因,我的应用程序在尝试针对 beta 上的文件运行 CLI 工具时会收到 ENOENT 错误,但在针对 alpha 版运行 CLI 工具时不会。此外, 允许对两个卷上的文件执行常规 FS 操作(例如 readdir、stat 甚至重命名)而不会出错。例如:应用程序首先了解测试版文件,因为它使用find 扫描文件系统;扫描成功。

我正在使用 CLI 工具 exiftool 从所有这些文件(例如尺寸、捕获设备等)中提取图像元数据。这是我的应用运行的命令,使用 child_process.spawn:

# as a shell command
exiftool -json -n PATH_TO_FILE
// as a node module usable by Electron
const ChildProcess = require('child_process')

module.exports = async function readExif( PATH_TO_FILE ) {
    if (typeof PATH_TO_FILE !== 'string') throw new TypeError('PATH_TO_FILE must be a string')

    let exifStdout = await new Promise(( resolve, reject ) => {
        let stdout = ''
        let stderr = ''
        const process = ChildProcess.spawn(
            'exiftool',
            ['-json', '-n', PATH_TO_FILE],
            { uid: 501, gid: 20 }
        )

        process.on('error', ( error ) => reject(error)) // couldn't launch the process
        process.stdout.on('data', ( data ) => stdout += data)
        process.stderr.on('data', ( data ) => stderr += data)
        process.on('close', () => stderr ? reject(stderr) : resolve(stdout))
    })

    let exifData = JSON.parse(exifStdout)

    return exifData[0] // exiftool always returns an array; unwrap it so our return mirrors our input
}

如果我从命令行使用 node 运行它,那么无论目标文件在哪里,它都可以工作。如果 Electron 运行它,它将对 alpha 有效,但对 beta 无效。如果我从 VS Code 内的集成终端运行它,我拒绝了网络文件夹权限,它可以预见地抛出 alpha 和 beta;无论我使用 node 还是 Electron 都是如此,只要它来自 VS Code 内部。

这里是 console.log(error) 作为打包的 Electron 应用程序运行时:

Error: spawn exiftool ENOENT
    at Process.ChildProcess._handle.onexit (internal/child_process.js:264:19)
    at onErrorNT (internal/child_process.js:456:16)
    at processTicksAndRejections (internal/process/task_queues.js:81:21) {
  errno: 'ENOENT',
  code: 'ENOENT',
  syscall: 'spawn exiftool',
  path: 'exiftool',
  spawnargs: [
    '-json',
    '-n',
    '/Volumes/beta/photographs/IMG_9999.jpg'
  ]
}

我已经通过实验验证过的事情:

  • 如果我从命令行逐字运行命令,它会起作用;所以,我的用户可以读取这些文件,exiftool 也可以
  • 将文件从 alpha 移动到 beta(使用 Finder)会导致我的应用程序无法读取它,反之亦然
  • 我的实现很好:如果我使用终端中的节点来运行导入 readExif 的小型 test.js,并手动提供测试版文件的路径,它就可以工作

以上所有让我认为这是一个权限问题,但还有很多其他证据表明权限很好:

  • 在对文件使用exiftool 之前,我的应用程序stats 单独使用FS.stat 获取文件的大小和时间戳;此统计调用适用于两个卷(注意:应用程序不会直接运行这些调用:它今天stats 文件,然后将文件添加到可能在几天后处理的exiftool 扫描队列)
  • 第一次运行应用程序的每个新版本时,MacOS 要求我重新确认授予网络文件夹权限;我总是同意他们
  • 作为实验,我为我的应用程序提供了全盘访问权限(它确实不需要),但这没有任何效果;我专门尝试了这个,因为我的终端应用程序 iTerm2 具有全磁盘访问权限,我认为这可能是导致行为与“生产”不同的原因
  • 我的应用 UI 允许我打开单个文件(使用 Electron.shell.openPath(PATH_TO_FILE)),这对于任一卷上的文件都成功

我也尽我所能检查基本文件权限,但我看不出有什么不同。这些卷由用户通过 Finder 安装,Finder 将它们放置在 /Volumes/alpha/Volumes/beta。挂载时,ls 显示这两个节点具有相同的权限:

/Volumes $ ls -lht
total 64
drwx------  1 Tom   staff    16K Mar 25 18:46 alpha
drwx------  1 Tom   staff    16K Mar 25 02:00 beta
lrwxr-xr-x  1 root  wheel     1B Dec 31  2019 Macintosh HD -> /

我还手动检查了单张照片的权限,但它们的权限是相同的。我已经使用 NAS 管理工具来验证我的用户帐户是否可以不受限制地访问两个卷;可以,否则我的手动实验都行不通。

而且,作为最后的努力,我将自己的 uid 和 gid 硬编码到 spawn 调用中,以使 Electron 以我自己的身份执行命令,但这也没有任何效果:当 Electron 运行时,我仍然得到 ENOENT exiftool 针对任何处于测试阶段的文件,仅仅是因为该文件处于测试阶段。再次,测试版是我拥有完全访问权限的网络卷,我已多次授予应用程序完全访问权限,该应用程序已经以其他几种方式与之交互,并且在任何方面与 alpha 没有明显不同,我尽管在两台设备上都具有 root 权限,但仍可以检测到。

我什至喊过“是的,有 ENT!”在它。我完全没有想法。

为什么这两种情况不同,我该如何解决?或者失败了,我该如何进一步调试它?

非常欢迎任何建议。

我的包版本:

  • 电子:9.2
  • 电子封装器:14.2
  • 节点:14.13

在运行 MacOS 11.2.3 的 Mac 上运行的电子

NAS 在某种 Linux 上运行 ext4 文件系统。

【问题讨论】:

  • 如果你得到一个 ENOENT,这意味着提供的 cwd 是无效路径(此处不适用,因为你没有传递 cwd)或者该命令不存在(来源:NodeJS docs)。换句话说,该消息与您尝试运行 exiftool 的文件无关。

标签: node.js unix electron file-permissions macos-big-sur


【解决方案1】:

指定有效命令的完整路径:

const process = ChildProcess.spawn(
    '/usr/local/bin/exiftool',
    ['-json', '-n', PATH_TO_FILE]
)

我不知道为什么当目标处于 alpha 时不需要这样做,但事实并非如此。

此版本适用于打包的应用程序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多