Example #1
0
 /**
  * @param string $path
  * @return string
  */
 protected function toTmpFile($path)
 {
     //no longer in the storage api, still useful here
     $source = $this->fopen($path, 'r');
     if (!$source) {
         return false;
     }
     if ($pos = strrpos($path, '.')) {
         $extension = substr($path, $pos);
     } else {
         $extension = '';
     }
     $tmpFile = \OC_Helper::tmpFile($extension);
     $target = fopen($tmpFile, 'w');
     \OC_Helper::streamCopy($source, $target);
     fclose($target);
     return $tmpFile;
 }
 /**
  * copy file between two storages
  *
  * @param Storage $sourceStorage
  * @param string $sourceInternalPath
  * @param string $targetInternalPath
  * @param bool $preserveMtime
  * @param bool $isRename
  * @return bool
  * @throws \Exception
  */
 private function copyBetweenStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename)
 {
     // for versions we have nothing to do, because versions should always use the
     // key from the original file. Just create a 1:1 copy and done
     if ($this->isVersion($targetInternalPath) || $this->isVersion($sourceInternalPath)) {
         $result = $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
         if ($result) {
             $info = $this->getCache('', $sourceStorage)->get($sourceInternalPath);
             // make sure that we update the unencrypted size for the version
             if (isset($info['encrypted']) && $info['encrypted'] === true) {
                 $this->updateUnencryptedSize($this->getFullPath($targetInternalPath), $info['size']);
             }
         }
         return $result;
     }
     // first copy the keys that we reuse the existing file key on the target location
     // and don't create a new one which would break versions for example.
     $mount = $this->mountManager->findByStorageId($sourceStorage->getId());
     if (count($mount) === 1) {
         $mountPoint = $mount[0]->getMountPoint();
         $source = $mountPoint . '/' . $sourceInternalPath;
         $target = $this->getFullPath($targetInternalPath);
         $this->copyKeys($source, $target);
     } else {
         $this->logger->error('Could not find mount point, can\'t keep encryption keys');
     }
     if ($sourceStorage->is_dir($sourceInternalPath)) {
         $dh = $sourceStorage->opendir($sourceInternalPath);
         $result = $this->mkdir($targetInternalPath);
         if (is_resource($dh)) {
             while ($result and ($file = readdir($dh)) !== false) {
                 if (!Filesystem::isIgnoredDir($file)) {
                     $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file);
                 }
             }
         }
     } else {
         try {
             $source = $sourceStorage->fopen($sourceInternalPath, 'r');
             $target = $this->fopen($targetInternalPath, 'w');
             list(, $result) = \OC_Helper::streamCopy($source, $target);
             fclose($source);
             fclose($target);
         } catch (\Exception $e) {
             fclose($source);
             fclose($target);
             throw $e;
         }
         if ($result) {
             if ($preserveMtime) {
                 $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath));
             }
             $isEncrypted = $this->encryptionManager->isEnabled() && $this->mount->getOption('encrypt', true) ? 1 : 0;
             // in case of a rename we need to manipulate the source cache because
             // this information will be kept for the new target
             if ($isRename) {
                 $sourceStorage->getCache()->put($sourceInternalPath, ['encrypted' => $isEncrypted]);
             } else {
                 $this->getCache()->put($targetInternalPath, ['encrypted' => $isEncrypted]);
             }
         } else {
             // delete partially written target file
             $this->unlink($targetInternalPath);
             // delete cache entry that was created by fopen
             $this->getCache()->remove($targetInternalPath);
         }
     }
     return (bool) $result;
 }
Example #3
0
 /**
  * @param \OCP\Files\Storage $sourceStorage
  * @param string $sourceInternalPath
  * @param string $targetInternalPath
  * @param bool $preserveMtime
  * @return bool
  */
 public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false)
 {
     if ($sourceStorage === $this) {
         return $this->copy($sourceInternalPath, $targetInternalPath);
     }
     if ($sourceStorage->is_dir($sourceInternalPath)) {
         $dh = $sourceStorage->opendir($sourceInternalPath);
         $result = $this->mkdir($targetInternalPath);
         if (is_resource($dh)) {
             while ($result and ($file = readdir($dh)) !== false) {
                 if (!Filesystem::isIgnoredDir($file)) {
                     $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file);
                 }
             }
         }
     } else {
         $source = $sourceStorage->fopen($sourceInternalPath, 'r');
         // TODO: call fopen in a way that we execute again all storage wrappers
         // to avoid that we bypass storage wrappers which perform important actions
         // for this operation. Same is true for all other operations which
         // are not the same as the original one.Once this is fixed we also
         // need to adjust the encryption wrapper.
         $target = $this->fopen($targetInternalPath, 'w');
         list(, $result) = \OC_Helper::streamCopy($source, $target);
         if ($result and $preserveMtime) {
             $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath));
         }
         fclose($source);
         fclose($target);
         if (!$result) {
             // delete partially written target file
             $this->unlink($targetInternalPath);
             // delete cache entry that was created by fopen
             $this->getCache()->remove($targetInternalPath);
         }
     }
     return (bool) $result;
 }
