From 1232bce2adf6f4a2a3d6ba7520cfdfb0f9e466fc Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Thu, 30 May 2013 15:44:19 +0200 Subject: [PATCH] Attempt to fix write permission issues in certain environments --- wcfsetup/install.php | 50 +++++++++++++---- .../acp/form/MasterPasswordInitForm.class.php | 3 +- .../action/GravatarDownloadAction.class.php | 2 +- .../data/language/LanguageEditor.class.php | 7 ++- .../lib/data/option/OptionEditor.class.php | 3 +- .../lib/data/style/StyleEditor.class.php | 12 ++-- .../data/template/TemplateEditor.class.php | 4 +- .../install/files/lib/system/io/Tar.class.php | 7 +-- .../install/files/lib/system/io/Zip.class.php | 11 +--- .../PackageInstallationDispatcher.class.php | 2 +- .../lib/system/setup/Installer.class.php | 9 +-- .../install/files/lib/util/FileUtil.class.php | 56 +++++++++++++------ 12 files changed, 102 insertions(+), 64 deletions(-) diff --git a/wcfsetup/install.php b/wcfsetup/install.php index eafce16a5b..22aa4fc1f8 100644 --- a/wcfsetup/install.php +++ b/wcfsetup/install.php @@ -233,7 +233,7 @@ class BasicFileUtil { if (!empty($_SERVER['DOCUMENT_ROOT'])) { if (!@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName)) { @mkdir($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName, 0777, true); - @chmod($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName, 0777); + self::makeWritable($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName); } if (@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName) && @is_writable($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName)) { @@ -245,7 +245,7 @@ class BasicFileUtil { if (isset($_ENV[$tmpDir]) && @is_writable($_ENV[$tmpDir])) { $dir = $_ENV[$tmpDir] . '/' . $tmpDirName; @mkdir($dir, 0777); - @chmod($dir, 0777); + self::makeWritable($dir); if (@file_exists($dir) && @is_writable($dir)) { return $dir; @@ -255,7 +255,7 @@ class BasicFileUtil { $dir = INSTALL_SCRIPT_DIR . 'tmp/' . $tmpDirName; @mkdir($dir, 0777); - @chmod($dir, 0777); + self::makeWritable($dir); if (!@file_exists($dir) || !@is_writable($dir)) { $tmpDir = explode('/', $dir); @@ -267,6 +267,37 @@ class BasicFileUtil { return $dir; } + + /** + * Tries to make a file or directory writable. It starts of with the least + * permissions and goes up until 0777. + * + * @param string $filename + */ + public static function makeWritable($filename) { + if (is_writable($filename)) { + return; + } + + $chmods = array('0644', '0755', '0775', '0777'); + + $startIndex = 0; + if (is_dir($filename)) { + $startIndex = 1; + } + + for ($i = $startIndex; $i < 4; $i++) { + @chmod($filename, octdec($chmods[$i])); + + if (is_writable($filename)) { + break; + } + else if ($i == 3) { + // does not work with 0777 + throw new SystemException("Unable to make '".$filename."' writable. This is a misconfiguration of your server, please contact your system administrator or hosting provider."); + } + } + } } /** @@ -465,12 +496,7 @@ class Tar { } $targetFile->close(); - if (function_exists('apache_get_version') || !@$targetFile->is_writable()) { - @$targetFile->chmod(0777); - } - else { - @$targetFile->chmod(0755); - } + BasicFileUtil::makeWritable($destination); if ($header['mtime']) { @$targetFile->touch($header['mtime']); @@ -788,7 +814,7 @@ if (!file_exists(TMP_DIR . 'install/files/lib/system/WCFSetup.class.php')) { $dir = TMP_DIR . dirname($file['filename']); if (!@is_dir($dir)) { @mkdir($dir, 0777, true); - @chmod($dir, 0777); + BasicFileUtil::makeWritable($dir); } $tar->extract($file['index'], TMP_DIR . $file['filename']); @@ -799,10 +825,10 @@ if (!file_exists(TMP_DIR . 'install/files/lib/system/WCFSetup.class.php')) { // create cache folders @mkdir(TMP_DIR . 'setup/lang/cache/', 0777); - @chmod(TMP_DIR . 'setup/lang/cache/', 0777); + BasicFileUtil::makeWritable(TMP_DIR . 'setup/lang/cache/'); @mkdir(TMP_DIR . 'setup/template/compiled/', 0777); - @chmod(TMP_DIR . 'setup/template/compiled/', 0777); + BasicFileUtil::makeWritable(TMP_DIR . 'setup/template/compiled/'); } if (!class_exists('wcf\system\WCFSetup')) { diff --git a/wcfsetup/install/files/lib/acp/form/MasterPasswordInitForm.class.php b/wcfsetup/install/files/lib/acp/form/MasterPasswordInitForm.class.php index a6f7724a9d..1b4c377d78 100755 --- a/wcfsetup/install/files/lib/acp/form/MasterPasswordInitForm.class.php +++ b/wcfsetup/install/files/lib/acp/form/MasterPasswordInitForm.class.php @@ -6,6 +6,7 @@ use wcf\system\exception\UserInputException; use wcf\system\io\File; use wcf\system\Regex; use wcf\system\WCF; +use wcf\util\FileUtil; use wcf\util\PasswordUtil; use wcf\util\StringUtil; @@ -108,7 +109,7 @@ DO NOT EDIT THIS FILE */ define('MASTER_PASSWORD', '".PasswordUtil::getDoubleSaltedHash($this->masterPassword)."'); ?>"); $file->close(); - @chmod(WCF_DIR.'acp/masterPassword.inc.php', 0777); + FileUtil::makeWritable(WCF_DIR.'acp/masterPassword.inc.php'); parent::save(); } diff --git a/wcfsetup/install/files/lib/action/GravatarDownloadAction.class.php b/wcfsetup/install/files/lib/action/GravatarDownloadAction.class.php index 1d568a1163..f0c6ec1a29 100644 --- a/wcfsetup/install/files/lib/action/GravatarDownloadAction.class.php +++ b/wcfsetup/install/files/lib/action/GravatarDownloadAction.class.php @@ -73,7 +73,7 @@ class GravatarDownloadAction extends AbstractAction { $tmpFile = FileUtil::downloadFileFromHttp($gravatarURL, 'gravatar'); copy($tmpFile, WCF_DIR.$cachedFilename); @unlink($tmpFile); - @chmod(WCF_DIR.$cachedFilename, 0777); + FileUtil::makeWritable(WCF_DIR.$cachedFilename); @header('Content-Type: image/png'); @readfile(WCF_DIR.$cachedFilename); diff --git a/wcfsetup/install/files/lib/data/language/LanguageEditor.class.php b/wcfsetup/install/files/lib/data/language/LanguageEditor.class.php index 680756d3a4..735b5dd12e 100644 --- a/wcfsetup/install/files/lib/data/language/LanguageEditor.class.php +++ b/wcfsetup/install/files/lib/data/language/LanguageEditor.class.php @@ -1,5 +1,7 @@ languageID.'_'.$category->languageCategory.'.php'); - @$file->chmod(0777); + $filename = WCF_DIR.'language/'.$this->languageID.'_'.$category->languageCategory.'.php'; + $file = new File($filename); + FileUtil::makeWritable($filename); $file->write($content . '?>'); $file->close(); } diff --git a/wcfsetup/install/files/lib/data/option/OptionEditor.class.php b/wcfsetup/install/files/lib/data/option/OptionEditor.class.php index c57bbfd5c0..ae88e2fd9c 100644 --- a/wcfsetup/install/files/lib/data/option/OptionEditor.class.php +++ b/wcfsetup/install/files/lib/data/option/OptionEditor.class.php @@ -6,6 +6,7 @@ use wcf\system\cache\builder\OptionCacheBuilder; use wcf\system\cache\CacheHandler; use wcf\system\io\File; use wcf\system\WCF; +use wcf\util\FileUtil; /** * Provides functions to edit options. @@ -138,6 +139,6 @@ class OptionEditor extends DatabaseObjectEditor implements IEditableCachedObject // close file $file->close(); - @$file->chmod(0777); + FileUtil::makeWritable(WCF_DIR.'options.inc.php'); } } diff --git a/wcfsetup/install/files/lib/data/style/StyleEditor.class.php b/wcfsetup/install/files/lib/data/style/StyleEditor.class.php index 9901acc1f3..4538256192 100644 --- a/wcfsetup/install/files/lib/data/style/StyleEditor.class.php +++ b/wcfsetup/install/files/lib/data/style/StyleEditor.class.php @@ -365,7 +365,7 @@ class StyleEditor extends DatabaseObjectEditor implements IEditableCachedObject foreach ($contentList as $key => $val) { if ($val['type'] == 'file') { $imagesTar->extract($key, $imagesLocation.basename($val['filename'])); - @chmod($imagesLocation.basename($val['filename']), 0666); + FileUtil::makeWritable($imagesLocation.basename($val['filename'])); } } @@ -417,7 +417,7 @@ class StyleEditor extends DatabaseObjectEditor implements IEditableCachedObject // create template path if (!file_exists($templatesDir)) { @mkdir($templatesDir, 0777); - @chmod($templatesDir, 0777); + FileUtil::makeWritable($templatesDir); } // copy templates @@ -456,7 +456,7 @@ class StyleEditor extends DatabaseObjectEditor implements IEditableCachedObject if ($index !== false) { $filename = WCF_DIR.'images/stylePreview-'.$style->styleID.$fileExtension; $tar->extract($index, $filename); - @chmod($filename, 0777); + FileUtil::makeWritable($filename); if (file_exists($filename)) { $style->update(array('image' => 'stylePreview-'.$style->styleID.$fileExtension)); @@ -541,7 +541,7 @@ class StyleEditor extends DatabaseObjectEditor implements IEditableCachedObject $directory = $location . ($index === null ? '' : $index); if (!is_dir($directory)) { @mkdir($directory, 0777, true); - @chmod($directory, 0777); + FileUtil::makeWritable($directory); return FileUtil::addTrailingSlash($directory); } @@ -643,7 +643,7 @@ class StyleEditor extends DatabaseObjectEditor implements IEditableCachedObject // create templates tar $templatesTarName = FileUtil::getTemporaryFilename('templates', '.tar'); $templatesTar = new TarWriter($templatesTarName); - @chmod($templatesTarName, 0777); + FileUtil::makeWritable($templatesTarName); // append templates to tar // get templates @@ -672,7 +672,7 @@ class StyleEditor extends DatabaseObjectEditor implements IEditableCachedObject // create images tar $imagesTarName = FileUtil::getTemporaryFilename('images_', '.tar'); $imagesTar = new TarWriter($imagesTarName); - @chmod($imagesTarName, 0777); + FileUtil::makeWritable($imagesTarName); // append images to tar $path = FileUtil::addTrailingSlash(WCF_DIR.$this->imagePath); diff --git a/wcfsetup/install/files/lib/data/template/TemplateEditor.class.php b/wcfsetup/install/files/lib/data/template/TemplateEditor.class.php index 8a169e7d00..3e659b019b 100644 --- a/wcfsetup/install/files/lib/data/template/TemplateEditor.class.php +++ b/wcfsetup/install/files/lib/data/template/TemplateEditor.class.php @@ -1,5 +1,7 @@ write($source); $file->close(); - @$file->chmod(0777); + FileUtil::makeWritable($path); } /** diff --git a/wcfsetup/install/files/lib/system/io/Tar.class.php b/wcfsetup/install/files/lib/system/io/Tar.class.php index d59ccaeeb6..19b8a8ac3a 100644 --- a/wcfsetup/install/files/lib/system/io/Tar.class.php +++ b/wcfsetup/install/files/lib/system/io/Tar.class.php @@ -225,12 +225,7 @@ class Tar implements IArchive { $targetFile->write($buffer); $targetFile->close(); - if (FileUtil::isApacheModule() || !@$targetFile->is_writable()) { - @$targetFile->chmod(0777); - } - else { - @$targetFile->chmod(0755); - } + FileUtil::makeWritable($destination); if ($header['mtime']) { @$targetFile->touch($header['mtime']); diff --git a/wcfsetup/install/files/lib/system/io/Zip.class.php b/wcfsetup/install/files/lib/system/io/Zip.class.php index 18be9bfbcf..4509b1e571 100644 --- a/wcfsetup/install/files/lib/system/io/Zip.class.php +++ b/wcfsetup/install/files/lib/system/io/Zip.class.php @@ -6,8 +6,8 @@ use wcf\util\FileUtil; /** * Reads zip files. * - * @author Tim Düsterhus - * @copyright 2012 Tim Düsterhus + * @author Tim Duesterhus + * @copyright 2001-2013 WoltLab GmbH * @license GNU Lesser General Public License * @package com.woltlab.wcf * @subpackage system.io @@ -114,12 +114,7 @@ class Zip extends File implements IArchive { $targetFile->write($file['content'], strlen($file['content'])); $targetFile->close(); - if (FileUtil::isApacheModule() || !@$targetFile->is_writable()) { - @$targetFile->chmod(0777); - } - else { - @$targetFile->chmod(0755); - } + FileUtil::makeWritable($destination); if ($file['header']['mtime']) { @$targetFile->touch($file['header']['mtime']); diff --git a/wcfsetup/install/files/lib/system/package/PackageInstallationDispatcher.class.php b/wcfsetup/install/files/lib/system/package/PackageInstallationDispatcher.class.php index 83a05d9441..b815abf671 100644 --- a/wcfsetup/install/files/lib/system/package/PackageInstallationDispatcher.class.php +++ b/wcfsetup/install/files/lib/system/package/PackageInstallationDispatcher.class.php @@ -669,7 +669,7 @@ class PackageInstallationDispatcher { // create directory and set permissions @mkdir($packageDir, 0777, true); - @chmod($packageDir, 0777); + FileUtil::makeWritable($packageDir); } return null; diff --git a/wcfsetup/install/files/lib/system/setup/Installer.class.php b/wcfsetup/install/files/lib/system/setup/Installer.class.php index 3d56d8cad1..6f9b6ba527 100644 --- a/wcfsetup/install/files/lib/system/setup/Installer.class.php +++ b/wcfsetup/install/files/lib/system/setup/Installer.class.php @@ -9,7 +9,7 @@ use wcf\util\StringUtil; * Extracts files and directories from a tar archive. * * @author Marcel Werk - * @copyright 2001-2012 WoltLab GmbH + * @copyright 2001-2013 WoltLab GmbH * @license GNU Lesser General Public License * @package com.woltlab.wcf * @subpackage system.setup @@ -203,11 +203,6 @@ class Installer { * @param string $target */ protected function makeWriteable($target) { - if (!preg_match('/^WIN/i', PHP_OS)) { - if (!@chmod($target, 0777)) { - // todo: what to do in this case? - //throw new SystemException("Could not chmod file '".$target."'"); - } - } + FileUtil::makeWritable($target); } } diff --git a/wcfsetup/install/files/lib/util/FileUtil.class.php b/wcfsetup/install/files/lib/util/FileUtil.class.php index de5bff87cd..d1d49de604 100644 --- a/wcfsetup/install/files/lib/util/FileUtil.class.php +++ b/wcfsetup/install/files/lib/util/FileUtil.class.php @@ -34,7 +34,7 @@ final class FileUtil { // create tmp folder in document root automatically if (!@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp')) { @mkdir($_SERVER['DOCUMENT_ROOT'].'/tmp/', 0777); - @chmod($_SERVER['DOCUMENT_ROOT'].'/tmp/', 0777); + self::makeWritable($_SERVER['DOCUMENT_ROOT'].'/tmp/'); } } if (@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp') && @is_writable($_SERVER['DOCUMENT_ROOT'].'/tmp')) { @@ -183,10 +183,9 @@ final class FileUtil { * necessary. * * @param string $path - * @param integer $chmod * @return boolean */ - public static function makePath($path, $chmod = 0777) { + public static function makePath($path) { // directory already exists, abort if (file_exists($path)) { return false; @@ -200,24 +199,18 @@ final class FileUtil { $parent = self::addTrailingSlash($parent); if (!@file_exists($parent)) { // could not create parent directory either => abort - if (!self::makePath($parent, $chmod)) { + if (!self::makePath($parent)) { return false; } } // well, the parent directory exists or has been created // lets create this path - $oldumask = @umask(0); - if (!@mkdir($path, $chmod)) { + if (!@mkdir($path)) { return false; } - @umask($oldumask); - /*if (!@chmod($path, $chmod)) { - return false; - }*/ - if (self::isApacheModule() || !@is_writable($path)) { - @chmod($path, 0777); - } + + self::makeWritable($path); return true; } @@ -457,12 +450,8 @@ final class FileUtil { } $targetFile->close(); $sourceFile->close(); - @$targetFile->chmod(0777); - /*if ($filesize != filesize($destination)) { - @unlink($destination); - return false; - }*/ + self::makeWritable($destination); return true; } @@ -491,5 +480,36 @@ final class FileUtil { return self::$finfo->file($filename); } + /** + * Tries to make a file or directory writable. It starts of with the least + * permissions and goes up until 0777. + * + * @param string $filename + */ + public static function makeWritable($filename) { + if (is_writable($filename)) { + return; + } + + $chmods = array('0644', '0755', '0775', '0777'); + + $startIndex = 0; + if (is_dir($filename)) { + $startIndex = 1; + } + + for ($i = $startIndex; $i < 4; $i++) { + @chmod($filename, octdec($chmods[$i])); + + if (is_writable($filename)) { + break; + } + else if ($i == 3) { + // does not work with 0777 + throw new SystemException("Unable to make '".$filename."' writable. This is a misconfiguration of your server, please contact your system administrator or hosting provider."); + } + } + } + private function __construct() { } } -- 2.20.1