aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/Files/View.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Files/View.php')
-rw-r--r--lib/private/Files/View.php152
1 files changed, 110 insertions, 42 deletions
diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php
index e97cd75251d..63eecf5e1d6 100644
--- a/lib/private/Files/View.php
+++ b/lib/private/Files/View.php
@@ -10,12 +10,14 @@ namespace OC\Files;
use Icewind\Streams\CallbackWrapper;
use OC\Files\Mount\MoveableMount;
use OC\Files\Storage\Storage;
+use OC\Files\Storage\Wrapper\Quota;
use OC\Share\Share;
use OC\User\LazyUser;
use OC\User\Manager as UserManager;
use OC\User\User;
use OCA\Files_Sharing\SharedMount;
use OCP\Constants;
+use OCP\Files;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\ConnectionLostException;
use OCP\Files\EmptyFileNameException;
@@ -24,11 +26,13 @@ use OCP\Files\ForbiddenException;
use OCP\Files\InvalidCharacterInPathException;
use OCP\Files\InvalidDirectoryException;
use OCP\Files\InvalidPathException;
+use OCP\Files\Mount\IMountManager;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\NotFoundException;
use OCP\Files\ReservedWordException;
use OCP\IUser;
use OCP\IUserManager;
+use OCP\L10N\IFactory;
use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
use OCP\Server;
@@ -605,13 +609,13 @@ class View {
$this->lockFile($path, ILockingProvider::LOCK_SHARED);
$exists = $this->file_exists($path);
- $run = true;
if ($this->shouldEmitHooks($path)) {
+ $run = true;
$this->emit_file_hooks_pre($exists, $path, $run);
- }
- if (!$run) {
- $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
- return false;
+ if (!$run) {
+ $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
+ return false;
+ }
}
try {
@@ -626,7 +630,7 @@ class View {
[$storage, $internalPath] = $this->resolvePath($path);
$target = $storage->fopen($internalPath, 'w');
if ($target) {
- [, $result] = \OC_Helper::streamCopy($data, $target);
+ [, $result] = Files::streamCopy($data, $target, true);
fclose($target);
fclose($data);
@@ -695,11 +699,14 @@ class View {
*
* @param string $source source path
* @param string $target target path
+ * @param array $options
*
* @return bool|mixed
* @throws LockedException
*/
- public function rename($source, $target) {
+ public function rename($source, $target, array $options = []) {
+ $checkSubMounts = $options['checkSubMounts'] ?? true;
+
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($source));
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($target));
@@ -707,6 +714,9 @@ class View {
throw new ForbiddenException('Moving a folder into a child folder is forbidden', false);
}
+ /** @var IMountManager $mountManager */
+ $mountManager = \OC::$server->get(IMountManager::class);
+
$targetParts = explode('/', $absolutePath2);
$targetUser = $targetParts[1] ?? null;
$result = false;
@@ -764,24 +774,28 @@ class View {
try {
$this->changeLock($target, ILockingProvider::LOCK_EXCLUSIVE, true);
+ if ($checkSubMounts) {
+ $movedMounts = $mountManager->findIn($this->getAbsolutePath($source));
+ } else {
+ $movedMounts = [];
+ }
+
if ($internalPath1 === '') {
- if ($mount1 instanceof MoveableMount) {
- $sourceParentMount = $this->getMount(dirname($source));
- if ($sourceParentMount === $mount2 && $this->targetIsNotShared($targetUser, $absolutePath2)) {
- /**
- * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
- */
- $sourceMountPoint = $mount1->getMountPoint();
- $result = $mount1->moveMount($absolutePath2);
- $manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
- } else {
- $result = false;
- }
- } else {
- $result = false;
- }
+ $sourceParentMount = $this->getMount(dirname($source));
+ $movedMounts[] = $mount1;
+ $this->validateMountMove($movedMounts, $sourceParentMount, $mount2, !$this->targetIsNotShared($targetUser, $absolutePath2));
+ /**
+ * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
+ */
+ $sourceMountPoint = $mount1->getMountPoint();
+ $result = $mount1->moveMount($absolutePath2);
+ $manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
+
// moving a file/folder within the same mount point
} elseif ($storage1 === $storage2) {
+ if (count($movedMounts) > 0) {
+ $this->validateMountMove($movedMounts, $mount1, $mount2, !$this->targetIsNotShared($targetUser, $absolutePath2));
+ }
if ($storage1) {
$result = $storage1->rename($internalPath1, $internalPath2);
} else {
@@ -789,6 +803,9 @@ class View {
}
// moving a file/folder between storages (from $storage1 to $storage2)
} else {
+ if (count($movedMounts) > 0) {
+ $this->validateMountMove($movedMounts, $mount1, $mount2, !$this->targetIsNotShared($targetUser, $absolutePath2));
+ }
$result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
}
@@ -839,6 +856,56 @@ class View {
}
/**
+ * @throws ForbiddenException
+ */
+ private function validateMountMove(array $mounts, IMountPoint $sourceMount, IMountPoint $targetMount, bool $targetIsShared): void {
+ $targetPath = $this->getRelativePath($targetMount->getMountPoint());
+ if ($targetPath) {
+ $targetPath = trim($targetPath, '/');
+ } else {
+ $targetPath = $targetMount->getMountPoint();
+ }
+
+ $l = \OC::$server->get(IFactory::class)->get('files');
+ foreach ($mounts as $mount) {
+ $sourcePath = $this->getRelativePath($mount->getMountPoint());
+ if ($sourcePath) {
+ $sourcePath = trim($sourcePath, '/');
+ } else {
+ $sourcePath = $mount->getMountPoint();
+ }
+
+ if (!$mount instanceof MoveableMount) {
+ throw new ForbiddenException($l->t('Storage %s cannot be moved', [$sourcePath]), false);
+ }
+
+ if ($targetIsShared) {
+ if ($sourceMount instanceof SharedMount) {
+ throw new ForbiddenException($l->t('Moving a share (%s) into a shared folder is not allowed', [$sourcePath]), false);
+ } else {
+ throw new ForbiddenException($l->t('Moving a storage (%s) into a shared folder is not allowed', [$sourcePath]), false);
+ }
+ }
+
+ if ($sourceMount !== $targetMount) {
+ if ($sourceMount instanceof SharedMount) {
+ if ($targetMount instanceof SharedMount) {
+ throw new ForbiddenException($l->t('Moving a share (%s) into another share (%s) is not allowed', [$sourcePath, $targetPath]), false);
+ } else {
+ throw new ForbiddenException($l->t('Moving a share (%s) into another storage (%s) is not allowed', [$sourcePath, $targetPath]), false);
+ }
+ } else {
+ if ($targetMount instanceof SharedMount) {
+ throw new ForbiddenException($l->t('Moving a storage (%s) into a share (%s) is not allowed', [$sourcePath, $targetPath]), false);
+ } else {
+ throw new ForbiddenException($l->t('Moving a storage (%s) into another storage (%s) is not allowed', [$sourcePath, $targetPath]), false);
+ }
+ }
+ }
+ }
+ }
+
+ /**
* Copy a file/folder from the source path to target path
*
* @param string $source source path
@@ -871,7 +938,7 @@ class View {
try {
$exists = $this->file_exists($target);
- if ($this->shouldEmitHooks()) {
+ if ($this->shouldEmitHooks($target)) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_copy,
@@ -911,7 +978,7 @@ class View {
$this->changeLock($target, ILockingProvider::LOCK_SHARED);
$lockTypePath2 = ILockingProvider::LOCK_SHARED;
- if ($this->shouldEmitHooks() && $result !== false) {
+ if ($this->shouldEmitHooks($target) && $result !== false) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_post_copy,
@@ -1401,8 +1468,7 @@ class View {
public function addSubMounts(FileInfo $info, $extOnly = false): void {
$mounts = Filesystem::getMountManager()->findIn($info->getPath());
$info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) {
- $subStorage = $mount->getStorage();
- return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage);
+ return !($extOnly && $mount instanceof SharedMount);
}));
}
@@ -1514,12 +1580,22 @@ class View {
// Create parent folders if the mountpoint is inside a subfolder that doesn't exist yet
if (!isset($files[$entryName])) {
try {
+ [$storage, ] = $this->resolvePath($path . '/' . $entryName);
+ // make sure we can create the mountpoint folder, even if the user has a quota of 0
+ if ($storage->instanceOfStorage(Quota::class)) {
+ $storage->enableQuota(false);
+ }
+
if ($this->mkdir($path . '/' . $entryName) !== false) {
$info = $this->getFileInfo($path . '/' . $entryName);
if ($info !== false) {
$files[$entryName] = $info;
}
}
+
+ if ($storage->instanceOfStorage(Quota::class)) {
+ $storage->enableQuota(true);
+ }
} catch (\Exception $e) {
// Creating the parent folder might not be possible, for example due to a lack of permissions.
$this->logger->debug('Failed to create non-existent parent', ['exception' => $e, 'path' => $path . '/' . $entryName]);
@@ -1995,9 +2071,9 @@ class View {
);
}
} catch (LockedException $e) {
- // rethrow with the a human-readable path
+ // rethrow with the human-readable path
throw new LockedException(
- $this->getPathRelativeToFiles($absolutePath),
+ $path,
$e,
$e->getExistingLock()
);
@@ -2035,20 +2111,12 @@ class View {
);
}
} catch (LockedException $e) {
- try {
- // rethrow with the a human-readable path
- throw new LockedException(
- $this->getPathRelativeToFiles($absolutePath),
- $e,
- $e->getExistingLock()
- );
- } catch (\InvalidArgumentException $ex) {
- throw new LockedException(
- $absolutePath,
- $ex,
- $e->getExistingLock()
- );
- }
+ // rethrow with the a human-readable path
+ throw new LockedException(
+ $path,
+ $e,
+ $e->getExistingLock()
+ );
}
return true;