Example #4
0
 /**
  * @param string $path
  * @param mixed $data
  * @return bool|mixed
  * @throws \Exception
  */
 public function file_put_contents($path, $data)
 {
     if (is_resource($data)) {
         //not having to deal with streams in file_put_contents makes life easier
         $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
         if (Filesystem::isValidPath($path) and !Filesystem::isFileBlacklisted($path)) {
             $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;
             }
             $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(, $result) = \OC_Helper::streamCopy($data, $target);
                 fclose($target);
                 fclose($data);
                 $this->writeUpdate($storage, $internalPath);
                 $this->changeLock($path, ILockingProvider::LOCK_SHARED);
                 if ($this->shouldEmitHooks($path) && $result !== false) {
                     $this->emit_file_hooks_post($exists, $path);
                 }
                 $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
                 return $result;
             } else {
                 $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
                 return false;
             }
         } else {
             return false;
         }
     } else {
         $hooks = $this->file_exists($path) ? array('update', 'write') : array('create', 'write');
         return $this->basicOperation('file_put_contents', $path, $hooks, $data);
     }
 }
Example #5
0
 public function copy($path1, $path2)
 {
     $postFix1 = substr($path1, -1, 1) === '/' ? '/' : '';
     $postFix2 = substr($path2, -1, 1) === '/' ? '/' : '';
     $absolutePath1 = OC_Filesystem::normalizePath($this->getAbsolutePath($path1));
     $absolutePath2 = OC_Filesystem::normalizePath($this->getAbsolutePath($path2));
     if (OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) and OC_Filesystem::isValidPath($path2)) {
         $path1 = $this->getRelativePath($absolutePath1);
         $path2 = $this->getRelativePath($absolutePath2);
         if ($path1 == null or $path2 == null) {
             return false;
         }
         $run = true;
         if ($this->fakeRoot == OC_Filesystem::getRoot()) {
             OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_copy, array(OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath => $path2, OC_Filesystem::signal_param_run => &$run));
             $exists = $this->file_exists($path2);
             if ($run and !$exists) {
                 OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_create, array(OC_Filesystem::signal_param_path => $path2, OC_Filesystem::signal_param_run => &$run));
             }
             if ($run) {
                 OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_write, array(OC_Filesystem::signal_param_path => $path2, OC_Filesystem::signal_param_run => &$run));
             }
         }
         if ($run) {
             $mp1 = $this->getMountPoint($path1 . $postFix1);
             $mp2 = $this->getMountPoint($path2 . $postFix2);
             if ($mp1 == $mp2) {
                 if ($storage = $this->getStorage($path1 . $postFix1)) {
                     $result = $storage->copy($this->getInternalPath($path1 . $postFix1), $this->getInternalPath($path2 . $postFix2));
                 }
             } else {
                 $source = $this->fopen($path1 . $postFix1, 'r');
                 $target = $this->fopen($path2 . $postFix2, 'w');
                 $result = OC_Helper::streamCopy($source, $target);
             }
             if ($this->fakeRoot == OC_Filesystem::getRoot()) {
                 OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_copy, array(OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath => $path2));
                 if (!$exists) {
                     OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_create, array(OC_Filesystem::signal_param_path => $path2));
                 }
                 OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array(OC_Filesystem::signal_param_path => $path2));
             } else {
                 // no real copy, file comes from somewhere else, e.g. version rollback -> just update the file cache and the webdav properties without all the other post_write actions
                 OC_FileCache_Update::update($path2, $this->fakeRoot);
                 OC_Filesystem::removeETagHook(array("path" => $path2), $this->fakeRoot);
             }
             return $result;
         }
     }
 }
