Skip to content

Commit 61b4b69

Browse files
committed
Check that executable files are executable
1 parent 36e8f5b commit 61b4b69

File tree

2 files changed

+39
-42
lines changed

2 files changed

+39
-42
lines changed

server/src/executables.ts

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
import * as Fs from 'fs'
2-
import * as Path from 'path'
1+
import * as fs from 'fs'
2+
import { basename, join } from 'path'
3+
import { promisify } from 'util'
34

45
import * as ArrayUtil from './util/array'
56
import * as FsUtil from './util/fs'
67
import * as ShUtil from './util/sh'
78

9+
const lstatAsync = promisify(fs.lstat)
10+
const readdirAsync = promisify(fs.readdir)
11+
812
/**
913
* Provides information based on the programs on your PATH
1014
*/
@@ -58,34 +62,40 @@ export default class Executables {
5862
/**
5963
* Only returns direct children, or the path itself if it's an executable.
6064
*/
61-
function findExecutablesInPath(path: string): Promise<string[]> {
65+
async function findExecutablesInPath(path: string): Promise<string[]> {
6266
path = FsUtil.untildify(path)
63-
return new Promise((resolve, _) => {
64-
Fs.lstat(path, (err, stat) => {
65-
if (err) {
66-
resolve([])
67-
} else {
68-
if (stat.isDirectory()) {
69-
Fs.readdir(path, (readDirErr, paths) => {
70-
if (readDirErr) {
71-
resolve([])
72-
} else {
73-
const files = paths.map(p =>
74-
FsUtil.getStats(Path.join(path, p))
75-
.then(s => (s.isFile() ? [Path.basename(p)] : []))
76-
.catch(() => []),
77-
)
78-
79-
resolve(Promise.all(files).then(ArrayUtil.flatten))
80-
}
81-
})
82-
} else if (stat.isFile()) {
83-
resolve([Path.basename(path)])
84-
} else {
85-
// Something else.
86-
resolve([])
67+
68+
try {
69+
const pathStats = await lstatAsync(path)
70+
71+
if (pathStats.isDirectory()) {
72+
const childrenPaths = await readdirAsync(path)
73+
74+
const files = []
75+
76+
for (const childrenPath of childrenPaths) {
77+
try {
78+
const stats = await lstatAsync(join(path, childrenPath))
79+
if (isExecutableFile(stats)) {
80+
files.push(basename(childrenPath))
81+
}
82+
} catch (error) {
83+
// Ignore error
8784
}
8885
}
89-
})
90-
})
86+
87+
return files
88+
} else if (isExecutableFile(pathStats)) {
89+
return [basename(path)]
90+
}
91+
} catch (error) {
92+
// Ignore error
93+
}
94+
95+
return []
96+
}
97+
98+
function isExecutableFile(stats: fs.Stats): boolean {
99+
const isExecutable = !!(1 & parseInt((stats.mode & parseInt('777', 8)).toString(8)[0]))
100+
return stats.isFile() && isExecutable
91101
}

server/src/util/fs.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,6 @@
1-
import * as Fs from 'fs'
21
import * as glob from 'glob'
32
import * as Os from 'os'
43

5-
export function getStats(path: string): Promise<Fs.Stats> {
6-
return new Promise((resolve, reject) => {
7-
Fs.lstat(path, (err, stat) => {
8-
if (err) {
9-
reject(err)
10-
} else {
11-
resolve(stat)
12-
}
13-
})
14-
})
15-
}
16-
174
// from https://github.com/sindresorhus/untildify/blob/f85a087418aeaa2beb56fe2684fe3b64fc8c588d/index.js#L11
185
export function untildify(pathWithTilde: string): string {
196
const homeDirectory = Os.homedir()

0 commit comments

Comments
 (0)