Electron 应用程序无法访问仅一个网络驱动器上的文件 [英] Electron app can't access files on only one network drive

查看:30
本文介绍了Electron 应用程序无法访问仅一个网络驱动器上的文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm building an Electron app that manages a collection of photographs on an NAS. That NAS has two logical volumes, named "alpha" and "beta". For reasons I want to understand (and fix!), my app gets an ENOENT error whenever it tries to run CLI tools against files on beta, but not when it runs CLI tools against alpha. Additionally, it is permitted to perform regular FS operations (e.g. readdir, stat, even rename) against files on both volumes without error. For example: the app first learns about the files on beta because it scans the filesystem using find; that scan succeeds.

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

I'm using the CLI tool exiftool to extract image metadata from all these files (e.g. dimensions, capture device, etc). Here's the command my app runs, using 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 内部.

If I run that using node from the command line, it works no matter where the target file is. If Electron runs it, it'll work against alpha but throw against beta. And if I run it from the integrated terminal inside VS Code, to which I have denied Network Folders permissions, it predictably throws against alpha and beta; that's true whether I use node or Electron, so long as it's from inside VS Code.

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

Here's console.log(error) when run as a packaged Electron app:

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'
  ]
}

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

Things I've verified experimentally:

  • 如果我从命令行逐字运行命令,它会起作用;所以,我的用户可以读取这些文件,exiftool
  • 也可以
  • 将文件从 alpha 移动到 beta(使用 Finder)会导致我的应用无法读取它,反之亦然
  • 我的实现很好:如果我使用终端中的节点来运行一个导入 readExif 的小 test.js,并手动提供测试版文件的路径,它有效
  • it works if I run the command verbatim from the command line; so, my user can read these files, as can exiftool
  • moving a file from alpha to beta (using Finder) causes it to become unreadable by my app, and vice versa
  • my implementation is fine: if I use node from the terminal to run a tiny test.js that imports readExif, and manually provide the path to a file on beta, it works

以上所有让我觉得这是一个权限问题,但还有很多其他的证据证明权限没问题:

All of the above makes me think this is a permissions issue, but there are so many other proofs that permissions are fine:

  • 在文件上使用 exiftool 之前,我的应用程序 stat 使用 FS.stat 单独获取文件的大小和大小.时间戳;此 stat 调用适用于两个卷(注意:应用程序不会按直接顺序运行这些调用:它 stat 今天是文件,然后将文件添加到 exiftool扫描队列可能会在几天后处理)
  • 第一次运行应用程序的每个新版本时,MacOS 要求我重新确认授予网络文件夹权限;我总是授予他们
  • 作为一项实验,我为我的应用程序提供了全磁盘访问权限(它确实不需要),但这没有任何效果;我专门尝试过这个,因为我的终端应用程序 iTerm2 具有完整磁盘访问权限,我认为这可能是因为与生产"行为不同的原因
  • 我的应用 UI 允许我打开单个文件(使用 Electron.shell.openPath(PATH_TO_FILE)),这对任一卷上的文件都成功
  • Before using exiftool on a file, my app stats the file individually using FS.stat to get its size & timestamps; this stat call works against both volumes (note: the app doesn't run these calls in direct sequence: it stats the file today, then adds the file to the exiftool scan queue which may be processed days later)
  • The first time I run each new build of the app, MacOS requires me to re-confirm granting Network Folders permissions; I always grant them
  • As an experiment, I gave my app Full Disk Access (which it really doesn't need), but that had no effect; I tried this specifically because my terminal app, iTerm2, has Full Disk Access, and I thought maybe that accounts for the different behavior vs "production"
  • My app UI lets me open individual files (using Electron.shell.openPath(PATH_TO_FILE)), which succeeds for files on either volume

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

I've also done what I can to inspect basic file permissions, but I can see no differences. These volumes get mounted by the user through the Finder, which places them at /Volumes/alpha and /Volumes/beta. While mounted, ls shows that those two nodes have the same perms:

/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 管理工具来验证我的用户帐户是否可以不受限制地访问两个卷;可以,否则我的手动实验都不起作用.

I've also hand-checked the perms on individual photos, but their permissions are the same. I've used the NAS admin tools to verify that my user account has unrestricted access to both volumes; it does, or none of my manual experiments would work.

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

And, as a last-ditch effort, I hard-coded my own uid and gid into the spawn call to make Electron execute the command as myself, but that also had no effect: I still get ENOENT when Electron runs exiftool against any file on beta, simply because the file is on beta. beta, again, a network volume to which I have full access, to which I have repeatedly granted the app full access, that this app already interacts with fine in several other ways, and that is not visibly different from alpha in any way that I can detect despite having root on both devices.

我什至大喊是的,有耳鼻喉科!";在它.我完全没有想法.

I have even shouted "Yes, there is ENT!" at it. I'm completely out of ideas.

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

Why are these two scenarios different, and how can I fix it? Or failing that, how can I further debug it?

非常欢迎任何建议.

我的软件包版本:

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

Electron 在运行 MacOS 11.2.3 的 Mac 上运行

Electron running on a Mac running MacOS 11.2.3

NAS 在某种 Linux 版本上运行 ext4 文件系统.

NAS is running an ext4 filesystem on some flavor of Linux.

推荐答案

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

Specifying the full path of the command worked:

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

我不知道为什么当目标处于 alpha 时这不是必需的,但事实并非如此.

I don't know why this isn't necessary when the target is on alpha, but it isn't.

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

This version works from the packaged app.

这篇关于Electron 应用程序无法访问仅一个网络驱动器上的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