Example #6
0
 /**
  * Stream copy file contents from $path1 to $path2
  *
  * @param View $view view to use for copying
  * @param string $path1 source file to copy
  * @param string $path2 target file
  *
  * @return bool true for success, false otherwise
  */
 private static function copyFileContents($view, $path1, $path2)
 {
     /** @var \OC\Files\Storage\Storage $storage1 */
     list($storage1, $internalPath1) = $view->resolvePath($path1);
     /** @var \OC\Files\Storage\Storage $storage2 */
     list($storage2, $internalPath2) = $view->resolvePath($path2);
     $view->lockFile($path1, ILockingProvider::LOCK_EXCLUSIVE);
     $view->lockFile($path2, ILockingProvider::LOCK_EXCLUSIVE);
     // TODO add a proper way of overwriting a file while maintaining file ids
     if ($storage1->instanceOfStorage('\\OC\\Files\\ObjectStore\\ObjectStoreStorage') || $storage2->instanceOfStorage('\\OC\\Files\\ObjectStore\\ObjectStoreStorage')) {
         $source = $storage1->fopen($internalPath1, 'r');
         $target = $storage2->fopen($internalPath2, 'w');
         list(, $result) = \OC_Helper::streamCopy($source, $target);
         fclose($source);
         fclose($target);
         if ($result !== false) {
             $storage1->unlink($internalPath1);
         }
     } else {
         $result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
     }
     $view->unlockFile($path1, ILockingProvider::LOCK_EXCLUSIVE);
     $view->unlockFile($path2, ILockingProvider::LOCK_EXCLUSIVE);
     return $result !== false;
 }
Example #7
0
 /**
  * copy the contents of one stream to another
  * @param resource source
  * @param resource target
  * @return int the number of bytes copied
  */
 public static function streamCopy($source, $target)
 {
     list($count, $result) = \OC_Helper::streamCopy($source, $target);
     return $count;
 }
Example #8
0
	public function testStreamCopyNotEnoughSpace() {
		$instance = $this->getLimitedStorage(9);
		$inputStream = fopen('data://text/plain,foobarqwerty', 'r');
		$outputStream = $instance->fopen('files/foo', 'w+');
		list($count, $result) = \OC_Helper::streamCopy($inputStream, $outputStream);
		$this->assertEquals(9, $count);
		$this->assertFalse($result);
		fclose($inputStream);
		fclose($outputStream);
	}
Example #9
0
 /**
  * @param string $path
  * @param mixed $data
  * @return bool|mixed
  */
 public function file_put_contents($path, $data)
 {
     if (is_resource($data)) {
         //not having to deal with streams in file_put_contents makes life easier
         $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
         if (Filesystem::isValidPath($path) and !Filesystem::isFileBlacklisted($path)) {
             $path = $this->getRelativePath($absolutePath);
             $exists = $this->file_exists($path);
             $run = true;
             if ($this->shouldEmitHooks($path)) {
                 $this->emit_file_hooks_pre($exists, $path, $run);
             }
             if (!$run) {
                 return false;
             }
             $target = $this->fopen($path, 'w');
             if ($target) {
                 list($count, $result) = \OC_Helper::streamCopy($data, $target);
                 fclose($target);
                 fclose($data);
                 $this->updater->update($path);
                 if ($this->shouldEmitHooks($path) && $result !== false) {
                     $this->emit_file_hooks_post($exists, $path);
                 }
                 return $result;
             } else {
                 return false;
             }
         } else {
             return false;
         }
     } else {
         $hooks = $this->file_exists($path) ? array('update', 'write') : array('create', 'write');
         return $this->basicOperation('file_put_contents', $path, $hooks, $data);
     }
 }
Example #10
0
 /**
  * copy the contents of one stream to another
  * @param resource source
  * @param resource target
  * @return int the number of bytes copied
  */
 public static function streamCopy($source, $target)
 {
     return \OC_Helper::streamCopy($source, $target);
 }
