diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 62f6a8c236..12be5aefcb 100644 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -205,12 +205,16 @@ class OC_Crypt { /** * decrypt data in 8192b sized blocks */ - public static function blockDecrypt($data, $key=''){ + public static function blockDecrypt($data, $key='',$maxLength=0){ $result=''; while(strlen($data)){ $result.=self::decrypt(substr($data,0,8192),$key); $data=substr($data,8192); } - return rtrim($result, "\0"); + if($maxLength>0){ + return substr($result,0,$maxLength); + }else{ + return rtrim($result, "\0"); + } } } diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php index c59a520a8d..901e8cccbf 100644 --- a/apps/files_encryption/lib/cryptstream.php +++ b/apps/files_encryption/lib/cryptstream.php @@ -35,6 +35,7 @@ class OC_CryptStream{ private $meta=array();//header/meta for source stream private $count; private $writeCache; + private $size; private static $rootView; public function stream_open($path, $mode, $options, &$opened_path){ @@ -45,8 +46,14 @@ class OC_CryptStream{ if(dirname($path)=='streams' and isset(self::$sourceStreams[basename($path)])){ $this->source=self::$sourceStreams[basename($path)]['stream']; $this->path=self::$sourceStreams[basename($path)]['path']; + $this->size=self::$sourceStreams[basename($path)]['size']; }else{ $this->path=$path; + if($mode=='w' or $mode=='w+' or $mode=='wb' or $mode=='wb+'){ + $this->size=0; + }else{ + $this->size=self::$rootView->filesize($path,$mode); + } OC_FileProxy::$enabled=false;//disable fileproxies so we can open the source file $this->source=self::$rootView->fopen($path,$mode); OC_FileProxy::$enabled=true; @@ -77,14 +84,16 @@ class OC_CryptStream{ OCP\Util::writeLog('files_encryption','php bug 21641 no longer holds, decryption will not work',OCP\Util::FATAL); die(); } + $pos=ftell($this->source); $data=fread($this->source,8192); if(strlen($data)){ $result=OC_Crypt::decrypt($data); }else{ $result=''; } - if($this->stream_eof()){ - $result=rtrim($result, "\0"); + $length=$this->size-$pos; + if($length<8192){ + $result=substr($result,0,$length); } return $result; } @@ -116,6 +125,8 @@ class OC_CryptStream{ $data=substr($data,8192); } } + $currentPos=ftell($this->source); + $this->size=max($this->size,$currentPos); return $length; } @@ -159,7 +170,7 @@ class OC_CryptStream{ public function stream_close(){ $this->flush(); if($this->meta['mode']!='r' and $this->meta['mode']!='rb'){ - OC_FileCache::put($this->path,array('encrypted'=>true),'/'); + OC_FileCache::put($this->path,array('encrypted'=>true,'size'=>$this->size),'/'); } return fclose($this->source); } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 052fff0bbb..633ae6b93d 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -66,15 +66,17 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ public function preFile_put_contents($path,&$data){ if(self::shouldEncrypt($path)){ if (!is_resource($data)) {//stream put contents should have been converter to fopen + $size=strlen($data); $data=OC_Crypt::blockEncrypt($data); - OC_FileCache::put($path,array('encrypted'=>true),'/'); + OC_FileCache::put($path,array('encrypted'=>true,'size'=>$size),'/'); } } } public function postFile_get_contents($path,$data){ if(self::isEncrypted($path)){ - $data=OC_Crypt::blockDecrypt($data); + $cached=OC_FileCache::getCached($path,'/'); + $data=OC_Crypt::blockDecrypt($data,'',$cached['size']); } return $data; } @@ -108,4 +110,21 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ } return $mime; } + + public function postStat($path,$data){ + if(self::isEncrypted($path)){ + $cached=OC_FileCache::getCached($path,'/'); + $data['size']=$cached['size']; + } + return $data; + } + + public function postFileSize($path,$size){ + if(self::isEncrypted($path)){ + $cached=OC_FileCache::getCached($path,'/'); + return $cached['size']; + }else{ + return $size; + } + } } diff --git a/apps/files_encryption/tests/encryption.php b/apps/files_encryption/tests/encryption.php index 70aa1daf4c..286770a69f 100644 --- a/apps/files_encryption/tests/encryption.php +++ b/apps/files_encryption/tests/encryption.php @@ -66,7 +66,7 @@ class Test_Encryption extends UnitTestCase { $this->assertEqual($decrypted,$source); $encrypted=OC_Crypt::blockEncrypt($source,$key); - $decrypted=OC_Crypt::blockDecrypt($encrypted,$key); + $decrypted=OC_Crypt::blockDecrypt($encrypted,$key,strlen($source)); $this->assertEqual($decrypted,$source); } } diff --git a/apps/files_encryption/tests/proxy.php b/apps/files_encryption/tests/proxy.php index 5616e2091a..4533289265 100644 --- a/apps/files_encryption/tests/proxy.php +++ b/apps/files_encryption/tests/proxy.php @@ -50,6 +50,7 @@ class Test_CryptProxy extends UnitTestCase { $fromFile=OC_Filesystem::file_get_contents('/file'); $this->assertNotEqual($original,$stored); + $this->assertEqual(strlen($original),strlen($fromFile)); $this->assertEqual($original,$fromFile); } @@ -88,6 +89,20 @@ class Test_CryptProxy extends UnitTestCase { $fromFile=OC_Filesystem::file_get_contents('/file'); $this->assertNotEqual($original,$stored); + $this->assertEqual(strlen($original),strlen($fromFile)); $this->assertEqual($original,$fromFile); + + $file=__DIR__.'/zeros'; + $original=file_get_contents($file); + + OC_Filesystem::file_put_contents('/file',$original); + + OC_FileProxy::$enabled=false; + $stored=OC_Filesystem::file_get_contents('/file'); + OC_FileProxy::$enabled=true; + + $fromFile=OC_Filesystem::file_get_contents('/file'); + $this->assertNotEqual($original,$stored); + $this->assertEqual(strlen($original),strlen($fromFile)); } } diff --git a/apps/files_encryption/tests/stream.php b/apps/files_encryption/tests/stream.php index 4ffeb6210a..d95ea792f7 100644 --- a/apps/files_encryption/tests/stream.php +++ b/apps/files_encryption/tests/stream.php @@ -10,23 +10,23 @@ class Test_CryptStream extends UnitTestCase { private $tmpFiles=array(); function testStream(){ - $stream=$this->getStream('test1','w'); + $stream=$this->getStream('test1','w',strlen('foobar')); fwrite($stream,'foobar'); fclose($stream); - $stream=$this->getStream('test1','r'); + $stream=$this->getStream('test1','r',strlen('foobar')); $data=fread($stream,6); fclose($stream); $this->assertEqual('foobar',$data); $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; $source=fopen($file,'r'); - $target=$this->getStream('test2','w'); + $target=$this->getStream('test2','w',0); OCP\Files::streamCopy($source,$target); fclose($target); fclose($source); - $stream=$this->getStream('test2','r'); + $stream=$this->getStream('test2','r',filesize($file)); $data=stream_get_contents($stream); $original=file_get_contents($file); $this->assertEqual(strlen($original),strlen($data)); @@ -37,9 +37,10 @@ class Test_CryptStream extends UnitTestCase { * get a cryptstream to a temporary file * @param string $id * @param string $mode + * @param int size * @return resource */ - function getStream($id,$mode){ + function getStream($id,$mode,$size){ if($id===''){ $id=uniqid(); } @@ -50,7 +51,7 @@ class Test_CryptStream extends UnitTestCase { $file=$this->tmpFiles[$id]; } $stream=fopen($file,$mode); - OC_CryptStream::$sourceStreams[$id]=array('path'=>'dummy'.$id,'stream'=>$stream); + OC_CryptStream::$sourceStreams[$id]=array('path'=>'dummy'.$id,'stream'=>$stream,'size'=>$size); return fopen('crypt://streams/'.$id,$mode); } @@ -58,11 +59,24 @@ class Test_CryptStream extends UnitTestCase { $file=__DIR__.'/binary'; $source=file_get_contents($file); - $stream=$this->getStream('test','w'); + $stream=$this->getStream('test','w',strlen($source)); fwrite($stream,$source); fclose($stream); - $stream=$this->getStream('test','r'); + $stream=$this->getStream('test','r',strlen($source)); + $data=stream_get_contents($stream); + fclose($stream); + $this->assertEqual(strlen($data),strlen($source)); + $this->assertEqual($source,$data); + + $file=__DIR__.'/zeros'; + $source=file_get_contents($file); + + $stream=$this->getStream('test2','w',strlen($source)); + fwrite($stream,$source); + fclose($stream); + + $stream=$this->getStream('test2','r',strlen($source)); $data=stream_get_contents($stream); fclose($stream); $this->assertEqual(strlen($data),strlen($source)); diff --git a/apps/files_encryption/tests/zeros b/apps/files_encryption/tests/zeros new file mode 100644 index 0000000000..ff982acf42 Binary files /dev/null and b/apps/files_encryption/tests/zeros differ diff --git a/lib/filecache.php b/lib/filecache.php index f93430fc9b..1d22bb34df 100644 --- a/lib/filecache.php +++ b/lib/filecache.php @@ -85,24 +85,20 @@ class OC_FileCache{ $root=''; } $path=$root.$path; - if($path=='/'){ - $parent=-1; - }else{ - $parent=self::getFileId(dirname($path)); - } - $id=self::getFileId($path); - if($id!=-1){ - self::update($id,$data); - return; - } - if(isset(self::$savedData[$path])){ - $data=array_merge($data,self::$savedData[$path]); - unset(self::$savedData[$path]); + $parent=self::getParentId($path); + $id=self::getId($path,''); + if(isset(OC_FileCache::$savedData[$path])){ + $data=array_merge(OC_FileCache::$savedData[$path],$data); + unset(OC_FileCache::$savedData[$path]); } if(!isset($data['size']) or !isset($data['mtime'])){//save incomplete data for the next time we write it self::$savedData[$path]=$data; return; } + if($id!=-1){ + self::update($id,$data); + return; + } if(!isset($data['encrypted'])){ $data['encrypted']=false; }