Merge branch 'master' into oc_api_tests

This commit is contained in:
tomneedham 2013-11-14 00:40:57 +00:00
commit 00944a376a
25 changed files with 531 additions and 217 deletions

View File

@ -660,19 +660,19 @@ var FileList={
$('.summary .filesize').html(humanFileSize(fileSummary.totalSize));
// Show only what's necessary (may be hidden)
if ($dirInfo.html().charAt(0) === "0") {
if (fileSummary.totalDirs === 0) {
$dirInfo.hide();
$connector.hide();
} else {
$dirInfo.show();
}
if ($fileInfo.html().charAt(0) === "0") {
if (fileSummary.totalFiles === 0) {
$fileInfo.hide();
$connector.hide();
} else {
$fileInfo.show();
}
if ($dirInfo.html().charAt(0) !== "0" && $fileInfo.html().charAt(0) !== "0") {
if (fileSummary.totalDirs > 0 && fileSummary.totalFiles > 0) {
$connector.show();
}
}

View File

@ -157,6 +157,49 @@ class Helper {
return $return;
}
/**
* @brief Check if a path is a .part file
* @param string $path Path that may identify a .part file
* @return bool
*/
public static function isPartialFilePath($path) {
$extension = pathinfo($path, PATHINFO_EXTENSION);
if ( $extension === 'part' || $extension === 'etmp') {
return true;
} else {
return false;
}
}
/**
* @brief Remove .path extension from a file path
* @param string $path Path that may identify a .part file
* @return string File path without .part extension
* @note this is needed for reusing keys
*/
public static function stripPartialFileExtension($path) {
$extension = pathinfo($path, PATHINFO_EXTENSION);
if ( $extension === 'part' || $extension === 'etmp') {
$newLength = strlen($path) - 5; // 5 = strlen(".part") = strlen(".etmp")
$fPath = substr($path, 0, $newLength);
// if path also contains a transaction id, we remove it too
$extension = pathinfo($fPath, PATHINFO_EXTENSION);
if(substr($extension, 0, 12) === 'ocTransferId') { // 12 = strlen("ocTransferId")
$newLength = strlen($fPath) - strlen($extension) -1;
$fPath = substr($fPath, 0, $newLength);
}
return $fPath;
} else {
return $path;
}
}
/**
* @brief disable recovery

View File

@ -152,10 +152,10 @@ class Keymanager {
}
// try reusing key file if part file
if (self::isPartialFilePath($targetPath)) {
if (Helper::isPartialFilePath($targetPath)) {
$result = $view->file_put_contents(
$basePath . '/' . self::fixPartialFilePath($targetPath) . '.key', $catfile);
$basePath . '/' . Helper::stripPartialFileExtension($targetPath) . '.key', $catfile);
} else {
@ -169,48 +169,6 @@ class Keymanager {
}
/**
* @brief Remove .path extension from a file path
* @param string $path Path that may identify a .part file
* @return string File path without .part extension
* @note this is needed for reusing keys
*/
public static function fixPartialFilePath($path) {
if (preg_match('/\.part$/', $path) || preg_match('/\.etmp$/', $path)) {
$newLength = strlen($path) - 5;
$fPath = substr($path, 0, $newLength);
return $fPath;
} else {
return $path;
}
}
/**
* @brief Check if a path is a .part file
* @param string $path Path that may identify a .part file
* @return bool
*/
public static function isPartialFilePath($path) {
if (preg_match('/\.part$/', $path) || preg_match('/\.etmp$/', $path)) {
return true;
} else {
return false;
}
}
/**
* @brief retrieve keyfile for an encrypted file
* @param \OC_FilesystemView $view
@ -226,7 +184,7 @@ class Keymanager {
$util = new Util($view, \OCP\User::getUser());
list($owner, $filename) = $util->getUidAndFilename($filePath);
$filename = self::fixPartialFilePath($filename);
$filename = Helper::stripPartialFileExtension($filename);
$filePath_f = ltrim($filename, '/');
// in case of system wide mount points the keys are stored directly in the data directory
@ -385,8 +343,8 @@ class Keymanager {
foreach ($shareKeys as $userId => $shareKey) {
// try reusing key file if part file
if (self::isPartialFilePath($shareKeyPath)) {
$writePath = $basePath . '/' . self::fixPartialFilePath($shareKeyPath) . '.' . $userId . '.shareKey';
if (Helper::isPartialFilePath($shareKeyPath)) {
$writePath = $basePath . '/' . Helper::stripPartialFileExtension($shareKeyPath) . '.' . $userId . '.shareKey';
} else {
$writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey';
}
@ -422,7 +380,7 @@ class Keymanager {
$util = new Util($view, \OCP\User::getUser());
list($owner, $filename) = $util->getUidAndFilename($filePath);
$filename = self::fixPartialFilePath($filename);
$filename = Helper::stripPartialFileExtension($filename);
// in case of system wide mount points the keys are stored directly in the data directory
if ($util->isSystemWideMountPoint($filename)) {
$shareKeyPath = '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey';

View File

@ -342,7 +342,7 @@ class Proxy extends \OC_FileProxy {
$fileInfo = false;
// get file info from database/cache if not .part file
if (!Keymanager::isPartialFilePath($path)) {
if (!Helper::isPartialFilePath($path)) {
$fileInfo = $view->getFileInfo($path);
}
@ -353,7 +353,7 @@ class Proxy extends \OC_FileProxy {
$fixSize = $util->getFileSize($path);
$fileInfo['unencrypted_size'] = $fixSize;
// put file info if not .part file
if (!Keymanager::isPartialFilePath($relativePath)) {
if (!Helper::isPartialFilePath($relativePath)) {
$view->putFileInfo($path, $fileInfo);
}
}
@ -372,7 +372,7 @@ class Proxy extends \OC_FileProxy {
$fileInfo['unencrypted_size'] = $size;
// put file info if not .part file
if (!Keymanager::isPartialFilePath($relativePath)) {
if (!Helper::isPartialFilePath($relativePath)) {
$view->putFileInfo($path, $fileInfo);
}
}

View File

@ -1145,10 +1145,7 @@ class Util {
// Make sure that a share key is generated for the owner too
list($owner, $ownerPath) = $this->getUidAndFilename($filePath);
$pathinfo = pathinfo($ownerPath);
if(array_key_exists('extension', $pathinfo) && $pathinfo['extension'] === 'part') {
$ownerPath = $pathinfo['dirname'] . '/' . $pathinfo['filename'];
}
$ownerPath = \OCA\Encryption\Helper::stripPartialFileExtension($ownerPath);
$userIds = array();
if ($sharingEnabled) {

View File

@ -0,0 +1,54 @@
<?php
/**
* Copyright (c) 2013 Bjoern Schiessle <schiessle@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
require_once __DIR__ . '/../lib/helper.php';
use OCA\Encryption;
/**
* Class Test_Encryption_Helper
*/
class Test_Encryption_Helper extends \PHPUnit_Framework_TestCase {
/**
* @medium
*/
function testStripPartialFileExtension() {
$partFilename = 'testfile.txt.part';
$filename = 'testfile.txt';
$this->assertTrue(Encryption\Helper::isPartialFilePath($partFilename));
$this->assertEquals('testfile.txt', Encryption\Helper::stripPartialFileExtension($partFilename));
$this->assertFalse(Encryption\Helper::isPartialFilePath($filename));
$this->assertEquals('testfile.txt', Encryption\Helper::stripPartialFileExtension($filename));
}
/**
* @medium
*/
function testStripPartialFileExtensionWithTransferIdPath() {
$partFilename = 'testfile.txt.ocTransferId643653835.part';
$filename = 'testfile.txt';
$this->assertTrue(Encryption\Helper::isPartialFilePath($partFilename));
$this->assertEquals('testfile.txt', Encryption\Helper::stripPartialFileExtension($partFilename));
$this->assertFalse(Encryption\Helper::isPartialFilePath($filename));
$this->assertEquals('testfile.txt', Encryption\Helper::stripPartialFileExtension($filename));
}
}

View File

@ -188,23 +188,6 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
$this->assertArrayHasKey('key', $sslInfoPrivate);
}
/**
* @medium
*/
function testFixPartialFilePath() {
$partFilename = 'testfile.txt.part';
$filename = 'testfile.txt';
$this->assertTrue(Encryption\Keymanager::isPartialFilePath($partFilename));
$this->assertEquals('testfile.txt', Encryption\Keymanager::fixPartialFilePath($partFilename));
$this->assertFalse(Encryption\Keymanager::isPartialFilePath($filename));
$this->assertEquals('testfile.txt', Encryption\Keymanager::fixPartialFilePath($filename));
}
/**
* @medium
*/

View File

@ -18,3 +18,7 @@ tr:hover>td.remove>img { visibility:visible; cursor:pointer; }
#addMountPoint>td { border:none; }
#addMountPoint>td.applicable { visibility:hidden; }
#selectBackend { margin-left:-10px; }
#externalStorage label > input[type="checkbox"] {
margin-right: 3px;
}

View File

@ -34,15 +34,15 @@ class Shared extends \OC\Files\Storage\Common {
$this->sharedFolder = $arguments['sharedFolder'];
}
public function getId(){
public function getId() {
return 'shared::' . $this->sharedFolder;
}
/**
* @brief Get the source file path, permissions, and owner for a shared file
* @param string Shared target file path
* @return Returns array with the keys path, permissions, and owner or false if not found
*/
* @brief Get the source file path, permissions, and owner for a shared file
* @param string Shared target file path
* @return Returns array with the keys path, permissions, and owner or false if not found
*/
public function getFile($target) {
if (!isset($this->files[$target])) {
// Check for partial files
@ -62,10 +62,10 @@ class Shared extends \OC\Files\Storage\Common {
}
/**
* @brief Get the source file path for a shared file
* @param string Shared target file path
* @return string source file path or false if not found
*/
* @brief Get the source file path for a shared file
* @param string Shared target file path
* @return string source file path or false if not found
*/
public function getSourcePath($target) {
$source = $this->getFile($target);
if ($source) {
@ -73,7 +73,7 @@ class Shared extends \OC\Files\Storage\Common {
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
$mount = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
if (is_array($mount)) {
$this->files[$target]['fullPath'] = $mount[key($mount)]->getMountPoint().$source['path'];
$this->files[$target]['fullPath'] = $mount[key($mount)]->getMountPoint() . $source['path'];
} else {
$this->files[$target]['fullPath'] = false;
}
@ -84,10 +84,10 @@ class Shared extends \OC\Files\Storage\Common {
}
/**
* @brief Get the permissions granted for a shared file
* @param string Shared target file path
* @return int CRUDS permissions granted or false if not found
*/
* @brief Get the permissions granted for a shared file
* @param string Shared target file path
* @return int CRUDS permissions granted or false if not found
*/
public function getPermissions($target) {
$source = $this->getFile($target);
if ($source) {
@ -222,7 +222,7 @@ class Shared extends \OC\Files\Storage\Common {
if ($path == '' || $path == '/') {
$mtime = 0;
$dh = $this->opendir($path);
if(is_resource($dh)) {
if (is_resource($dh)) {
while (($filename = readdir($dh)) !== false) {
$tempmtime = $this->filemtime($filename);
if ($tempmtime > $mtime) {
@ -244,7 +244,7 @@ class Shared extends \OC\Files\Storage\Common {
$source = $this->getSourcePath($path);
if ($source) {
$info = array(
'target' => $this->sharedFolder.$path,
'target' => $this->sharedFolder . $path,
'source' => $source,
);
\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_get_contents', $info);
@ -257,13 +257,14 @@ class Shared extends \OC\Files\Storage\Common {
if ($source = $this->getSourcePath($path)) {
// Check if permission is granted
if (($this->file_exists($path) && !$this->isUpdatable($path))
|| ($this->is_dir($path) && !$this->isCreatable($path))) {
|| ($this->is_dir($path) && !$this->isCreatable($path))
) {
return false;
}
$info = array(
'target' => $this->sharedFolder.$path,
'source' => $source,
);
'target' => $this->sharedFolder . $path,
'source' => $source,
);
\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_put_contents', $info);
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
$result = $storage->file_put_contents($internalPath, $data);
@ -304,31 +305,16 @@ class Shared extends \OC\Files\Storage\Common {
$pos1 = strpos($path1, '/', 1);
$pos2 = strpos($path2, '/', 1);
if ($pos1 !== false && $pos2 !== false && ($oldSource = $this->getSourcePath($path1))) {
$newSource = $this->getSourcePath(dirname($path2)).'/'.basename($path2);
if (dirname($path1) == dirname($path2)) {
// Rename the file if UPDATE permission is granted
if ($this->isUpdatable($path1)) {
list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource);
list( , $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource);
return $storage->rename($oldInternalPath, $newInternalPath);
}
} else {
// Move the file if DELETE and CREATE permissions are granted
if ($this->isDeletable($path1) && $this->isCreatable(dirname($path2))) {
// Get the root shared folder
$folder1 = substr($path1, 0, $pos1);
$folder2 = substr($path2, 0, $pos2);
// Copy and unlink the file if it exists in a different shared folder
if ($folder1 != $folder2) {
if ($this->copy($path1, $path2)) {
return $this->unlink($path1);
}
} else {
list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource);
list( , $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource);
return $storage->rename($oldInternalPath, $newInternalPath);
}
}
$newSource = $this->getSourcePath(dirname($path2)) . '/' . basename($path2);
// Within the same folder, we only need UPDATE permissions
if (dirname($path1) == dirname($path2) and $this->isUpdatable($path1)) {
list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource);
list(, $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource);
return $storage->rename($oldInternalPath, $newInternalPath);
// otherwise DELETE and CREATE permissions required
} elseif ($this->isDeletable($path1) && $this->isCreatable(dirname($path2))) {
$rootView = new \OC\Files\View('');
return $rootView->rename($oldSource, $newSource);
}
}
}
@ -338,10 +324,10 @@ class Shared extends \OC\Files\Storage\Common {
public function copy($path1, $path2) {
// Copy the file if CREATE permission is granted
if ($this->isCreatable(dirname($path2))) {
$source = $this->fopen($path1, 'r');
$target = $this->fopen($path2, 'w');
list ($count, $result) = \OC_Helper::streamCopy($source, $target);
return $result;
$oldSource = $this->getSourcePath($path1);
$newSource = $this->getSourcePath(dirname($path2)) . '/' . basename($path2);
$rootView = new \OC\Files\View('');
return $rootView->copy($oldSource, $newSource);
}
return false;
}
@ -363,16 +349,16 @@ class Shared extends \OC\Files\Storage\Common {
case 'xb':
case 'a':
case 'ab':
$exists = $this->file_exists($path);
if ($exists && !$this->isUpdatable($path)) {
return false;
}
if (!$exists && !$this->isCreatable(dirname($path))) {
return false;
}
$exists = $this->file_exists($path);
if ($exists && !$this->isUpdatable($path)) {
return false;
}
if (!$exists && !$this->isCreatable(dirname($path))) {
return false;
}
}
$info = array(
'target' => $this->sharedFolder.$path,
'target' => $this->sharedFolder . $path,
'source' => $source,
'mode' => $mode,
);
@ -412,6 +398,7 @@ class Shared extends \OC\Files\Storage\Common {
}
return false;
}
public function touch($path, $mtime = null) {
if ($source = $this->getSourcePath($path)) {
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
@ -422,11 +409,12 @@ class Shared extends \OC\Files\Storage\Common {
public static function setup($options) {
if (!\OCP\User::isLoggedIn() || \OCP\User::getUser() != $options['user']
|| \OCP\Share::getItemsSharedWith('file')) {
|| \OCP\Share::getItemsSharedWith('file')
) {
$user_dir = $options['user_dir'];
\OC\Files\Filesystem::mount('\OC\Files\Storage\Shared',
array('sharedFolder' => '/Shared'),
$user_dir.'/Shared/');
$user_dir . '/Shared/');
}
}

View File

@ -3,13 +3,9 @@
width: 60%;
}
.tablecell {
display: table-cell !important;
white-space: nowrap;
}
.tablerow {
display: table-row;
white-space: nowrap;
}
.tablerow input, .tablerow textarea {
@ -78,6 +74,7 @@
.wizSpinner {
height: 15px;
margin: 0.3em;
}
.ldapSettingControls {
@ -100,7 +97,6 @@
#ldap fieldset input, #ldap fieldset textarea {
width: 60%;
display: inline-block;
}
#ldap fieldset p input[type=checkbox] {

View File

@ -192,19 +192,20 @@ var LdapWizard = {
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
LdapWizard.showSpinner('#ldap_base');
$('#ldap_base').prop('disabled', 'disabled');
LdapWizard.ajax(param,
function(result) {
LdapWizard.applyChanges(result);
LdapWizard.hideSpinner('#ldap_base');
if($('#ldap_base').val()) {
$('#ldap_base').removeClass('invisible');
LdapWizard.hideInfoBox();
}
$('#ldap_base').prop('disabled', false);
},
function (result) {
LdapWizard.hideSpinner('#ldap_base');
$('#ldap_base').removeClass('invisible');
LdapWizard.showInfoBox('Please specify a port');
LdapWizard.showInfoBox('Please specify a Base DN');
$('#ldap_base').prop('disabled', false);
}
);
}
@ -212,28 +213,28 @@ var LdapWizard = {
checkPort: function() {
host = $('#ldap_host').val();
user = $('#ldap_dn').val();
pass = $('#ldap_agent_password').val();
port = $('#ldap_port').val();
if(host && user && pass) {
if(host && !port) {
param = 'action=guessPortAndTLS'+
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
LdapWizard.showSpinner('#ldap_port');
$('#ldap_port').prop('disabled', 'disabled');
LdapWizard.ajax(param,
function(result) {
LdapWizard.applyChanges(result);
LdapWizard.hideSpinner('#ldap_port');
if($('#ldap_port').val()) {
LdapWizard.checkBaseDN();
$('#ldap_port').removeClass('invisible');
$('#ldap_port').prop('disabled', false);
LdapWizard.hideInfoBox();
}
},
function (result) {
LdapWizard.hideSpinner('#ldap_port');
$('#ldap_port').removeClass('invisible');
LdapWizard.showInfoBox('Please specify the BaseDN');
$('#ldap_port').prop('disabled', false);
LdapWizard.showInfoBox('Please specify the Port');
}
);
}
@ -461,12 +462,6 @@ var LdapWizard = {
},
init: function() {
if($('#ldap_port').val()) {
$('#ldap_port').removeClass('invisible');
}
if($('#ldap_base').val()) {
$('#ldap_base').removeClass('invisible');
}
LdapWizard.basicStatusCheck();
},
@ -521,6 +516,8 @@ var LdapWizard = {
},
processChanges: function(triggerObj) {
LdapWizard.hideInfoBox();
if(triggerObj.id == 'ldap_host'
|| triggerObj.id == 'ldap_port'
|| triggerObj.id == 'ldap_dn'

View File

@ -63,8 +63,6 @@ class Wizard extends LDAPUtility {
public function countGroups() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapBase',
))) {
return false;
@ -98,8 +96,6 @@ class Wizard extends LDAPUtility {
public function countUsers() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapBase',
'ldapUserFilter',
))) {
@ -130,8 +126,6 @@ class Wizard extends LDAPUtility {
public function determineAttributes() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapBase',
'ldapUserFilter',
))) {
@ -160,8 +154,6 @@ class Wizard extends LDAPUtility {
private function getUserAttributes() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapBase',
'ldapUserFilter',
))) {
@ -214,8 +206,6 @@ class Wizard extends LDAPUtility {
private function determineGroups($dbkey, $confkey, $testMemberOf = true) {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapBase',
))) {
return false;
@ -242,8 +232,6 @@ class Wizard extends LDAPUtility {
public function determineGroupMemberAssoc() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapGroupFilter',
))) {
return false;
@ -266,8 +254,6 @@ class Wizard extends LDAPUtility {
public function determineGroupObjectClasses() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapBase',
))) {
return false;
@ -294,8 +280,6 @@ class Wizard extends LDAPUtility {
public function determineUserObjectClasses() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapBase',
))) {
return false;
@ -322,8 +306,6 @@ class Wizard extends LDAPUtility {
public function getGroupFilter() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapBase',
))) {
return false;
@ -337,8 +319,6 @@ class Wizard extends LDAPUtility {
public function getUserListFilter() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapBase',
))) {
return false;
@ -355,13 +335,12 @@ class Wizard extends LDAPUtility {
public function getUserLoginFilter() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapAgentName',
'ldapAgentPassword',
'ldapBase',
'ldapUserFilter',
))) {
return false;
}
$filter = $this->composeLdapFilter(self::LFILTER_LOGIN);
if(!$filter) {
throw new \Exception('Cannot create filter');
@ -377,8 +356,6 @@ class Wizard extends LDAPUtility {
*/
public function guessPortAndTLS() {
if(!$this->checkRequirements(array('ldapHost',
'ldapAgentName',
'ldapAgentPassword'
))) {
return false;
}
@ -418,8 +395,6 @@ class Wizard extends LDAPUtility {
*/
public function guessBaseDN() {
if(!$this->checkRequirements(array('ldapHost',
'ldapAgentName',
'ldapAgentPassword',
'ldapPort',
))) {
return false;
@ -799,7 +774,22 @@ class Wizard extends LDAPUtility {
throw new \Exception($error);
}
/**
* @brief checks whether a valid combination of agent and password has been
* provided (either two values or nothing for anonymous connect)
* @return boolean, true if everything is fine, false otherwise
*
*/
private function checkAgentRequirements() {
$agent = $this->configuration->ldapAgentName;
$pwd = $this->configuration->ldapAgentPassword;
return ( (!empty($agent) && !empty($pwd))
|| (empty($agent) && empty($pwd)));
}
private function checkRequirements($reqs) {
$this->checkAgentRequirements();
foreach($reqs as $option) {
$value = $this->configuration->$option;
if(empty($value)) {
@ -1005,9 +995,9 @@ class Wizard extends LDAPUtility {
//In case the port is already provided, we will check this first
if($port > 0) {
$hostInfo = parse_url($host);
if(is_array($hostInfo)
if(!(is_array($hostInfo)
&& isset($hostInfo['scheme'])
&& stripos($hostInfo['scheme'], 'ldaps') === false) {
&& stripos($hostInfo['scheme'], 'ldaps') !== false)) {
$portSettings[] = array('port' => $port, 'tls' => true);
}
$portSettings[] =array('port' => $port, 'tls' => false);

View File

@ -32,7 +32,7 @@
/>
<span>
<input type="number" id="ldap_port" name="ldap_port"
class="invisible lwautosave"
class="lwautosave"
placeholder="<?php p($l->t('Port'));?>" />
</span>
</div>
@ -56,7 +56,7 @@
<div class="tablerow">
<textarea id="ldap_base" name="ldap_base"
class="tablecell invisible lwautosave"
class="tablecell lwautosave"
placeholder="<?php p($l->t('One Base DN per line'));?>"
title="<?php p($l->t('You can specify Base DN for users and groups in the Advanced tab'));?>">
</textarea>

View File

@ -20,8 +20,7 @@
<h3><?php p($l->t('Connection Settings'));?></h3>
<div>
<p><label for="ldap_configuration_active"><?php p($l->t('Configuration Active'));?></label><input type="checkbox" id="ldap_configuration_active" name="ldap_configuration_active" value="1" data-default="<?php p($_['ldap_configuration_active_default']); ?>" title="<?php p($l->t('When unchecked, this configuration will be skipped.'));?>" /></p>
<p><label for="ldap_login_filter"><?php p($l->t('User Login Filter'));?></label>
<input type="text" id="ldap_login_filter" name="ldap_login_filter"
<p><label for="ldap_login_filter"><?php p($l->t('User Login Filter'));?></label><input type="text" id="ldap_login_filter" name="ldap_login_filter"
data-default="<?php p($_['ldap_login_filter_default']); ?>"
title="<?php p($l->t('Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: "uid=%%uid"'));?>" /></p>
<p><label for="ldap_backup_host"><?php p($l->t('Backup (Replica) Host'));?></label><input type="text" id="ldap_backup_host" name="ldap_backup_host" data-default="<?php p($_['ldap_backup_host_default']); ?>" title="<?php p($l->t('Give an optional backup host. It must be a replica of the main LDAP/AD server.'));?>"></p>

View File

@ -230,9 +230,31 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
}
if ($chunk_handler->isComplete()) {
$newPath = $path . '/' . $info['name'];
$chunk_handler->file_assemble($newPath);
return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath);
// we first assembly the target file as a part file
$partFile = $path . '/' . $info['name'] . '.ocTransferId' . $info['transferid'] . '.part';
$chunk_handler->file_assemble($partFile);
// here is the final atomic rename
$fs = $this->getFS();
$targetPath = $path . '/' . $info['name'];
$renameOkay = $fs->rename($partFile, $targetPath);
$fileExists = $fs->file_exists($targetPath);
if ($renameOkay === false || $fileExists === false) {
\OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR);
$fs->unlink($targetPath);
throw new Sabre_DAV_Exception();
}
// allow sync clients to send the mtime along in a header
$mtime = OC_Request::hasModificationTime();
if ($mtime !== false) {
if($fs->touch($this->path, $mtime)) {
header('X-OC-MTime: accepted');
}
}
return OC_Connector_Sabre_Node::getETagPropertyForPath($targetPath);
}
return null;

40
lib/private/files/cache/homecache.php vendored Normal file
View File

@ -0,0 +1,40 @@
<?php
/**
* Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Files\Cache;
class HomeCache extends Cache {
/**
* get the size of a folder and set it in the cache
*
* @param string $path
* @return int
*/
public function calculateFolderSize($path) {
if ($path !== '/' and $path !== '') {
return parent::calculateFolderSize($path);
}
$totalSize = 0;
$entry = $this->get($path);
if ($entry && $entry['mimetype'] === 'httpd/unix-directory') {
$id = $entry['fileid'];
$sql = 'SELECT SUM(`size`) FROM `*PREFIX*filecache` ' .
'WHERE `parent` = ? AND `storage` = ? AND `size` >= 0';
$result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId()));
if ($row = $result->fetchRow()) {
list($sum) = array_values($row);
$totalSize = (int)$sum;
if ($entry['size'] !== $totalSize) {
$this->update($id, array('size' => $totalSize));
}
}
}
return $totalSize;
}
}

View File

@ -307,10 +307,18 @@ class Filesystem {
$root = \OC_User::getHome($user);
$userObject = \OC_User::getManager()->get($user);
if (\OC\Files\Cache\Storage::exists('local::' . $root . '/') or is_null($userObject)) {
if (!is_null($userObject)) {
// check for legacy home id (<= 5.0.12)
if (\OC\Files\Cache\Storage::exists('local::' . $root . '/')) {
self::mount('\OC\Files\Storage\Home', array('user' => $userObject, 'legacy' => true), $user);
}
else {
self::mount('\OC\Files\Storage\Home', array('user' => $userObject), $user);
}
}
else {
self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user);
} else {
self::mount('\OC\Files\Storage\Home', array('user' => $userObject), $user);
}
$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");

View File

@ -21,11 +21,11 @@ namespace OC\Files\Storage;
*/
abstract class Common implements \OC\Files\Storage\Storage {
private $cache;
private $scanner;
private $permissioncache;
private $watcher;
private $storageCache;
protected $cache;
protected $scanner;
protected $permissioncache;
protected $watcher;
protected $storageCache;
public function __construct($parameters) {
}

View File

@ -12,6 +12,11 @@ namespace OC\Files\Storage;
* Specialized version of Local storage for home directory usage
*/
class Home extends Local {
/**
* @var string
*/
protected $id;
/**
* @var \OC\User\User $user
*/
@ -20,11 +25,25 @@ class Home extends Local {
public function __construct($arguments) {
$this->user = $arguments['user'];
$datadir = $this->user->getHome();
if (isset($arguments['legacy']) && $arguments['legacy']) {
// legacy home id (<= 5.0.12)
$this->id = 'local::' . $datadir . '/';
}
else {
$this->id = 'home::' . $this->user->getUID();
}
parent::__construct(array('datadir' => $datadir));
}
public function getId() {
return 'home::' . $this->user->getUID();
return $this->id;
}
public function getCache($path = '') {
if (!isset($this->cache)) {
$this->cache = new \OC\Files\Cache\HomeCache($this);
}
return $this->cache;
}
}

View File

@ -12,6 +12,11 @@ input#openid, input#webdav { width:20em; }
display: block;
}
.personalblock input[type="checkbox"] {
position: relative;
top: 2px;
}
/* Sync clients */
.clientsbox { margin:12px; }
.clientsbox h1 { font-size:40px; font-weight:bold; margin:50px 0 20px; }

View File

@ -18,11 +18,11 @@ class LongId extends \OC\Files\Storage\Temporary {
class Cache extends \PHPUnit_Framework_TestCase {
/**
* @var \OC\Files\Storage\Temporary $storage;
* @var \OC\Files\Storage\Temporary $storage ;
*/
private $storage;
/**
* @var \OC\Files\Storage\Temporary $storage2;
* @var \OC\Files\Storage\Temporary $storage2 ;
*/
private $storage2;
@ -137,6 +137,33 @@ class Cache extends \PHPUnit_Framework_TestCase {
$this->assertFalse($this->cache->inCache('folder/bar'));
}
public function testRootFolderSizeForNonHomeStorage() {
$dir1 = 'knownsize';
$dir2 = 'unknownsize';
$fileData = array();
$fileData[''] = array('size' => -1, 'mtime' => 20, 'mimetype' => 'httpd/unix-directory');
$fileData[$dir1] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'httpd/unix-directory');
$fileData[$dir2] = array('size' => -1, 'mtime' => 25, 'mimetype' => 'httpd/unix-directory');
$this->cache->put('', $fileData['']);
$this->cache->put($dir1, $fileData[$dir1]);
$this->cache->put($dir2, $fileData[$dir2]);
$this->assertTrue($this->cache->inCache($dir1));
$this->assertTrue($this->cache->inCache($dir2));
// check that root size ignored the unknown sizes
$this->assertEquals(-1, $this->cache->calculateFolderSize(''));
// clean up
$this->cache->remove('');
$this->cache->remove($dir1);
$this->cache->remove($dir2);
$this->assertFalse($this->cache->inCache($dir1));
$this->assertFalse($this->cache->inCache($dir2));
}
function testStatus() {
$this->assertEquals(\OC\Files\Cache\Cache::NOT_FOUND, $this->cache->getStatus('foo'));
$this->cache->put('foo', array('size' => -1));
@ -247,14 +274,14 @@ class Cache extends \PHPUnit_Framework_TestCase {
$data = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file');
$this->cache->put('foo', $data);
$cachedData = $this->cache->get('foo');
$this->assertEquals($data['mtime'], $cachedData['storage_mtime']);//if no storage_mtime is saved, mtime should be used
$this->assertEquals($data['mtime'], $cachedData['storage_mtime']); //if no storage_mtime is saved, mtime should be used
$this->cache->put('foo', array('storage_mtime' => 30));//when setting storage_mtime, mtime is also set
$this->cache->put('foo', array('storage_mtime' => 30)); //when setting storage_mtime, mtime is also set
$cachedData = $this->cache->get('foo');
$this->assertEquals(30, $cachedData['storage_mtime']);
$this->assertEquals(30, $cachedData['mtime']);
$this->cache->put('foo', array('mtime' => 25));//setting mtime does not change storage_mtime
$this->cache->put('foo', array('mtime' => 25)); //setting mtime does not change storage_mtime
$cachedData = $this->cache->get('foo');
$this->assertEquals(30, $cachedData['storage_mtime']);
$this->assertEquals(25, $cachedData['mtime']);
@ -295,18 +322,18 @@ class Cache extends \PHPUnit_Framework_TestCase {
$this->assertGreaterThan(0, $cacheMock->put('folder', $data));
// put un-normalized folder
$this->assertFalse($cacheMock->get('folder/' .$folderWith0308));
$this->assertGreaterThan(0, $cacheMock->put('folder/' .$folderWith0308, $data));
$this->assertFalse($cacheMock->get('folder/' . $folderWith0308));
$this->assertGreaterThan(0, $cacheMock->put('folder/' . $folderWith0308, $data));
// get un-normalized folder by name
$unNormalizedFolderName = $cacheMock->get('folder/' .$folderWith0308);
$unNormalizedFolderName = $cacheMock->get('folder/' . $folderWith0308);
// check if database layer normalized the folder name (this should not happen)
$this->assertEquals($folderWith0308, $unNormalizedFolderName['name']);
// put normalized folder
$this->assertFalse($cacheMock->get('folder/' . $folderWith00F6));
$this->assertGreaterThan(0, $cacheMock->put('folder/' .$folderWith00F6, $data));
$this->assertGreaterThan(0, $cacheMock->put('folder/' . $folderWith00F6, $data));
// this is our bug, we have two different hashes with the same name (Schön)
$this->assertEquals(2, count($cacheMock->getFolderContents('folder')));
@ -317,7 +344,7 @@ class Cache extends \PHPUnit_Framework_TestCase {
*/
public function testWithNormalizer() {
if(!class_exists('Patchwork\PHP\Shim\Normalizer')) {
if (!class_exists('Patchwork\PHP\Shim\Normalizer')) {
$this->markTestSkipped('The 3rdparty Normalizer extension is not available.');
return;
}
@ -335,18 +362,18 @@ class Cache extends \PHPUnit_Framework_TestCase {
$this->assertGreaterThan(0, $this->cache->put('folder', $data));
// put un-normalized folder
$this->assertFalse($this->cache->get('folder/' .$folderWith0308));
$this->assertGreaterThan(0, $this->cache->put('folder/' .$folderWith0308, $data));
$this->assertFalse($this->cache->get('folder/' . $folderWith0308));
$this->assertGreaterThan(0, $this->cache->put('folder/' . $folderWith0308, $data));
// get un-normalized folder by name
$unNormalizedFolderName = $this->cache->get('folder/' .$folderWith0308);
$unNormalizedFolderName = $this->cache->get('folder/' . $folderWith0308);
// check if folder name was normalized
$this->assertEquals($folderWith00F6, $unNormalizedFolderName['name']);
// put normalized folder
$this->assertTrue(is_array($this->cache->get('folder/' . $folderWith00F6)));
$this->assertGreaterThan(0, $this->cache->put('folder/' .$folderWith00F6, $data));
$this->assertGreaterThan(0, $this->cache->put('folder/' . $folderWith00F6, $data));
// at this point we should have only one folder named "Schön"
$this->assertEquals(1, count($this->cache->getFolderContents('folder')));

95
tests/lib/files/cache/homecache.php vendored Normal file
View File

@ -0,0 +1,95 @@
<?php
/**
* Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace Test\Files\Cache;
class DummyUser extends \OC\User\User {
/**
* @var string $home
*/
private $home;
/**
* @var string $uid
*/
private $uid;
public function __construct($uid, $home) {
$this->home = $home;
$this->uid = $uid;
}
/**
* @return string
*/
public function getHome() {
return $this->home;
}
/**
* @return string
*/
public function getUID() {
return $this->uid;
}
}
class HomeCache extends \PHPUnit_Framework_TestCase {
/**
* @var \OC\Files\Storage\Home $storage
*/
private $storage;
/**
* @var \OC\Files\Cache\HomeCache $cache
*/
private $cache;
/**
* @var \OC\User\User $user
*/
private $user;
public function setUp() {
$this->user = new DummyUser('foo', \OC_Helper::tmpFolder());
$this->storage = new \OC\Files\Storage\Home(array('user' => $this->user));
$this->cache = $this->storage->getCache();
}
/**
* Tests that the root folder size calculation ignores the subdirs that have an unknown
* size. This makes sure that quota calculation still works as it's based on the root
* folder size.
*/
public function testRootFolderSizeIgnoresUnknownUpdate() {
$dir1 = 'knownsize';
$dir2 = 'unknownsize';
$fileData = array();
$fileData[''] = array('size' => -1, 'mtime' => 20, 'mimetype' => 'httpd/unix-directory');
$fileData[$dir1] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'httpd/unix-directory');
$fileData[$dir2] = array('size' => -1, 'mtime' => 25, 'mimetype' => 'httpd/unix-directory');
$this->cache->put('', $fileData['']);
$this->cache->put($dir1, $fileData[$dir1]);
$this->cache->put($dir2, $fileData[$dir2]);
$this->assertTrue($this->cache->inCache($dir1));
$this->assertTrue($this->cache->inCache($dir2));
// check that root size ignored the unknown sizes
$this->assertEquals(1000, $this->cache->calculateFolderSize(''));
// clean up
$this->cache->remove('');
$this->cache->remove($dir1);
$this->cache->remove($dir2);
$this->assertFalse($this->cache->inCache($dir1));
$this->assertFalse($this->cache->inCache($dir2));
}
}

View File

@ -41,9 +41,12 @@ class Filesystem extends \PHPUnit_Framework_TestCase {
foreach ($this->tmpDirs as $dir) {
\OC_Helper::rmdirr($dir);
}
\OC\Files\Filesystem::clearMounts();
\OC_User::setUserId('');
}
public function setUp() {
\OC_User::setUserId('');
\OC\Files\Filesystem::clearMounts();
}
@ -103,6 +106,67 @@ class Filesystem extends \PHPUnit_Framework_TestCase {
// \OC\Files\Filesystem::file_put_contents('/bar//foo', $fh);
}
/**
* Tests that a local storage mount is used when passed user
* does not exist.
*/
public function testLocalMountWhenUserDoesNotExist() {
$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
$userId = uniqid('user_');
\OC\Files\Filesystem::initMountPoints($userId);
$homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
$this->assertInstanceOf('\OC\Files\Storage\Local', $homeMount);
$this->assertEquals('local::' . $datadir . '/' . $userId . '/', $homeMount->getId());
}
/**
* Tests that the home storage is used for the user's mount point
*/
public function testHomeMount() {
$userId = uniqid('user_');
\OC_User::createUser($userId, $userId);
\OC\Files\Filesystem::initMountPoints($userId);
$homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
$this->assertInstanceOf('\OC\Files\Storage\Home', $homeMount);
$this->assertEquals('home::' . $userId, $homeMount->getId());
\OC_User::deleteUser($userId);
}
/**
* Tests that the home storage is used in legacy mode
* for the user's mount point
*/
public function testLegacyHomeMount() {
$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
$userId = uniqid('user_');
// insert storage into DB by constructing it
// to make initMountsPoint find its existence
$localStorage = new \OC\Files\Storage\Local(array('datadir' => $datadir . '/' . $userId . '/'));
// this will trigger the insert
$cache = $localStorage->getCache();
\OC_User::createUser($userId, $userId);
\OC\Files\Filesystem::initMountPoints($userId);
$homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
$this->assertInstanceOf('\OC\Files\Storage\Home', $homeMount);
$this->assertEquals('local::' . $datadir. '/' . $userId . '/', $homeMount->getId());
\OC_User::deleteUser($userId);
// delete storage entry
$cache->clear();
}
public function dummyHook($arguments) {
$path = $arguments['path'];
$this->assertEquals($path, \OC\Files\Filesystem::normalizePath($path)); //the path passed to the hook should already be normalized

View File

@ -56,8 +56,8 @@ class Home extends Storage {
public function setUp() {
$this->tmpDir = \OC_Helper::tmpFolder();
$userId = uniqid('user_');
$this->user = new DummyUser($userId, $this->tmpDir);
$this->userId = uniqid('user_');
$this->user = new DummyUser($this->userId, $this->tmpDir);
$this->instance = new \OC\Files\Storage\Home(array('user' => $this->user));
}
@ -65,7 +65,32 @@ class Home extends Storage {
\OC_Helper::rmdirr($this->tmpDir);
}
/**
* Tests that the root path matches the data dir
*/
public function testRoot() {
$this->assertEquals($this->tmpDir, $this->instance->getLocalFolder(''));
}
/**
* Tests that the home id is in the format home::user1
*/
public function testId() {
$this->assertEquals('home::' . $this->userId, $this->instance->getId());
}
/**
* Tests that the legacy home id is in the format local::/path/to/datadir/user1/
*/
public function testLegacyId() {
$this->instance = new \OC\Files\Storage\Home(array('user' => $this->user, 'legacy' => true));
$this->assertEquals('local::' . $this->tmpDir . '/', $this->instance->getId());
}
/**
* Tests that getCache() returns an instance of HomeCache
*/
public function testGetCacheReturnsHomeCache() {
$this->assertInstanceOf('\OC\Files\Cache\HomeCache', $this->instance->getCache());
}
}

View File

@ -1,10 +1,10 @@
<?php
// We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel when updating major/minor version number.
$OC_Version=array(6, 00, 0, 5);
$OC_Version=array(6, 00, 0, 6);
// The human readable string
$OC_VersionString='6.0 beta 3';
$OC_VersionString='6.0 beta 4';
// The ownCloud edition
$OC_Edition='';