Skip to content

Commit dee2942

Browse files
committed
feat: make search path for BinaryFinder customizable.
This feature is important for nextcloud running on distributions like NixOS, where all the standard search paths do not exist. Also added tests. This fixes issue #43922 Signed-off-by: Reno Reckling <e-github@wthack.de>
1 parent 80e4193 commit dee2942

3 files changed

Lines changed: 128 additions & 11 deletions

File tree

config/config.sample.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1962,7 +1962,7 @@
19621962
/**
19631963
* Blacklist characters from being used in filenames. This is useful if you
19641964
* have a filesystem or OS which does not support certain characters like windows.
1965-
*
1965+
*
19661966
* The '/' and '\' characters are always forbidden.
19671967
*
19681968
* Example for windows systems: ``array('?', '<', '>', ':', '*', '|', '"', chr(0), "\n", "\r")``
@@ -2431,4 +2431,20 @@
24312431
* Defaults to ``true``
24322432
*/
24332433
'enable_non-accessible_features' => true,
2434+
2435+
/**
2436+
* Directories where nextcloud looks for binaries.
2437+
* This is used to find external binaries like libreoffice, sendmail, ffmpeg and more.
2438+
*
2439+
* Defaults to ``['/usr/local/sbin','/usr/local/bin','/usr/sbin','/usr/bin','/sbin','/bin','/opt/bin']``
2440+
*/
2441+
'binary_search_paths' => [
2442+
'/usr/local/sbin',
2443+
'/usr/local/bin',
2444+
'/usr/sbin',
2445+
'/usr/bin',
2446+
'/sbin',
2447+
'/bin',
2448+
'/opt/bin',
2449+
],
24342450
];

lib/private/BinaryFinder.php

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
declare(strict_types = 1);
44
/**
55
* @copyright 2022 Carl Schwan <carl@carlschwan.eu>
6+
* @copyright 2024 Reno Reckling <e-github@wthack.de>
67
* @license GNU AGPL version 3 or any later version
78
*
89
* This program is free software: you can redistribute it and/or modify
@@ -25,15 +26,28 @@
2526
use OCP\IBinaryFinder;
2627
use OCP\ICache;
2728
use OCP\ICacheFactory;
29+
use OCP\IConfig;
2830
use Symfony\Component\Process\ExecutableFinder;
2931

3032
/**
3133
* Service that find the binary path for a program
3234
*/
3335
class BinaryFinder implements IBinaryFinder {
36+
public const DEFAULT_BINARY_SEARCH_PATHS = [
37+
'/usr/local/sbin',
38+
'/usr/local/bin',
39+
'/usr/sbin',
40+
'/usr/bin',
41+
'/sbin',
42+
'/bin',
43+
'/opt/bin',
44+
];
3445
private ICache $cache;
3546

36-
public function __construct(ICacheFactory $cacheFactory) {
47+
public function __construct(
48+
ICacheFactory $cacheFactory,
49+
private IConfig $config
50+
) {
3751
$this->cache = $cacheFactory->createLocal('findBinaryPath');
3852
}
3953

@@ -51,15 +65,10 @@ public function findBinaryPath(string $program) {
5165
if (\OCP\Util::isFunctionEnabled('exec')) {
5266
$exeSniffer = new ExecutableFinder();
5367
// Returns null if nothing is found
54-
$result = $exeSniffer->find($program, null, [
55-
'/usr/local/sbin',
56-
'/usr/local/bin',
57-
'/usr/sbin',
58-
'/usr/bin',
59-
'/sbin',
60-
'/bin',
61-
'/opt/bin',
62-
]);
68+
$result = $exeSniffer->find(
69+
$program,
70+
null,
71+
$this->config->getSystemValue('binary_search_paths', self::DEFAULT_BINARY_SEARCH_PATHS));
6372
if ($result === null) {
6473
$result = false;
6574
}

tests/lib/BinaryFinderTest.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
/**
5+
* @copyright 2024 Reno Reckling <e-github@wthack.de>
6+
* @license GNU AGPL version 3 or any later version
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as
10+
* published by the Free Software Foundation, either version 3 of the
11+
* License, or (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
23+
namespace Test;
24+
25+
use OCP\ICache;
26+
use OCP\IConfig;
27+
use OCP\ICacheFactory;
28+
use OC\BinaryFinder;
29+
30+
class BinaryFinderTest extends TestCase {
31+
private ICache $cache;
32+
private array $cacheMap;
33+
private ICacheFactory $cacheFactory;
34+
35+
protected function setUp(): void {
36+
$this->cacheMap = [];
37+
$this->cacheFactory = $this->createMock(ICacheFactory::class);
38+
$this->cache = $this->createMock(ICache::class);
39+
$this->cache->method('get')->will($this->returnCallback(function($key) {
40+
return array_key_exists($key, $this->cacheMap) ? $this->cacheMap[$key] : null;
41+
}));
42+
$this->cache->method('set')->will($this->returnCallback(function($key, $val, $expires) {
43+
$this->cacheMap[$key] = $val;
44+
}));
45+
$this->cacheFactory->method('createLocal')->with('findBinaryPath')->willReturn($this->cache);
46+
47+
}
48+
49+
public function testDefaultFindsCat() {
50+
$config = $this->createMock(IConfig::class);
51+
$config
52+
->method('getSystemValue')
53+
->with('binary_search_paths', $this->anything())
54+
->will($this->returnCallback(function($key, $default) {
55+
return $default;
56+
}));
57+
$finder = new BinaryFinder($this->cacheFactory, $config);
58+
$this->assertEquals($finder->findBinaryPath('cat'), '/usr/bin/cat');
59+
}
60+
61+
public function testDefaultDoesNotFindCata() {
62+
$config = $this->createMock(IConfig::class);
63+
$config
64+
->method('getSystemValue')
65+
->with('binary_search_paths', $this->anything())
66+
->will($this->returnCallback(function($key, $default) {
67+
return $default;
68+
}));
69+
$finder = new BinaryFinder($this->cacheFactory, $config);
70+
$this->assertFalse($finder->findBinaryPath('cata'));
71+
}
72+
73+
public function testCustomPathFindsCat() {
74+
$config = $this->createMock(IConfig::class);
75+
$config
76+
->method('getSystemValue')
77+
->with('binary_search_paths', $this->anything())
78+
->willReturn(['/usr/bin']);
79+
$finder = new BinaryFinder($this->cacheFactory, $config);
80+
$this->assertEquals($finder->findBinaryPath('cat'), '/usr/bin/cat');
81+
}
82+
83+
public function testWrongCustomPathDoesNotFindCat() {
84+
$config = $this->createMock(IConfig::class);
85+
$config
86+
->method('getSystemValue')
87+
->with('binary_search_paths')
88+
->willReturn(['/wrong']);
89+
$finder = new BinaryFinder($this->cacheFactory, $config);
90+
$this->assertFalse($finder->findBinaryPath('cats'));
91+
}
92+
}

0 commit comments

Comments
 (0)