Example #11
0
 public function copy($path1, $path2)
 {
     $postFix1 = substr($path1, -1, 1) === '/' ? '/' : '';
     $postFix2 = substr($path2, -1, 1) === '/' ? '/' : '';
     $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
     $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
     if (\OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) and Filesystem::isValidPath($path2) and Filesystem::isValidPath($path1) and !Filesystem::isFileBlacklisted($path2)) {
         $path1 = $this->getRelativePath($absolutePath1);
         $path2 = $this->getRelativePath($absolutePath2);
         if ($path1 == null or $path2 == null) {
             return false;
         }
         $run = true;
         $exists = $this->file_exists($path2);
         if ($this->shouldEmitHooks()) {
             \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_copy, array(Filesystem::signal_param_oldpath => $this->getHookPath($path1), Filesystem::signal_param_newpath => $this->getHookPath($path2), Filesystem::signal_param_run => &$run));
             if ($run and !$exists) {
                 \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_create, array(Filesystem::signal_param_path => $this->getHookPath($path2), Filesystem::signal_param_run => &$run));
             }
             if ($run) {
                 \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_write, array(Filesystem::signal_param_path => $this->getHookPath($path2), Filesystem::signal_param_run => &$run));
             }
         }
         if ($run) {
             $mp1 = $this->getMountPoint($path1 . $postFix1);
             $mp2 = $this->getMountPoint($path2 . $postFix2);
             if ($mp1 == $mp2) {
                 list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1);
                 list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2);
                 if ($storage) {
                     $result = $storage->copy($internalPath1, $internalPath2);
                 } else {
                     $result = false;
                 }
             } else {
                 if ($this->is_dir($path1) && ($dh = $this->opendir($path1))) {
                     $result = $this->mkdir($path2);
                     if (is_resource($dh)) {
                         while (($file = readdir($dh)) !== false) {
                             if (!Filesystem::isIgnoredDir($file)) {
                                 $result = $this->copy($path1 . '/' . $file, $path2 . '/' . $file);
                             }
                         }
                     }
                 } else {
                     $source = $this->fopen($path1 . $postFix1, 'r');
                     $target = $this->fopen($path2 . $postFix2, 'w');
                     list($count, $result) = \OC_Helper::streamCopy($source, $target);
                     fclose($source);
                     fclose($target);
                 }
             }
             if ($this->shouldEmitHooks() && $result !== false) {
                 \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_copy, array(Filesystem::signal_param_oldpath => $this->getHookPath($path1), Filesystem::signal_param_newpath => $this->getHookPath($path2)));
                 if (!$exists) {
                     \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_create, array(Filesystem::signal_param_path => $this->getHookPath($path2)));
                 }
                 \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_write, array(Filesystem::signal_param_path => $this->getHookPath($path2)));
             }
             return $result;
         } else {
             return false;
         }
     } else {
         return false;
     }
 }
