diff options
Diffstat (limited to 'lib/private/files/view.php')
-rw-r--r-- | lib/private/files/view.php | 97 |
1 files changed, 85 insertions, 12 deletions
diff --git a/lib/private/files/view.php b/lib/private/files/view.php index b98842f5eb7..483dc610523 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -535,25 +535,40 @@ class View { ) { $path = $this->getRelativePath($absolutePath); + $this->lockFile($path, ILockingProvider::LOCK_SHARED); + $exists = $this->file_exists($path); $run = true; if ($this->shouldEmitHooks($path)) { $this->emit_file_hooks_pre($exists, $path, $run); } if (!$run) { + $this->unlockFile($path, ILockingProvider::LOCK_SHARED); return false; } - $target = $this->fopen($path, 'w'); + + $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE); + + /** @var \OC\Files\Storage\Storage $storage */ + list($storage, $internalPath) = $this->resolvePath($path); + $target = $storage->fopen($internalPath, 'w'); if ($target) { - list ($count, $result) = \OC_Helper::streamCopy($data, $target); + list (, $result) = \OC_Helper::streamCopy($data, $target); fclose($target); fclose($data); + + $this->changeLock($path, ILockingProvider::LOCK_SHARED); + $this->updater->update($path); + + $this->unlockFile($path, ILockingProvider::LOCK_SHARED); + if ($this->shouldEmitHooks($path) && $result !== false) { $this->emit_file_hooks_post($exists, $path); } return $result; } else { + $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE); return false; } } else { @@ -1661,52 +1676,74 @@ class View { /** * @param string $path the path of the file to lock, relative to the view * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @return bool False if the path is excluded from locking, true otherwise + * @throws \OCP\Lock\LockedException if the path is already locked */ private function lockPath($path, $type) { + $absolutePath = $this->getAbsolutePath($path); + if (!$this->shouldLockFile($absolutePath)) { + return false; + } + $mount = $this->getMount($path); if ($mount) { $mount->getStorage()->acquireLock( - $mount->getInternalPath( - $this->getAbsolutePath($path) - ), + $mount->getInternalPath($absolutePath), $type, $this->lockingProvider ); } + + return true; } /** + * Change the lock type + * * @param string $path the path of the file to lock, relative to the view * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @return bool False if the path is excluded from locking, true otherwise + * @throws \OCP\Lock\LockedException if the path is already locked */ - private function changeLock($path, $type) { + public function changeLock($path, $type) { + $absolutePath = $this->getAbsolutePath($path); + if (!$this->shouldLockFile($absolutePath)) { + return false; + } + $mount = $this->getMount($path); if ($mount) { $mount->getStorage()->changeLock( - $mount->getInternalPath( - $this->getAbsolutePath($path) - ), + $mount->getInternalPath($absolutePath), $type, $this->lockingProvider ); } + + return true; } /** * @param string $path the path of the file to unlock, relative to the view * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @return bool False if the path is excluded from locking, true otherwise */ private function unlockPath($path, $type) { + $absolutePath = $this->getAbsolutePath($path); + if (!$this->shouldLockFile($absolutePath)) { + return false; + } + $mount = $this->getMount($path); if ($mount) { $mount->getStorage()->releaseLock( - $mount->getInternalPath( - $this->getAbsolutePath($path) - ), + $mount->getInternalPath($absolutePath), $type, $this->lockingProvider ); } + + return true; } /** @@ -1714,15 +1751,24 @@ class View { * * @param string $path the path of the file to lock relative to the view * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @return bool False if the path is excluded from locking, true otherwise */ public function lockFile($path, $type) { $path = '/' . trim($path, '/'); + + $absolutePath = $this->getAbsolutePath($path); + if (!$this->shouldLockFile($absolutePath)) { + return false; + } + $this->lockPath($path, $type); $parents = $this->getParents($path); foreach ($parents as $parent) { $this->lockPath($parent, ILockingProvider::LOCK_SHARED); } + + return true; } /** @@ -1730,14 +1776,41 @@ class View { * * @param string $path the path of the file to lock relative to the view * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @return bool False if the path is excluded from locking, true otherwise */ public function unlockFile($path, $type) { $path = rtrim($path, '/'); + + $absolutePath = $this->getAbsolutePath($path); + if (!$this->shouldLockFile($absolutePath)) { + return false; + } + $this->unlockPath($path, $type); $parents = $this->getParents($path); foreach ($parents as $parent) { $this->unlockPath($parent, ILockingProvider::LOCK_SHARED); } + + return true; + } + + /** + * Only lock files in data/user/files/ + * + * @param string $path Absolute path to the file/folder we try to (un)lock + * @return bool + */ + protected function shouldLockFile($path) { + $path = Filesystem::normalizePath($path); + + $pathSegments = explode('/', $path); + if (isset($pathSegments[2])) { + // E.g.: /username/files/path-to-file + return $pathSegments[2] === 'files'; + } + + return true; } } |