nextcloud/lib/private/TempManager.php
Christoph Wurst caff1023ea
Format control structures, classes, methods and function
To continue this formatting madness, here's a tiny patch that adds
unified formatting for control structures like if and loops as well as
classes, their methods and anonymous functions. This basically forces
the constructs to start on the same line. This is not exactly what PSR2
wants, but I think we can have a few exceptions with "our" style. The
starting of braces on the same line is pracrically standard for our
code.

This also removes and empty lines from method/function bodies at the
beginning and end.

Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
2020-04-10 14:19:56 +02:00

279 lines
7.4 KiB
PHP

<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Lars <winnetou+github@catolic.de>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Martin Mattel <martin.mattel@diemattels.at>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Olivier Paroz <github@oparoz.com>
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Stefan Weil <sw@weilnetz.de>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OC;
use OCP\IConfig;
use OCP\ILogger;
use OCP\ITempManager;
class TempManager implements ITempManager {
/** @var string[] Current temporary files and folders, used for cleanup */
protected $current = [];
/** @var string i.e. /tmp on linux systems */
protected $tmpBaseDir;
/** @var ILogger */
protected $log;
/** @var IConfig */
protected $config;
/** Prefix */
const TMP_PREFIX = 'oc_tmp_';
/**
* @param \OCP\ILogger $logger
* @param \OCP\IConfig $config
*/
public function __construct(ILogger $logger, IConfig $config) {
$this->log = $logger;
$this->config = $config;
$this->tmpBaseDir = $this->getTempBaseDir();
}
/**
* Builds the filename with suffix and removes potential dangerous characters
* such as directory separators.
*
* @param string $absolutePath Absolute path to the file / folder
* @param string $postFix Postfix appended to the temporary file name, may be user controlled
* @return string
*/
private function buildFileNameWithSuffix($absolutePath, $postFix = '') {
if ($postFix !== '') {
$postFix = '.' . ltrim($postFix, '.');
$postFix = str_replace(['\\', '/'], '', $postFix);
$absolutePath .= '-';
}
return $absolutePath . $postFix;
}
/**
* Create a temporary file and return the path
*
* @param string $postFix Postfix appended to the temporary file name
* @return string
*/
public function getTemporaryFile($postFix = '') {
if (is_writable($this->tmpBaseDir)) {
// To create an unique file and prevent the risk of race conditions
// or duplicated temporary files by other means such as collisions
// we need to create the file using `tempnam` and append a possible
// postfix to it later
$file = tempnam($this->tmpBaseDir, self::TMP_PREFIX);
$this->current[] = $file;
// If a postfix got specified sanitize it and create a postfixed
// temporary file
if ($postFix !== '') {
$fileNameWithPostfix = $this->buildFileNameWithSuffix($file, $postFix);
touch($fileNameWithPostfix);
chmod($fileNameWithPostfix, 0600);
$this->current[] = $fileNameWithPostfix;
return $fileNameWithPostfix;
}
return $file;
} else {
$this->log->warning(
'Can not create a temporary file in directory {dir}. Check it exists and has correct permissions',
[
'dir' => $this->tmpBaseDir,
]
);
return false;
}
}
/**
* Create a temporary folder and return the path
*
* @param string $postFix Postfix appended to the temporary folder name
* @return string
*/
public function getTemporaryFolder($postFix = '') {
if (is_writable($this->tmpBaseDir)) {
// To create an unique directory and prevent the risk of race conditions
// or duplicated temporary files by other means such as collisions
// we need to create the file using `tempnam` and append a possible
// postfix to it later
$uniqueFileName = tempnam($this->tmpBaseDir, self::TMP_PREFIX);
$this->current[] = $uniqueFileName;
// Build a name without postfix
$path = $this->buildFileNameWithSuffix($uniqueFileName . '-folder', $postFix);
mkdir($path, 0700);
$this->current[] = $path;
return $path . '/';
} else {
$this->log->warning(
'Can not create a temporary folder in directory {dir}. Check it exists and has correct permissions',
[
'dir' => $this->tmpBaseDir,
]
);
return false;
}
}
/**
* Remove the temporary files and folders generated during this request
*/
public function clean() {
$this->cleanFiles($this->current);
}
/**
* @param string[] $files
*/
protected function cleanFiles($files) {
foreach ($files as $file) {
if (file_exists($file)) {
try {
\OC_Helper::rmdirr($file);
} catch (\UnexpectedValueException $ex) {
$this->log->warning(
"Error deleting temporary file/folder: {file} - Reason: {error}",
[
'file' => $file,
'error' => $ex->getMessage(),
]
);
}
}
}
}
/**
* Remove old temporary files and folders that were failed to be cleaned
*/
public function cleanOld() {
$this->cleanFiles($this->getOldFiles());
}
/**
* Get all temporary files and folders generated by oc older than an hour
*
* @return string[]
*/
protected function getOldFiles() {
$cutOfTime = time() - 3600;
$files = [];
$dh = opendir($this->tmpBaseDir);
if ($dh) {
while (($file = readdir($dh)) !== false) {
if (substr($file, 0, 7) === self::TMP_PREFIX) {
$path = $this->tmpBaseDir . '/' . $file;
$mtime = filemtime($path);
if ($mtime < $cutOfTime) {
$files[] = $path;
}
}
}
}
return $files;
}
/**
* Get the temporary base directory configured on the server
*
* @return string Path to the temporary directory or null
* @throws \UnexpectedValueException
*/
public function getTempBaseDir() {
if ($this->tmpBaseDir) {
return $this->tmpBaseDir;
}
$directories = [];
if ($temp = $this->config->getSystemValue('tempdirectory', null)) {
$directories[] = $temp;
}
if ($temp = \OC::$server->getIniWrapper()->get('upload_tmp_dir')) {
$directories[] = $temp;
}
if ($temp = getenv('TMP')) {
$directories[] = $temp;
}
if ($temp = getenv('TEMP')) {
$directories[] = $temp;
}
if ($temp = getenv('TMPDIR')) {
$directories[] = $temp;
}
if ($temp = sys_get_temp_dir()) {
$directories[] = $temp;
}
foreach ($directories as $dir) {
if ($this->checkTemporaryDirectory($dir)) {
return $dir;
}
}
$temp = tempnam(dirname(__FILE__), '');
if (file_exists($temp)) {
unlink($temp);
return dirname($temp);
}
throw new \UnexpectedValueException('Unable to detect system temporary directory');
}
/**
* Check if a temporary directory is ready for use
*
* @param mixed $directory
* @return bool
*/
private function checkTemporaryDirectory($directory) {
// suppress any possible errors caused by is_writable
// checks missing or invalid path or characters, wrong permissions etc
try {
if (is_writable($directory)) {
return true;
}
} catch (\Exception $e) {
}
$this->log->warning('Temporary directory {dir} is not present or writable',
['dir' => $directory]
);
return false;
}
/**
* Override the temporary base directory
*
* @param string $directory
*/
public function overrideTempBaseDir($directory) {
$this->tmpBaseDir = $directory;
}
}