Example #12
0
 /**
  * Updates the data
  *
  * The data argument is a readable stream resource.
  *
  * After a successful put operation, you may choose to return an ETag. The
  * etag must always be surrounded by double-quotes. These quotes must
  * appear in the actual string you're returning.
  *
  * Clients may use the ETag from a PUT request to later on make sure that
  * when they update the file, the contents haven't changed in the mean
  * time.
  *
  * If you don't plan to store the file byte-by-byte, and you return a
  * different object on a subsequent GET you are strongly recommended to not
  * return an ETag, and just return null.
  *
  * @param resource $data
  *
  * @throws Forbidden
  * @throws UnsupportedMediaType
  * @throws BadRequest
  * @throws Exception
  * @throws EntityTooLarge
  * @throws ServiceUnavailable
  * @throws FileLocked
  * @return string|null
  */
 public function put($data)
 {
     try {
         $exists = $this->fileView->file_exists($this->path);
         if ($this->info && $exists && !$this->info->isUpdateable()) {
             throw new Forbidden();
         }
     } catch (StorageNotAvailableException $e) {
         throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
     }
     // verify path of the target
     $this->verifyPath();
     // chunked handling
     if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
         return $this->createFileChunked($data);
     }
     list($partStorage) = $this->fileView->resolvePath($this->path);
     $needsPartFile = $this->needsPartFile($partStorage) && strlen($this->path) > 1;
     if ($needsPartFile) {
         // mark file as partial while uploading (ignored by the scanner)
         $partFilePath = $this->path . '.ocTransferId' . rand() . '.part';
     } else {
         // upload file directly as the final path
         $partFilePath = $this->path;
     }
     try {
         $this->fileView->lockFile($this->path, ILockingProvider::LOCK_EXCLUSIVE);
     } catch (LockedException $e) {
         throw new FileLocked($e->getMessage(), $e->getCode(), $e);
     }
     // the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
     /** @var \OC\Files\Storage\Storage $partStorage */
     list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
     /** @var \OC\Files\Storage\Storage $storage */
     list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
     try {
         $target = $partStorage->fopen($internalPartPath, 'wb');
         if ($target === false) {
             \OC_Log::write('webdav', '\\OC\\Files\\Filesystem::fopen() failed', \OC_Log::ERROR);
             $partStorage->unlink($internalPartPath);
             // because we have no clue about the cause we can only throw back a 500/Internal Server Error
             throw new Exception('Could not write file contents');
         }
         list($count, ) = \OC_Helper::streamCopy($data, $target);
         fclose($target);
         // if content length is sent by client:
         // double check if the file was fully received
         // compare expected and actual size
         if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] !== 'LOCK') {
             $expected = $_SERVER['CONTENT_LENGTH'];
             if ($count != $expected) {
                 $partStorage->unlink($internalPartPath);
                 throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
             }
         }
     } catch (NotPermittedException $e) {
         // a more general case - due to whatever reason the content could not be written
         throw new Forbidden($e->getMessage());
     } catch (EntityTooLargeException $e) {
         // the file is too big to be stored
         throw new EntityTooLarge($e->getMessage());
     } catch (InvalidContentException $e) {
         // the file content is not permitted
         throw new UnsupportedMediaType($e->getMessage());
     } catch (InvalidPathException $e) {
         // the path for the file was not valid
         // TODO: find proper http status code for this case
         throw new Forbidden($e->getMessage());
     } catch (LockNotAcquiredException $e) {
         // the file is currently being written to by another process
         throw new FileLocked($e->getMessage(), $e->getCode(), $e);
     } catch (GenericEncryptionException $e) {
         // returning 503 will allow retry of the operation at a later point in time
         throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
     } catch (StorageNotAvailableException $e) {
         throw new ServiceUnavailable("Failed to write file contents: " . $e->getMessage());
     }
     try {
         $view = \OC\Files\Filesystem::getView();
         $run = true;
         if ($view) {
             $hookPath = $view->getRelativePath($this->fileView->getAbsolutePath($this->path));
             if (!$exists) {
                 \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array(\OC\Files\Filesystem::signal_param_path => $hookPath, \OC\Files\Filesystem::signal_param_run => &$run));
             } else {
                 \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array(\OC\Files\Filesystem::signal_param_path => $hookPath, \OC\Files\Filesystem::signal_param_run => &$run));
             }
             \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array(\OC\Files\Filesystem::signal_param_path => $hookPath, \OC\Files\Filesystem::signal_param_run => &$run));
         }
         if ($needsPartFile) {
             // rename to correct path
             try {
                 if ($run) {
                     $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
                     $fileExists = $storage->file_exists($internalPath);
                 }
                 if (!$run || $renameOkay === false || $fileExists === false) {
                     \OC_Log::write('webdav', 'renaming part file to final file failed', \OC_Log::ERROR);
                     $partStorage->unlink($internalPartPath);
                     throw new Exception('Could not rename part file to final file');
                 }
             } catch (\OCP\Files\LockNotAcquiredException $e) {
                 // the file is currently being written to by another process
                 throw new FileLocked($e->getMessage(), $e->getCode(), $e);
             }
         }
         // since we skipped the view we need to scan and emit the hooks ourselves
         $partStorage->getScanner()->scanFile($internalPath);
         if ($view) {
             $this->fileView->getUpdater()->propagate($hookPath);
             if (!$exists) {
                 \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(\OC\Files\Filesystem::signal_param_path => $hookPath));
             } else {
                 \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_update, array(\OC\Files\Filesystem::signal_param_path => $hookPath));
             }
             \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_write, array(\OC\Files\Filesystem::signal_param_path => $hookPath));
         }
         // allow sync clients to send the mtime along in a header
         $request = \OC::$server->getRequest();
         if (isset($request->server['HTTP_X_OC_MTIME'])) {
             if ($this->fileView->touch($this->path, $request->server['HTTP_X_OC_MTIME'])) {
                 header('X-OC-MTime: accepted');
             }
         }
         $this->refreshInfo();
     } catch (StorageNotAvailableException $e) {
         throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
     }
     $this->fileView->unlockFile($this->path, ILockingProvider::LOCK_EXCLUSIVE);
     return '"' . $this->info->getEtag() . '"';
 }
Example #13
0
 public function copy($path1, $path2)
 {
     if ($this->is_dir($path1)) {
         $this->remove($path2);
         $dir = $this->opendir($path1);
         $this->mkdir($path2);
         while ($file = readdir($dir)) {
             if (!Filesystem::isIgnoredDir($file)) {
                 if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) {
                     return false;
                 }
             }
         }
         closedir($dir);
         return true;
     } else {
         $source = $this->fopen($path1, 'r');
         $target = $this->fopen($path2, 'w');
         list(, $result) = \OC_Helper::streamCopy($source, $target);
         $this->removeCachedFile($path2);
         return $result;
     }
 }
