123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- <?php
- /**
- * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
- class OC_FileChunking {
- protected $info;
- protected $cache;
- static public function decodeName($name) {
- preg_match('/(?P<name>.*)-chunking-(?P<transferid>\d+)-(?P<chunkcount>\d+)-(?P<index>\d+)/', $name, $matches);
- return $matches;
- }
- /**
- * @param string[] $info
- */
- public function __construct($info) {
- $this->info = $info;
- }
- public function getPrefix() {
- $name = $this->info['name'];
- $transferid = $this->info['transferid'];
- return $name.'-chunking-'.$transferid.'-';
- }
- protected function getCache() {
- if (!isset($this->cache)) {
- $this->cache = new \OC\Cache\File();
- }
- return $this->cache;
- }
- /**
- * Stores the given $data under the given $key - the number of stored bytes is returned
- *
- * @param string $index
- * @param resource $data
- * @return int
- */
- public function store($index, $data) {
- $cache = $this->getCache();
- $name = $this->getPrefix().$index;
- $cache->set($name, $data);
- return $cache->size($name);
- }
- public function isComplete() {
- $prefix = $this->getPrefix();
- $parts = 0;
- $cache = $this->getCache();
- for($i=0; $i < $this->info['chunkcount']; $i++) {
- if ($cache->hasKey($prefix.$i)) {
- $parts ++;
- }
- }
- return $parts == $this->info['chunkcount'];
- }
- /**
- * Assembles the chunks into the file specified by the path.
- * Chunks are deleted afterwards.
- *
- * @param string $f target path
- *
- * @return integer assembled file size
- *
- * @throws \OC\InsufficientStorageException when file could not be fully
- * assembled due to lack of free space
- */
- public function assemble($f) {
- $cache = $this->getCache();
- $prefix = $this->getPrefix();
- $count = 0;
- for ($i = 0; $i < $this->info['chunkcount']; $i++) {
- $chunk = $cache->get($prefix.$i);
- // remove after reading to directly save space
- $cache->remove($prefix.$i);
- $count += fwrite($f, $chunk);
- }
- return $count;
- }
- /**
- * Returns the size of the chunks already present
- * @return integer size in bytes
- */
- public function getCurrentSize() {
- $cache = $this->getCache();
- $prefix = $this->getPrefix();
- $total = 0;
- for ($i = 0; $i < $this->info['chunkcount']; $i++) {
- $total += $cache->size($prefix.$i);
- }
- return $total;
- }
- /**
- * Removes all chunks which belong to this transmission
- */
- public function cleanup() {
- $cache = $this->getCache();
- $prefix = $this->getPrefix();
- for($i=0; $i < $this->info['chunkcount']; $i++) {
- $cache->remove($prefix.$i);
- }
- }
- /**
- * Removes one specific chunk
- * @param string $index
- */
- public function remove($index) {
- $cache = $this->getCache();
- $prefix = $this->getPrefix();
- $cache->remove($prefix.$index);
- }
- public function signature_split($orgfile, $input) {
- $info = unpack('n', fread($input, 2));
- $blocksize = $info[1];
- $this->info['transferid'] = mt_rand();
- $count = 0;
- $needed = array();
- $cache = $this->getCache();
- $prefix = $this->getPrefix();
- while (!feof($orgfile)) {
- $new_md5 = fread($input, 16);
- if (feof($input)) {
- break;
- }
- $data = fread($orgfile, $blocksize);
- $org_md5 = md5($data, true);
- if ($org_md5 == $new_md5) {
- $cache->set($prefix.$count, $data);
- } else {
- $needed[] = $count;
- }
- $count++;
- }
- return array(
- 'transferid' => $this->info['transferid'],
- 'needed' => $needed,
- 'count' => $count,
- );
- }
- /**
- * Assembles the chunks into the file specified by the path.
- * Also triggers the relevant hooks and proxies.
- *
- * @param string $path target path
- *
- * @return boolean assembled file size or false if file could not be created
- *
- * @throws \OC\InsufficientStorageException when file could not be fully
- * assembled due to lack of free space
- */
- public function file_assemble($path) {
- $absolutePath = \OC\Files\Filesystem::normalizePath(\OC\Files\Filesystem::getView()->getAbsolutePath($path));
- $data = '';
- // use file_put_contents as method because that best matches what this function does
- if (OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data)
- && \OC\Files\Filesystem::isValidPath($path)) {
- $path = \OC\Files\Filesystem::getView()->getRelativePath($absolutePath);
- $exists = \OC\Files\Filesystem::file_exists($path);
- $run = true;
- if(!$exists) {
- OC_Hook::emit(
- \OC\Files\Filesystem::CLASSNAME,
- \OC\Files\Filesystem::signal_create,
- array(
- \OC\Files\Filesystem::signal_param_path => $path,
- \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 => $path,
- \OC\Files\Filesystem::signal_param_run => &$run
- )
- );
- if(!$run) {
- return false;
- }
- $target = \OC\Files\Filesystem::fopen($path, 'w');
- if($target) {
- $count = $this->assemble($target);
- fclose($target);
- if(!$exists) {
- OC_Hook::emit(
- \OC\Files\Filesystem::CLASSNAME,
- \OC\Files\Filesystem::signal_post_create,
- array( \OC\Files\Filesystem::signal_param_path => $path)
- );
- }
- OC_Hook::emit(
- \OC\Files\Filesystem::CLASSNAME,
- \OC\Files\Filesystem::signal_post_write,
- array( \OC\Files\Filesystem::signal_param_path => $path)
- );
- OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count);
- return $count > 0;
- }else{
- return false;
- }
- }
- return false;
- }
- }
|