Browse Source

:bug: 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
Juan Cruz Viotti 9 years ago
parent
commit
585ff9062c

+ 1 - 0
atom/common/api/atom_api_asar.cc

@@ -54,6 +54,7 @@ class Archive : public mate::Wrappable {
     mate::Dictionary dict(isolate, v8::Object::New(isolate));
     dict.Set("size", stats.size);
     dict.Set("offset", stats.offset);
+    dict.Set("executable", stats.executable);
     dict.Set("isFile", stats.is_file);
     dict.Set("isDirectory", stats.is_directory);
     dict.Set("isLink", stats.is_link);

+ 3 - 0
atom/common/asar/archive.cc

@@ -107,6 +107,9 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
     return false;
   info->offset += header_size;
 
+  info->executable = false;
+  node->GetBoolean("executable", &info->executable);
+
   return true;
 }
 

+ 1 - 0
atom/common/asar/archive.h

@@ -27,6 +27,7 @@ class Archive {
   struct FileInfo {
     FileInfo() : size(0), offset(0) {}
     bool unpacked;
+    bool executable;
     uint32 size;
     uint64 offset;
   };

+ 11 - 0
atom/common/lib/asar.coffee

@@ -1,5 +1,6 @@
 asar = process.binding 'atom_common_asar'
 child_process = require 'child_process'
+fs = require 'fs'
 path = require 'path'
 util = require 'util'
 
@@ -83,6 +84,11 @@ overrideAPISync = (module, name, arg = 0) ->
     newPath = archive.copyFileOut filePath
     notFoundError asarPath, filePath unless newPath
 
+    stat = archive.stat filePath
+
+    if stat.executable
+      fs.chmodSync(newPath, 0o755)
+
     arguments[arg] = newPath
     old.apply this, arguments
 
@@ -102,6 +108,11 @@ overrideAPI = (module, name, arg = 0) ->
     newPath = archive.copyFileOut filePath
     return notFoundError asarPath, filePath, callback unless newPath
 
+    stat = archive.stat filePath
+
+    if stat.executable
+      fs.chmodSync(newPath, 0o755)
+
     arguments[arg] = newPath
     old.apply this, arguments