Example #14
0
 public function copy($path1, $path2)
 {
     $absolutePath1 = $this->getAbsolutePath($path1);
     $absolutePath2 = $this->getAbsolutePath($path2);
     if (OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) and OC_Filesystem::isValidPath($path2)) {
         $path1 = $this->getRelativePath($absolutePath1);
         $path2 = $this->getRelativePath($absolutePath2);
         if ($path1 == null or $path2 == null) {
             return false;
         }
         $run = true;
         OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_copy, array(OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath => $path2, OC_Filesystem::signal_param_run => &$run));
         $exists = $this->file_exists($path2);
         if ($run and !$exists) {
             OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_create, array(OC_Filesystem::signal_param_path => $path2, OC_Filesystem::signal_param_run => &$run));
         }
         if ($run) {
             OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_write, array(OC_Filesystem::signal_param_path => $path2, OC_Filesystem::signal_param_run => &$run));
         }
         if ($run) {
             $mp1 = $this->getMountPoint($path1);
             $mp2 = $this->getMountPoint($path2);
             if ($mp1 == $mp2) {
                 if ($storage = $this->getStorage($path1)) {
                     $result = $storage->copy($this->getInternalPath($path1), $this->getInternalPath($path2));
                 }
             } else {
                 $source = $this->fopen($path1, 'r');
                 $target = $this->fopen($path2, 'w');
                 $count = OC_Helper::streamCopy($data, $target);
             }
             OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_copy, array(OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath => $path2));
             if (!$exists) {
                 OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_create, array(OC_Filesystem::signal_param_path => $path2));
             }
             OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array(OC_Filesystem::signal_param_path => $path2));
             return $result;
         }
     }
 }
Example #15
0
 /**
  * @dataProvider streamCopyDataProvider
  */
 public function testStreamCopy($expectedCount, $expectedResult, $source, $target)
 {
     if (is_string($source)) {
         $source = fopen($source, 'r');
     }
     if (is_string($target)) {
         $target = fopen($target, 'w');
     }
     list($count, $result) = \OC_Helper::streamCopy($source, $target);
     if (is_resource($source)) {
         fclose($source);
     }
     if (is_resource($target)) {
         fclose($target);
     }
     $this->assertSame($expectedCount, $count);
     $this->assertSame($expectedResult, $result);
 }
Example #16
0
 /**
  * Copy a file/folder from the source path to target path
  *
  * @param string $path1 source path
  * @param string $path2 target path
  * @param bool $preserveMtime whether to preserve mtime on the copy
  *
  * @return bool|mixed
  */
 public function copy($path1, $path2, $preserveMtime = false)
 {
     $postFix1 = substr($path1, -1, 1) === '/' ? '/' : '';
     $postFix2 = substr($path2, -1, 1) === '/' ? '/' : '';
     $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
     $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
     if (Filesystem::isValidPath($path2) and Filesystem::isValidPath($path1) and !Filesystem::isFileBlacklisted($path2)) {
         $path1 = $this->getRelativePath($absolutePath1);
         $path2 = $this->getRelativePath($absolutePath2);
         if ($path1 == null or $path2 == null) {
             return false;
         }
         $run = true;
         $exists = $this->file_exists($path2);
         if ($this->shouldEmitHooks()) {
             \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_copy, array(Filesystem::signal_param_oldpath => $this->getHookPath($path1), Filesystem::signal_param_newpath => $this->getHookPath($path2), Filesystem::signal_param_run => &$run));
             $this->emit_file_hooks_pre($exists, $path2, $run);
         }
         if ($run) {
             $mp1 = $this->getMountPoint($path1 . $postFix1);
             $mp2 = $this->getMountPoint($path2 . $postFix2);
             if ($mp1 == $mp2) {
                 list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1);
                 list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2);
                 if ($storage) {
                     $result = $storage->copy($internalPath1, $internalPath2);
                     if (!$result) {
                         // delete partially written target file
                         $storage->unlink($internalPath2);
                         $storage->getCache()->remove($internalPath2);
                     }
                 } else {
                     $result = false;
                 }
             } else {
                 if ($this->is_dir($path1) && ($dh = $this->opendir($path1))) {
                     $result = $this->mkdir($path2);
                     if ($preserveMtime) {
                         $this->touch($path2, $this->filemtime($path1));
                     }
                     if (is_resource($dh)) {
                         while (($file = readdir($dh)) !== false) {
                             if (!Filesystem::isIgnoredDir($file)) {
                                 if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file, $preserveMtime)) {
                                     $result = false;
                                 }
                             }
                         }
                     }
                 } else {
                     list($storage2, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2);
                     $source = $this->fopen($path1 . $postFix1, 'r');
                     $target = $this->fopen($path2 . $postFix2, 'w');
                     list(, $result) = \OC_Helper::streamCopy($source, $target);
                     if ($result && $preserveMtime) {
                         $this->touch($path2, $this->filemtime($path1));
                     }
                     fclose($source);
                     fclose($target);
                     if (!$result) {
                         // delete partially written target file
                         $storage2->unlink($internalPath2);
                         $storage2->getCache()->remove($internalPath2);
                     }
                 }
             }
             $this->updater->update($path2);
             if ($this->shouldEmitHooks() && $result !== false) {
                 \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_copy, array(Filesystem::signal_param_oldpath => $this->getHookPath($path1), Filesystem::signal_param_newpath => $this->getHookPath($path2)));
                 $this->emit_file_hooks_post($exists, $path2);
             }
             return $result;
         } else {
             return false;
         }
     } else {
         return false;
     }
 }
Example #17
0
 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');
         return OC_Helper::streamCopy($source, $target);
     }
     return false;
 }
Example #18
0
	/**
	 * Updates the data
	 *
	 * The data argument is a readable stream resource.
	 *
	 * After a successful put operation, you may choose to return an ETag. The
	 * etag must always be surrounded by double-quotes. These quotes must
	 * appear in the actual string you're returning.
	 *
	 * Clients may use the ETag from a PUT request to later on make sure that
	 * when they update the file, the contents haven't changed in the mean
	 * time.
	 *
	 * If you don't plan to store the file byte-by-byte, and you return a
	 * different object on a subsequent GET you are strongly recommended to not
	 * return an ETag, and just return null.
	 *
	 * @param resource $data
	 *
	 * @throws Forbidden
	 * @throws UnsupportedMediaType
	 * @throws BadRequest
	 * @throws Exception
	 * @throws EntityTooLarge
	 * @throws ServiceUnavailable
	 * @throws FileLocked
	 * @return string|null
	 */
	public function put($data) {
		try {
			$exists = $this->fileView->file_exists($this->path);
			if ($this->info && $exists && !$this->info->isUpdateable()) {
				throw new Forbidden();
			}
		} catch (StorageNotAvailableException $e) {
			throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
		}

		// verify path of the target
		$this->verifyPath();

		// chunked handling
		if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
			try {
				return $this->createFileChunked($data);
			} catch (\Exception $e) {
				$this->convertToSabreException($e);
			}
		}

		list($partStorage) = $this->fileView->resolvePath($this->path);
		$needsPartFile = $this->needsPartFile($partStorage) && (strlen($this->path) > 1);

		if ($needsPartFile) {
			// mark file as partial while uploading (ignored by the scanner)
			$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
		} else {
			// upload file directly as the final path
			$partFilePath = $this->path;
		}

		// the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
		/** @var \OC\Files\Storage\Storage $partStorage */
		list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
		/** @var \OC\Files\Storage\Storage $storage */
		list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
		try {
			$target = $partStorage->fopen($internalPartPath, 'wb');
			if ($target === false) {
				\OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::fopen() failed', \OCP\Util::ERROR);
				// because we have no clue about the cause we can only throw back a 500/Internal Server Error
				throw new Exception('Could not write file contents');
			}
			list($count, $result) = \OC_Helper::streamCopy($data, $target);
			fclose($target);

			if ($result === false) {
				$expected = -1;
				if (isset($_SERVER['CONTENT_LENGTH'])) {
					$expected = $_SERVER['CONTENT_LENGTH'];
				}
				throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
			}

			// if content length is sent by client:
			// double check if the file was fully received
			// compare expected and actual size
			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] !== 'LOCK') {
				$expected = $_SERVER['CONTENT_LENGTH'];
				if ($count != $expected) {
					throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
				}
			}

		} catch (\Exception $e) {
			if ($needsPartFile) {
				$partStorage->unlink($internalPartPath);
			}
			$this->convertToSabreException($e);
		}

		try {
			$view = \OC\Files\Filesystem::getView();
			if ($view) {
				$run = $this->emitPreHooks($exists);
			} else {
				$run = true;
			}

			try {
				$this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
			} catch (LockedException $e) {
				if ($needsPartFile) {
					$partStorage->unlink($internalPartPath);
				}
				throw new FileLocked($e->getMessage(), $e->getCode(), $e);
			}

			if ($needsPartFile) {
				// rename to correct path
				try {
					if ($run) {
						$renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
						$fileExists = $storage->file_exists($internalPath);
					}
					if (!$run || $renameOkay === false || $fileExists === false) {
						\OCP\Util::writeLog('webdav', 'renaming part file to final file failed', \OCP\Util::ERROR);
						throw new Exception('Could not rename part file to final file');
					}
				} catch (\Exception $e) {
					$partStorage->unlink($internalPartPath);
					$this->convertToSabreException($e);
				}
			}

			// since we skipped the view we need to scan and emit the hooks ourselves
			$this->fileView->getUpdater()->update($this->path);

			try {
				$this->changeLock(ILockingProvider::LOCK_SHARED);
			} catch (LockedException $e) {
				throw new FileLocked($e->getMessage(), $e->getCode(), $e);
			}

			if ($view) {
				$this->emitPostHooks($exists);
			}

			// allow sync clients to send the mtime along in a header
			$request = \OC::$server->getRequest();
			if (isset($request->server['HTTP_X_OC_MTIME'])) {
				if ($this->fileView->touch($this->path, $request->server['HTTP_X_OC_MTIME'])) {
					header('X-OC-MTime: accepted');
				}
			}
			$this->refreshInfo();
		} catch (StorageNotAvailableException $e) {
			throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
		}

		return '"' . $this->info->getEtag() . '"';
	}
Example #19
0
 public function copy($path1, $path2)
 {
     $postFix1 = substr($path1, -1, 1) === '/' ? '/' : '';
     $postFix2 = substr($path2, -1, 1) === '/' ? '/' : '';
     $absolutePath1 = OC_Filesystem::normalizePath($this->getAbsolutePath($path1));
     $absolutePath2 = OC_Filesystem::normalizePath($this->getAbsolutePath($path2));
     if (OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) and OC_Filesystem::isValidPath($path2)) {
         $path1 = $this->getRelativePath($absolutePath1);
         $path2 = $this->getRelativePath($absolutePath2);
         if ($path1 == null or $path2 == null) {
             return false;
         }
         $run = true;
         if ($this->fakeRoot == OC_Filesystem::getRoot()) {
             OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_copy, array(OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath => $path2, OC_Filesystem::signal_param_run => &$run));
             $exists = $this->file_exists($path2);
             if ($run and !$exists) {
                 OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_create, array(OC_Filesystem::signal_param_path => $path2, OC_Filesystem::signal_param_run => &$run));
             }
             if ($run) {
                 OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_write, array(OC_Filesystem::signal_param_path => $path2, OC_Filesystem::signal_param_run => &$run));
             }
         }
         if ($run) {
             $mp1 = $this->getMountPoint($path1 . $postFix1);
             $mp2 = $this->getMountPoint($path2 . $postFix2);
             if ($mp1 == $mp2) {
                 if ($storage = $this->getStorage($path1 . $postFix1)) {
                     $result = $storage->copy($this->getInternalPath($path1 . $postFix1), $this->getInternalPath($path2 . $postFix2));
                 }
             } else {
                 $source = $this->fopen($path1 . $postFix1, 'r');
                 $target = $this->fopen($path2 . $postFix2, 'w');
                 $result = OC_Helper::streamCopy($source, $target);
             }
             if ($this->fakeRoot == OC_Filesystem::getRoot()) {
                 // If the file to be copied originates within
                 // the user's data directory
                 OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_copy, array(OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath => $path2));
                 if (!$exists) {
                     OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_create, array(OC_Filesystem::signal_param_path => $path2));
                 }
                 OC_Hook::emit(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array(OC_Filesystem::signal_param_path => $path2));
             } else {
                 // If this is not a normal file copy operation
                 // and the file originates somewhere else
                 // (e.g. a version rollback operation), do not
                 // perform all the other post_write actions
                 // Update webdav properties
                 OC_Filesystem::removeETagHook(array("path" => $path2), $this->fakeRoot);
                 $splitPath2 = explode('/', $path2);
                 // Only cache information about files
                 // that are being copied from within
                 // the user files directory. Caching
                 // other files, like VCS backup files,
                 // serves no purpose
                 if ($splitPath2[1] == 'files') {
                     OC_FileCache_Update::update($path2, $this->fakeRoot);
                 }
             }
             return $result;
         }
     }
 }