🐛 Fix missing execution permission bit in execFile override
Consider an electron application that uses `execFile` to run a script that lives within the application code base: ```coffee child_process = require 'child_process' child_process.execFile __dirname + '/script.sh', (error) -> throw error if error? ``` An application like this will fail when being packaged in an `asar` with an following error: ``` Error: spawn EACCES ``` Electron overrides certain `fs` functions to make them work within an `asar` package. In the case of `execFile`, the file to be executed is extracted from the `asar` package into a temporary file and ran from there. The problem is that during the extraction, the original permissions of the file are lost. We workaround this by: 1. Extending `asar.stat` to return whether a file is executable or not, which is information that's already saved in the `asar` header. 2. Setting execution permissions on the extracted file if the above property holds true. Fixes: https://github.com/atom/electron/issues/3512
This commit is contained in:
parent
bf5e9e4f4d
commit
585ff9062c
4 changed files with 16 additions and 0 deletions
|
@ -54,6 +54,7 @@ class Archive : public mate::Wrappable {
|
||||||
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||||
dict.Set("size", stats.size);
|
dict.Set("size", stats.size);
|
||||||
dict.Set("offset", stats.offset);
|
dict.Set("offset", stats.offset);
|
||||||
|
dict.Set("executable", stats.executable);
|
||||||
dict.Set("isFile", stats.is_file);
|
dict.Set("isFile", stats.is_file);
|
||||||
dict.Set("isDirectory", stats.is_directory);
|
dict.Set("isDirectory", stats.is_directory);
|
||||||
dict.Set("isLink", stats.is_link);
|
dict.Set("isLink", stats.is_link);
|
||||||
|
|
|
@ -107,6 +107,9 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
|
||||||
return false;
|
return false;
|
||||||
info->offset += header_size;
|
info->offset += header_size;
|
||||||
|
|
||||||
|
info->executable = false;
|
||||||
|
node->GetBoolean("executable", &info->executable);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ class Archive {
|
||||||
struct FileInfo {
|
struct FileInfo {
|
||||||
FileInfo() : size(0), offset(0) {}
|
FileInfo() : size(0), offset(0) {}
|
||||||
bool unpacked;
|
bool unpacked;
|
||||||
|
bool executable;
|
||||||
uint32 size;
|
uint32 size;
|
||||||
uint64 offset;
|
uint64 offset;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
asar = process.binding 'atom_common_asar'
|
asar = process.binding 'atom_common_asar'
|
||||||
child_process = require 'child_process'
|
child_process = require 'child_process'
|
||||||
|
fs = require 'fs'
|
||||||
path = require 'path'
|
path = require 'path'
|
||||||
util = require 'util'
|
util = require 'util'
|
||||||
|
|
||||||
|
@ -83,6 +84,11 @@ overrideAPISync = (module, name, arg = 0) ->
|
||||||
newPath = archive.copyFileOut filePath
|
newPath = archive.copyFileOut filePath
|
||||||
notFoundError asarPath, filePath unless newPath
|
notFoundError asarPath, filePath unless newPath
|
||||||
|
|
||||||
|
stat = archive.stat filePath
|
||||||
|
|
||||||
|
if stat.executable
|
||||||
|
fs.chmodSync(newPath, 0o755)
|
||||||
|
|
||||||
arguments[arg] = newPath
|
arguments[arg] = newPath
|
||||||
old.apply this, arguments
|
old.apply this, arguments
|
||||||
|
|
||||||
|
@ -102,6 +108,11 @@ overrideAPI = (module, name, arg = 0) ->
|
||||||
newPath = archive.copyFileOut filePath
|
newPath = archive.copyFileOut filePath
|
||||||
return notFoundError asarPath, filePath, callback unless newPath
|
return notFoundError asarPath, filePath, callback unless newPath
|
||||||
|
|
||||||
|
stat = archive.stat filePath
|
||||||
|
|
||||||
|
if stat.executable
|
||||||
|
fs.chmodSync(newPath, 0o755)
|
||||||
|
|
||||||
arguments[arg] = newPath
|
arguments[arg] = newPath
|
||||||
old.apply this, arguments
|
old.apply this, arguments
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue