Passed
Push — master ( daee22...bbb168 )
by Morris
13:11 queued 10s
created

OC_Helper::phpFileSize()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 5
nop 1
dl 0
loc 17
rs 9.5555
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Ardinis <[email protected]>
6
 * @author Arthur Schiwon <[email protected]>
7
 * @author Bart Visscher <[email protected]>
8
 * @author Björn Schießle <[email protected]>
9
 * @author Christopher Schäpers <[email protected]>
10
 * @author Clark Tomlinson <[email protected]>
11
 * @author Fabian Henze <[email protected]>
12
 * @author Felix Moeller <[email protected]>
13
 * @author Jakob Sack <[email protected]>
14
 * @author Jan-Christoph Borchardt <[email protected]>
15
 * @author Joas Schilling <[email protected]>
16
 * @author Jörn Friedrich Dreyer <[email protected]>
17
 * @author Lukas Reschke <[email protected]>
18
 * @author Michael Gapczynski <[email protected]>
19
 * @author Morris Jobke <[email protected]>
20
 * @author Olivier Paroz <[email protected]>
21
 * @author Pellaeon Lin <[email protected]>
22
 * @author RealRancor <[email protected]>
23
 * @author Robin Appelman <[email protected]>
24
 * @author Robin McCorkell <[email protected]>
25
 * @author Roeland Jago Douma <[email protected]>
26
 * @author Simon Könnecke <[email protected]>
27
 * @author Thomas Müller <[email protected]>
28
 * @author Thomas Tanghus <[email protected]>
29
 * @author Vincent Petry <[email protected]>
30
 *
31
 * @license AGPL-3.0
32
 *
33
 * This code is free software: you can redistribute it and/or modify
34
 * it under the terms of the GNU Affero General Public License, version 3,
35
 * as published by the Free Software Foundation.
36
 *
37
 * This program is distributed in the hope that it will be useful,
38
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40
 * GNU Affero General Public License for more details.
41
 *
42
 * You should have received a copy of the GNU Affero General Public License, version 3,
43
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
44
 *
45
 */
46
use Symfony\Component\Process\ExecutableFinder;
47
48
/**
49
 * Collection of useful functions
50
 */
51
class OC_Helper {
52
	private static $templateManager;
53
54
	/**
55
	 * Make a human file size
56
	 * @param int $bytes file size in bytes
57
	 * @return string a human readable file size
58
	 *
59
	 * Makes 2048 to 2 kB.
60
	 */
61
	public static function humanFileSize($bytes) {
62
		if ($bytes < 0) {
63
			return "?";
64
		}
65
		if ($bytes < 1024) {
66
			return "$bytes B";
67
		}
68
		$bytes = round($bytes / 1024, 0);
69
		if ($bytes < 1024) {
70
			return "$bytes KB";
71
		}
72
		$bytes = round($bytes / 1024, 1);
73
		if ($bytes < 1024) {
74
			return "$bytes MB";
75
		}
76
		$bytes = round($bytes / 1024, 1);
77
		if ($bytes < 1024) {
78
			return "$bytes GB";
79
		}
80
		$bytes = round($bytes / 1024, 1);
81
		if ($bytes < 1024) {
82
			return "$bytes TB";
83
		}
84
85
		$bytes = round($bytes / 1024, 1);
86
		return "$bytes PB";
87
	}
88
89
	/**
90
	 * Make a computer file size
91
	 * @param string $str file size in human readable format
92
	 * @return float|bool a file size in bytes
93
	 *
94
	 * Makes 2kB to 2048.
95
	 *
96
	 * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418
97
	 */
98
	public static function computerFileSize($str) {
99
		$str = strtolower($str);
100
		if (is_numeric($str)) {
101
			return (float)$str;
102
		}
103
104
		$bytes_array = array(
105
			'b' => 1,
106
			'k' => 1024,
107
			'kb' => 1024,
108
			'mb' => 1024 * 1024,
109
			'm' => 1024 * 1024,
110
			'gb' => 1024 * 1024 * 1024,
111
			'g' => 1024 * 1024 * 1024,
112
			'tb' => 1024 * 1024 * 1024 * 1024,
113
			't' => 1024 * 1024 * 1024 * 1024,
114
			'pb' => 1024 * 1024 * 1024 * 1024 * 1024,
115
			'p' => 1024 * 1024 * 1024 * 1024 * 1024,
116
		);
117
118
		$bytes = (float)$str;
119
120
		if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) {
121
			$bytes *= $bytes_array[$matches[1]];
122
		} else {
123
			return false;
124
		}
125
126
		$bytes = round($bytes);
127
128
		return $bytes;
129
	}
130
131
	/**
132
	 * Recursive copying of folders
133
	 * @param string $src source folder
134
	 * @param string $dest target folder
135
	 *
136
	 */
137
	static function copyr($src, $dest) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
138
		if (is_dir($src)) {
139
			if (!is_dir($dest)) {
140
				mkdir($dest);
141
			}
142
			$files = scandir($src);
143
			foreach ($files as $file) {
144
				if ($file != "." && $file != "..") {
145
					self::copyr("$src/$file", "$dest/$file");
146
				}
147
			}
148
		} elseif (file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) {
149
			copy($src, $dest);
150
		}
151
	}
152
153
	/**
154
	 * Recursive deletion of folders
155
	 * @param string $dir path to the folder
156
	 * @param bool $deleteSelf if set to false only the content of the folder will be deleted
157
	 * @return bool
158
	 */
159
	static function rmdirr($dir, $deleteSelf = true) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
160
		if (is_dir($dir)) {
161
			$files = new RecursiveIteratorIterator(
162
				new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
163
				RecursiveIteratorIterator::CHILD_FIRST
164
			);
165
166
			foreach ($files as $fileInfo) {
167
				/** @var SplFileInfo $fileInfo */
168
				if ($fileInfo->isLink()) {
169
					unlink($fileInfo->getPathname());
170
				} else if ($fileInfo->isDir()) {
171
					rmdir($fileInfo->getRealPath());
172
				} else {
173
					unlink($fileInfo->getRealPath());
174
				}
175
			}
176
			if ($deleteSelf) {
177
				rmdir($dir);
178
			}
179
		} elseif (file_exists($dir)) {
180
			if ($deleteSelf) {
181
				unlink($dir);
182
			}
183
		}
184
		if (!$deleteSelf) {
185
			return true;
186
		}
187
188
		return !file_exists($dir);
189
	}
190
191
	/**
192
	 * @return \OC\Files\Type\TemplateManager
193
	 */
194
	static public function getFileTemplateManager() {
195
		if (!self::$templateManager) {
196
			self::$templateManager = new \OC\Files\Type\TemplateManager();
197
		}
198
		return self::$templateManager;
199
	}
200
201
	/**
202
	 * detect if a given program is found in the search PATH
203
	 *
204
	 * @param string $name
205
	 * @param bool $path
206
	 * @internal param string $program name
207
	 * @internal param string $optional search path, defaults to $PATH
208
	 * @return bool    true if executable program found in path
209
	 */
210
	public static function canExecute($name, $path = false) {
211
		// path defaults to PATH from environment if not set
212
		if ($path === false) {
213
			$path = getenv("PATH");
214
		}
215
		// we look for an executable file of that name
216
		$exts = [""];
217
		$check_fn = "is_executable";
218
		// Default check will be done with $path directories :
219
		$dirs = explode(PATH_SEPARATOR, $path);
220
		// WARNING : We have to check if open_basedir is enabled :
221
		$obd = OC::$server->getIniWrapper()->getString('open_basedir');
222
		if ($obd != "none") {
223
			$obd_values = explode(PATH_SEPARATOR, $obd);
224
			if (count($obd_values) > 0 and $obd_values[0]) {
225
				// open_basedir is in effect !
226
				// We need to check if the program is in one of these dirs :
227
				$dirs = $obd_values;
228
			}
229
		}
230
		foreach ($dirs as $dir) {
231
			foreach ($exts as $ext) {
232
				if ($check_fn("$dir/$name" . $ext))
233
					return true;
234
			}
235
		}
236
		return false;
237
	}
238
239
	/**
240
	 * copy the contents of one stream to another
241
	 *
242
	 * @param resource $source
243
	 * @param resource $target
244
	 * @return array the number of bytes copied and result
245
	 */
246
	public static function streamCopy($source, $target) {
247
		if (!$source or !$target) {
0 ignored issues
show
introduced by
$source is of type resource, thus it always evaluated to false.
Loading history...
248
			return array(0, false);
249
		}
250
		$bufSize = 8192;
251
		$result = true;
252
		$count = 0;
253
		while (!feof($source)) {
254
			$buf = fread($source, $bufSize);
255
			$bytesWritten = fwrite($target, $buf);
256
			if ($bytesWritten !== false) {
257
				$count += $bytesWritten;
258
			}
259
			// note: strlen is expensive so only use it when necessary,
260
			// on the last block
261
			if ($bytesWritten === false
262
				|| ($bytesWritten < $bufSize && $bytesWritten < strlen($buf))
263
			) {
264
				// write error, could be disk full ?
265
				$result = false;
266
				break;
267
			}
268
		}
269
		return array($count, $result);
270
	}
271
272
	/**
273
	 * Adds a suffix to the name in case the file exists
274
	 *
275
	 * @param string $path
276
	 * @param string $filename
277
	 * @return string
278
	 */
279
	public static function buildNotExistingFileName($path, $filename) {
280
		$view = \OC\Files\Filesystem::getView();
281
		return self::buildNotExistingFileNameForView($path, $filename, $view);
282
	}
283
284
	/**
285
	 * Adds a suffix to the name in case the file exists
286
	 *
287
	 * @param string $path
288
	 * @param string $filename
289
	 * @return string
290
	 */
291
	public static function buildNotExistingFileNameForView($path, $filename, \OC\Files\View $view) {
292
		if ($path === '/') {
293
			$path = '';
294
		}
295
		if ($pos = strrpos($filename, '.')) {
296
			$name = substr($filename, 0, $pos);
297
			$ext = substr($filename, $pos);
298
		} else {
299
			$name = $filename;
300
			$ext = '';
301
		}
302
303
		$newpath = $path . '/' . $filename;
304
		if ($view->file_exists($newpath)) {
305
			if (preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) {
306
				//Replace the last "(number)" with "(number+1)"
307
				$last_match = count($matches[0]) - 1;
308
				$counter = $matches[1][$last_match][0] + 1;
309
				$offset = $matches[0][$last_match][1];
310
				$match_length = strlen($matches[0][$last_match][0]);
311
			} else {
312
				$counter = 2;
313
				$match_length = 0;
314
				$offset = false;
315
			}
316
			do {
317
				if ($offset) {
318
					//Replace the last "(number)" with "(number+1)"
319
					$newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length);
320
				} else {
321
					$newname = $name . ' (' . $counter . ')';
322
				}
323
				$newpath = $path . '/' . $newname . $ext;
324
				$counter++;
325
			} while ($view->file_exists($newpath));
326
		}
327
328
		return $newpath;
329
	}
330
331
	/**
332
	 * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
333
	 *
334
	 * @param array $input The array to work on
335
	 * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default)
336
	 * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
337
	 * @return array
338
	 *
339
	 * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
340
	 * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715
341
	 *
342
	 */
343
	public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') {
344
		$case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER;
345
		$ret = array();
346
		foreach ($input as $k => $v) {
347
			$ret[mb_convert_case($k, $case, $encoding)] = $v;
348
		}
349
		return $ret;
350
	}
351
352
	/**
353
	 * performs a search in a nested array
354
	 * @param array $haystack the array to be searched
355
	 * @param string $needle the search string
356
	 * @param mixed $index optional, only search this key name
357
	 * @return mixed the key of the matching field, otherwise false
358
	 *
359
	 * performs a search in a nested array
360
	 *
361
	 * taken from http://www.php.net/manual/en/function.array-search.php#97645
362
	 */
363
	public static function recursiveArraySearch($haystack, $needle, $index = null) {
364
		$aIt = new RecursiveArrayIterator($haystack);
365
		$it = new RecursiveIteratorIterator($aIt);
366
367
		while ($it->valid()) {
368
			if (((isset($index) AND ($it->key() == $index)) OR !isset($index)) AND ($it->current() == $needle)) {
369
				return $aIt->key();
370
			}
371
372
			$it->next();
373
		}
374
375
		return false;
376
	}
377
378
	/**
379
	 * calculates the maximum upload size respecting system settings, free space and user quota
380
	 *
381
	 * @param string $dir the current folder where the user currently operates
382
	 * @param int $freeSpace the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
383
	 * @return int number of bytes representing
384
	 */
385
	public static function maxUploadFilesize($dir, $freeSpace = null) {
386
		if (is_null($freeSpace) || $freeSpace < 0){
387
			$freeSpace = self::freeSpace($dir);
388
		}
389
		return min($freeSpace, self::uploadLimit());
390
	}
391
392
	/**
393
	 * Calculate free space left within user quota
394
	 *
395
	 * @param string $dir the current folder where the user currently operates
396
	 * @return int number of bytes representing
397
	 */
398
	public static function freeSpace($dir) {
399
		$freeSpace = \OC\Files\Filesystem::free_space($dir);
400
		if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
401
			$freeSpace = max($freeSpace, 0);
402
			return $freeSpace;
403
		} else {
404
			return (INF > 0)? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
405
		}
406
	}
407
408
	/**
409
	 * Calculate PHP upload limit
410
	 *
411
	 * @return int PHP upload file size limit
412
	 */
413
	public static function uploadLimit() {
414
		$ini = \OC::$server->getIniWrapper();
415
		$upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize'));
416
		$post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size'));
417
		if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) {
418
			return INF;
419
		} elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) {
420
			return max($upload_max_filesize, $post_max_size); //only the non 0 value counts
421
		} else {
422
			return min($upload_max_filesize, $post_max_size);
423
		}
424
	}
425
426
	/**
427
	 * Checks if a function is available
428
	 *
429
	 * @param string $function_name
430
	 * @return bool
431
	 */
432
	public static function is_function_enabled($function_name) {
433
		if (!function_exists($function_name)) {
434
			return false;
435
		}
436
		$ini = \OC::$server->getIniWrapper();
437
		$disabled = explode(',', $ini->get('disable_functions') ?: '');
438
		$disabled = array_map('trim', $disabled);
439
		if (in_array($function_name, $disabled)) {
440
			return false;
441
		}
442
		$disabled = explode(',', $ini->get('suhosin.executor.func.blacklist') ?: '');
443
		$disabled = array_map('trim', $disabled);
444
		if (in_array($function_name, $disabled)) {
445
			return false;
446
		}
447
		return true;
448
	}
449
450
	/**
451
	 * Try to find a program
452
	 *
453
	 * @param string $program
454
	 * @return null|string
455
	 */
456
	public static function findBinaryPath($program) {
457
		$memcache = \OC::$server->getMemCacheFactory()->createDistributed('findBinaryPath');
458
		if ($memcache->hasKey($program)) {
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ICache::hasKey() has been deprecated: 9.1.0 Directly read from GET to prevent race conditions ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

458
		if (/** @scrutinizer ignore-deprecated */ $memcache->hasKey($program)) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
459
			return $memcache->get($program);
460
		}
461
		$result = null;
462
		if (self::is_function_enabled('exec')) {
463
			$exeSniffer = new ExecutableFinder();
464
			// Returns null if nothing is found
465
			$result = $exeSniffer->find($program, null, ['/usr/local/sbin', '/usr/local/bin', '/usr/sbin', '/usr/bin', '/sbin', '/bin', '/opt/bin']);
466
		}
467
		// store the value for 5 minutes
468
		$memcache->set($program, $result, 300);
469
		return $result;
470
	}
471
472
	/**
473
	 * Calculate the disc space for the given path
474
	 *
475
	 * @param string $path
476
	 * @param \OCP\Files\FileInfo $rootInfo (optional)
477
	 * @return array
478
	 * @throws \OCP\Files\NotFoundException
479
	 */
480
	public static function getStorageInfo($path, $rootInfo = null) {
481
		// return storage info without adding mount points
482
		$includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
483
484
		if (!$rootInfo) {
485
			$rootInfo = \OC\Files\Filesystem::getFileInfo($path, $includeExtStorage ? 'ext' : false);
486
		}
487
		if (!$rootInfo instanceof \OCP\Files\FileInfo) {
488
			throw new \OCP\Files\NotFoundException();
489
		}
490
		$used = $rootInfo->getSize();
491
		if ($used < 0) {
492
			$used = 0;
493
		}
494
		$quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
495
		$storage = $rootInfo->getStorage();
496
		$sourceStorage = $storage;
497
		if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
498
			$includeExtStorage = false;
499
			$sourceStorage = $storage->getSourceStorage();
0 ignored issues
show
Bug introduced by
The method getSourceStorage() does not exist on OCP\Files\Storage. It seems like you code against a sub-type of OCP\Files\Storage such as OC\Files\Storage\Wrapper\Wrapper. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

499
			/** @scrutinizer ignore-call */ 
500
   $sourceStorage = $storage->getSourceStorage();
Loading history...
Bug introduced by
The method getSourceStorage() does not exist on OC\Files\Storage\Storage. It seems like you code against a sub-type of OC\Files\Storage\Storage such as OC\Files\Storage\Wrapper\Wrapper. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

499
			/** @scrutinizer ignore-call */ 
500
   $sourceStorage = $storage->getSourceStorage();
Loading history...
500
		}
501
		if ($includeExtStorage) {
502
			if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
503
				|| $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
504
			) {
505
				/** @var \OC\Files\Storage\Home $storage */
506
				$userInstance = $storage->getUser();
507
				$user = ($userInstance === null) ? null : $userInstance->getUID();
508
			} else {
509
				$user = \OC::$server->getUserSession()->getUser()->getUID();
510
			}
511
			if ($user) {
512
				$quota = OC_Util::getUserQuota($user);
513
			} else {
514
				$quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
515
			}
516
			if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
517
				// always get free space / total space from root + mount points
518
				return self::getGlobalStorageInfo();
519
			}
520
		}
521
522
		// TODO: need a better way to get total space from storage
523
		if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')) {
524
			/** @var \OC\Files\Storage\Wrapper\Quota $storage */
525
			$quota = $sourceStorage->getQuota();
526
		}
527
		$free = $sourceStorage->free_space($rootInfo->getInternalPath());
528
		if ($free >= 0) {
529
			$total = $free + $used;
530
		} else {
531
			$total = $free; //either unknown or unlimited
532
		}
533
		if ($total > 0) {
534
			if ($quota > 0 && $total > $quota) {
535
				$total = $quota;
536
			}
537
			// prevent division by zero or error codes (negative values)
538
			$relative = round(($used / $total) * 10000) / 100;
539
		} else {
540
			$relative = 0;
541
		}
542
543
		$ownerId = $storage->getOwner($path);
544
		$ownerDisplayName = '';
545
		$owner = \OC::$server->getUserManager()->get($ownerId);
546
		if($owner) {
547
			$ownerDisplayName = $owner->getDisplayName();
548
		}
549
550
		return [
551
			'free' => $free,
552
			'used' => $used,
553
			'quota' => $quota,
554
			'total' => $total,
555
			'relative' => $relative,
556
			'owner' => $ownerId,
557
			'ownerDisplayName' => $ownerDisplayName,
558
		];
559
	}
560
561
	/**
562
	 * Get storage info including all mount points and quota
563
	 *
564
	 * @return array
565
	 */
566
	private static function getGlobalStorageInfo() {
567
		$quota = OC_Util::getUserQuota(\OCP\User::getUser());
0 ignored issues
show
Deprecated Code introduced by
The function OCP\User::getUser() has been deprecated: 8.0.0 Use \OC::$server->getUserSession()->getUser()->getUID() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

567
		$quota = OC_Util::getUserQuota(/** @scrutinizer ignore-deprecated */ \OCP\User::getUser());

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
568
569
		$rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext');
0 ignored issues
show
Bug introduced by
'ext' of type string is incompatible with the type boolean expected by parameter $includeMountPoints of OC\Files\Filesystem::getFileInfo(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

569
		$rootInfo = \OC\Files\Filesystem::getFileInfo('', /** @scrutinizer ignore-type */ 'ext');
Loading history...
570
		$used = $rootInfo['size'];
571
		if ($used < 0) {
572
			$used = 0;
573
		}
574
575
		$total = $quota;
576
		$free = $quota - $used;
577
578
		if ($total > 0) {
579
			if ($quota > 0 && $total > $quota) {
580
				$total = $quota;
581
			}
582
			// prevent division by zero or error codes (negative values)
583
			$relative = round(($used / $total) * 10000) / 100;
584
		} else {
585
			$relative = 0;
586
		}
587
588
		return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative);
589
590
	}
591
592
	/**
593
	 * Returns whether the config file is set manually to read-only
594
	 * @return bool
595
	 */
596
	public static function isReadOnlyConfigEnabled() {
597
		return \OC::$server->getConfig()->getSystemValue('config_is_read_only', false);
598
	}
599
}
600