* See the COPYING-README file.
*/
-OC::$CLASSPATH['OC_Archive'] = 'apps/files_archive/lib/archive.php';
-OC::$CLASSPATH['Archive_Tar'] = '3rdparty/Archive/Tar.php';
-foreach(array('ZIP','TAR') as $type){
- OC::$CLASSPATH['OC_Archive_'.$type] = 'apps/files_archive/lib/'.strtolower($type).'.php';
-}
-
OC::$CLASSPATH['OC_Filestorage_Archive']='apps/files_archive/lib/storage.php';
OC_Hook::connect('OC_Filesystem','get_mountpoint','OC_Filestorage_Archive','autoMount');
+++ /dev/null
-<?php
-/**
- * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-abstract class OC_Archive{
- /**
- * open any of the supporeted archive types
- * @param string path
- * @return OC_Archive
- */
- public static function open($path){
- $ext=substr($path,strrpos($path,'.'));
- switch($ext){
- case '.zip':
- return new OC_Archive_ZIP($path);
- case '.gz':
- case '.bz':
- case '.bz2':
- if(strpos($path,'.tar.')){
- return new OC_Archive_TAR($path);
- }
- break;
- case '.tgz':
- return new OC_Archive_TAR($path);
- }
- }
-
- abstract function __construct($source);
- /**
- * add an empty folder to the archive
- * @param string path
- * @return bool
- */
- abstract function addFolder($path);
- /**
- * add a file to the archive
- * @param string path
- * @param string source either a local file or string data
- * @return bool
- */
- abstract function addFile($path,$source='');
- /**
- * rename a file or folder in the archive
- * @param string source
- * @param string dest
- * @return bool
- */
- abstract function rename($source,$dest);
- /**
- * get the uncompressed size of a file in the archive
- * @param string path
- * @return int
- */
- abstract function filesize($path);
- /**
- * get the last modified time of a file in the archive
- * @param string path
- * @return int
- */
- abstract function mtime($path);
- /**
- * get the files in a folder
- * @param path
- * @return array
- */
- abstract function getFolder($path);
- /**
- *get all files in the archive
- * @return array
- */
- abstract function getFiles();
- /**
- * get the content of a file
- * @param string path
- * @return string
- */
- abstract function getFile($path);
- /**
- * extract a single file from the archive
- * @param string path
- * @param string dest
- * @return bool
- */
- abstract function extractFile($path,$dest);
- /**
- * extract the archive
- * @param string path
- * @param string dest
- * @return bool
- */
- abstract function extract($dest);
- /**
- * check if a file or folder exists in the archive
- * @param string path
- * @return bool
- */
- abstract function fileExists($path);
- /**
- * remove a file or folder from the archive
- * @param string path
- * @return bool
- */
- abstract function remove($path);
- /**
- * get a file handler
- * @param string path
- * @param string mode
- * @return resource
- */
- abstract function getStream($path,$mode);
-}
+++ /dev/null
-<?php
-/**
- * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-class OC_Archive_TAR extends OC_Archive{
- const PLAIN=0;
- const GZIP=1;
- const BZIP=2;
-
- /**
- * @var Archive_Tar tar
- */
- private $tar=null;
- private $path;
-
- function __construct($source){
- $types=array(null,'gz','bz');
- $this->path=$source;
- $this->tar=new Archive_Tar($source,$types[self::getTarType($source)]);
- }
-
- /**
- * try to detect the type of tar compression
- * @param string file
- * @return str
- */
- static public function getTarType($file){
- if(strpos($file,'.')){
- $extension=substr($file,strrpos($file,'.'));
- switch($extension){
- case 'gz':
- case 'tgz':
- return self::GZIP;
- case 'bz':
- case 'bz2':
- return self::BZIP;
- default:
- return self::PLAIN;
- }
- }else{
- return self::PLAIN;
- }
- }
-
- /**
- * add an empty folder to the archive
- * @param string path
- * @return bool
- */
- function addFolder($path){
- $tmpBase=get_temp_dir().'/';
- if(substr($path,-1,1)!='/'){
- $path.='/';
- }
- if($this->fileExists($path)){
- return false;
- }
- mkdir($tmpBase.$path);
- $result=$this->tar->addModify(array($tmpBase.$path),'',$tmpBase);
- rmdir($tmpBase.$path);
- return $result;
- }
- /**
- * add a file to the archive
- * @param string path
- * @param string source either a local file or string data
- * @return bool
- */
- function addFile($path,$source=''){
- if($this->fileExists($path)){
- $this->remove($path);
- }
- if(file_exists($source)){
- $header=array();
- $dummy='';
- $this->tar->_openAppend();
- $result=$this->tar->_addfile($source,$header,$dummy,$dummy,$path);
- }else{
- $result=$this->tar->addString($path,$source);
- }
- return $result;
- }
-
- /**
- * rename a file or folder in the archive
- * @param string source
- * @param string dest
- * @return bool
- */
- function rename($source,$dest){
- //no proper way to delete, rename entire archive, rename file and remake archive
- $tmp=OCP\Files::tmpFolder();
- $this->tar->extract($tmp);
- rename($tmp.$source,$tmp.$dest);
- $this->tar=null;
- unlink($this->path);
- $types=array(null,'gz','bz');
- $this->tar=new Archive_Tar($this->path,$types[self::getTarType($this->path)]);
- $this->tar->createModify(array($tmp),'',$tmp.'/');
- }
-
- private function getHeader($file){
- $headers=$this->tar->listContent();
- foreach($headers as $header){
- if($file==$header['filename'] or $file.'/'==$header['filename']){
- return $header;
- }
- }
- return null;
- }
-
- /**
- * get the uncompressed size of a file in the archive
- * @param string path
- * @return int
- */
- function filesize($path){
- $stat=$this->getHeader($path);
- return $stat['size'];
- }
- /**
- * get the last modified time of a file in the archive
- * @param string path
- * @return int
- */
- function mtime($path){
- $stat=$this->getHeader($path);
- return $stat['mtime'];
- }
-
- /**
- * get the files in a folder
- * @param path
- * @return array
- */
- function getFolder($path){
- $files=$this->getFiles();
- $folderContent=array();
- $pathLength=strlen($path);
- foreach($files as $file){
- if(substr($file,0,$pathLength)==$path and $file!=$path){
- if(strrpos(substr($file,0,-1),'/')<=$pathLength){
- $folderContent[]=substr($file,$pathLength);
- }
- }
- }
- return $folderContent;
- }
- /**
- *get all files in the archive
- * @return array
- */
- function getFiles(){
- $headers=$this->tar->listContent();
- $files=array();
- foreach($headers as $header){
- $files[]=$header['filename'];
- }
- return $files;
- }
- /**
- * get the content of a file
- * @param string path
- * @return string
- */
- function getFile($path){
- return $this->tar->extractInString($path);
- }
- /**
- * extract a single file from the archive
- * @param string path
- * @param string dest
- * @return bool
- */
- function extractFile($path,$dest){
- $tmp=OCP\Files::tmpFolder();
- if(!$this->fileExists($path)){
- return false;
- }
- $success=$this->tar->extractList(array($path),$tmp);
- if($success){
- rename($tmp.$path,$dest);
- }
- OCP\Files::rmdirr($tmp);
- return $success;
- }
- /**
- * extract the archive
- * @param string path
- * @param string dest
- * @return bool
- */
- function extract($dest){
- return $this->tar->extract($dest);
- }
- /**
- * check if a file or folder exists in the archive
- * @param string path
- * @return bool
- */
- function fileExists($path){
- return $this->getHeader($path)!==null;
- }
-
- /**
- * remove a file or folder from the archive
- * @param string path
- * @return bool
- */
- function remove($path){
- if(!$this->fileExists($path)){
- return false;
- }
- //no proper way to delete, extract entire archive, delete file and remake archive
- $tmp=OCP\Files::tmpFolder();
- $this->tar->extract($tmp);
- OCP\Files::rmdirr($tmp.$path);
- $this->tar=null;
- unlink($this->path);
- $this->reopen();
- $this->tar->createModify(array($tmp),'',$tmp);
- return true;
- }
- /**
- * get a file handler
- * @param string path
- * @param string mode
- * @return resource
- */
- function getStream($path,$mode){
- if(strrpos($path,'.')!==false){
- $ext=substr($path,strrpos($path,'.'));
- }else{
- $ext='';
- }
- $tmpFile=OCP\Files::tmpFile($ext);
- if($this->fileExists($path)){
- $this->extractFile($path,$tmpFile);
- }elseif($mode=='r' or $mode=='rb'){
- return false;
- }
- if($mode=='r' or $mode=='rb'){
- return fopen($tmpFile,$mode);
- }else{
- OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack');
- self::$tempFiles[$tmpFile]=$path;
- return fopen('close://'.$tmpFile,$mode);
- }
- }
-
- private static $tempFiles=array();
- /**
- * write back temporary files
- */
- function writeBack($tmpFile){
- if(isset(self::$tempFiles[$tmpFile])){
- $this->addFile(self::$tempFiles[$tmpFile],$tmpFile);
- unlink($tmpFile);
- }
- }
-
- /**
- * reopen the archive to ensure everything is written
- */
- private function reopen(){
- if($this->tar){
- $this->tar->_close();
- $this->tar=null;
- }
- $types=array(null,'gz','bz');
- $this->tar=new Archive_Tar($this->path,$types[self::getTarType($this->path)]);
- }
-}
+++ /dev/null
-<?php
-/**
- * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-class OC_Archive_ZIP extends OC_Archive{
- /**
- * @var ZipArchive zip
- */
- private $zip=null;
- private $success=false;
- private $path;
-
- function __construct($source){
- $this->path=$source;
- $this->zip=new ZipArchive();
- if($this->zip->open($source,ZipArchive::CREATE)){
- }else{
- OCP\Util::writeLog('files_archive','Error while opening archive '.$source,OCP\Util::WARN);
- }
- }
- /**
- * add an empty folder to the archive
- * @param string path
- * @return bool
- */
- function addFolder($path){
- return $this->zip->addEmptyDir($path);
- }
- /**
- * add a file to the archive
- * @param string path
- * @param string source either a local file or string data
- * @return bool
- */
- function addFile($path,$source=''){
- if(file_exists($source)){
- $result=$this->zip->addFile($source,$path);
- }else{
- $result=$this->zip->addFromString($path,$source);
- }
- if($result){
- $this->zip->close();//close and reopen to save the zip
- $this->zip->open($this->path);
- }
- return $result;
- }
- /**
- * rename a file or folder in the archive
- * @param string source
- * @param string dest
- * @return bool
- */
- function rename($source,$dest){
- $source=$this->stripPath($source);
- $dest=$this->stripPath($dest);
- $this->zip->renameName($source,$dest);
- }
- /**
- * get the uncompressed size of a file in the archive
- * @param string path
- * @return int
- */
- function filesize($path){
- $stat=$this->zip->statName($path);
- return $stat['size'];
- }
- /**
- * get the last modified time of a file in the archive
- * @param string path
- * @return int
- */
- function mtime($path){
- $stat=$this->zip->statName($path);
- return $stat['mtime'];
- }
- /**
- * get the files in a folder
- * @param path
- * @return array
- */
- function getFolder($path){
- $files=$this->getFiles();
- $folderContent=array();
- $pathLength=strlen($path);
- foreach($files as $file){
- if(substr($file,0,$pathLength)==$path and $file!=$path){
- if(strrpos(substr($file,0,-1),'/')<=$pathLength){
- $folderContent[]=substr($file,$pathLength);
- }
- }
- }
- return $folderContent;
- }
- /**
- *get all files in the archive
- * @return array
- */
- function getFiles(){
- $fileCount=$this->zip->numFiles;
- $files=array();
- for($i=0;$i<$fileCount;$i++){
- $files[]=$this->zip->getNameIndex($i);
- }
- return $files;
- }
- /**
- * get the content of a file
- * @param string path
- * @return string
- */
- function getFile($path){
- return $this->zip->getFromName($path);
- }
- /**
- * extract a single file from the archive
- * @param string path
- * @param string dest
- * @return bool
- */
- function extractFile($path,$dest){
- $fp = $this->zip->getStream($path);
- file_put_contents($dest,$fp);
- }
- /**
- * extract the archive
- * @param string path
- * @param string dest
- * @return bool
- */
- function extract($dest){
- return $this->zip->extractTo($dest);
- }
- /**
- * check if a file or folder exists in the archive
- * @param string path
- * @return bool
- */
- function fileExists($path){
- return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false);
- }
- /**
- * remove a file or folder from the archive
- * @param string path
- * @return bool
- */
- function remove($path){
- if($this->fileExists($path.'/')){
- return $this->zip->deleteName($path.'/');
- }else{
- return $this->zip->deleteName($path);
- }
- }
- /**
- * get a file handler
- * @param string path
- * @param string mode
- * @return resource
- */
- function getStream($path,$mode){
- if($mode=='r' or $mode=='rb'){
- return $this->zip->getStream($path);
- }else{//since we cant directly get a writable stream, make a temp copy of the file and put it back in the archive when the stream is closed
- if(strrpos($path,'.')!==false){
- $ext=substr($path,strrpos($path,'.'));
- }else{
- $ext='';
- }
- $tmpFile=OCP\Files::tmpFile($ext);
- OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack');
- if($this->fileExists($path)){
- $this->extractFile($path,$tmpFile);
- }
- self::$tempFiles[$tmpFile]=$path;
- return fopen('close://'.$tmpFile,$mode);
- }
- }
-
- private static $tempFiles=array();
- /**
- * write back temporary files
- */
- function writeBack($tmpFile){
- if(isset(self::$tempFiles[$tmpFile])){
- $this->addFile(self::$tempFiles[$tmpFile],$tmpFile);
- unlink($tmpFile);
- }
- }
-
- private function stripPath($path){
- if(substr($path,0,1)=='/'){
- return substr($path,1);
- }else{
- return $path;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-abstract class Test_Archive extends UnitTestCase {
- /**
- * @var OC_Archive
- */
- protected $instance;
-
- /**
- * get the existing test archive
- * @return OC_Archive
- */
- abstract protected function getExisting();
- /**
- * get a new archive for write testing
- * @return OC_Archive
- */
- abstract protected function getNew();
-
- public function testGetFiles(){
- $this->instance=$this->getExisting();
- $allFiles=$this->instance->getFiles();
- $expected=array('lorem.txt','logo-wide.png','dir/','dir/lorem.txt');
- $this->assertEqual(4,count($allFiles),'only found '.count($allFiles).' out of 4 expected files');
- foreach($expected as $file){
- $this->assertNotIdentical(false,array_search($file,$allFiles),'cant find '.$file.' in archive');
- $this->assertTrue($this->instance->fileExists($file),'file '.$file.' does not exist in archive');
- }
- $this->assertFalse($this->instance->fileExists('non/existing/file'));
-
- $rootContent=$this->instance->getFolder('');
- $expected=array('lorem.txt','logo-wide.png','dir/');
- $this->assertEqual(3,count($rootContent));
- foreach($expected as $file){
- $this->assertNotIdentical(false,array_search($file,$rootContent),'cant find '.$file.' in archive');
- }
-
- $dirContent=$this->instance->getFolder('dir/');
- $expected=array('lorem.txt');
- $this->assertEqual(1,count($dirContent));
- foreach($expected as $file){
- $this->assertNotIdentical(false,array_search($file,$dirContent),'cant find '.$file.' in archive');
- }
- }
-
- public function testContent(){
- $this->instance=$this->getExisting();
- $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
- $textFile=$dir.'/lorem.txt';
- $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt'));
-
- $tmpFile=OCP\Files::tmpFile('.txt');
- $this->instance->extractFile('lorem.txt',$tmpFile);
- $this->assertEqual(file_get_contents($textFile),file_get_contents($tmpFile));
- }
-
- public function testWrite(){
- $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
- $textFile=$dir.'/lorem.txt';
- $this->instance=$this->getNew();
- $this->assertEqual(0,count($this->instance->getFiles()));
- $this->instance->addFile('lorem.txt',$textFile);
- $this->assertEqual(1,count($this->instance->getFiles()));
- $this->assertTrue($this->instance->fileExists('lorem.txt'));
- $this->assertFalse($this->instance->fileExists('lorem.txt/'));
-
- $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt'));
- $this->instance->addFile('lorem.txt','foobar');
- $this->assertEqual('foobar',$this->instance->getFile('lorem.txt'));
- }
-
- public function testReadStream(){
- $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
- $this->instance=$this->getExisting();
- $fh=$this->instance->getStream('lorem.txt','r');
- $this->assertTrue($fh);
- $content=fread($fh,$this->instance->filesize('lorem.txt'));
- fclose($fh);
- $this->assertEqual(file_get_contents($dir.'/lorem.txt'),$content);
- }
- public function testWriteStream(){
- $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
- $this->instance=$this->getNew();
- $fh=$this->instance->getStream('lorem.txt','w');
- $source=fopen($dir.'/lorem.txt','r');
- OCP\Files::streamCopy($source,$fh);
- fclose($source);
- fclose($fh);
- $this->assertTrue($this->instance->fileExists('lorem.txt'));
- $this->assertEqual(file_get_contents($dir.'/lorem.txt'),$this->instance->getFile('lorem.txt'));
- }
- public function testFolder(){
- $this->instance=$this->getNew();
- $this->assertFalse($this->instance->fileExists('/test'));
- $this->assertFalse($this->instance->fileExists('/test/'));
- $this->instance->addFolder('/test');
- $this->assertTrue($this->instance->fileExists('/test'));
- $this->assertTrue($this->instance->fileExists('/test/'));
- $this->instance->remove('/test');
- $this->assertFalse($this->instance->fileExists('/test'));
- $this->assertFalse($this->instance->fileExists('/test/'));
- }
- public function testExtract(){
- $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
- $this->instance=$this->getExisting();
- $tmpDir=OCP\Files::tmpFolder();
- $this->instance->extract($tmpDir);
- $this->assertEqual(true,file_exists($tmpDir.'lorem.txt'));
- $this->assertEqual(true,file_exists($tmpDir.'dir/lorem.txt'));
- $this->assertEqual(true,file_exists($tmpDir.'logo-wide.png'));
- $this->assertEqual(file_get_contents($dir.'/lorem.txt'),file_get_contents($tmpDir.'lorem.txt'));
- OCP\Files::rmdirr($tmpDir);
- }
- public function testMoveRemove(){
- $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
- $textFile=$dir.'/lorem.txt';
- $this->instance=$this->getNew();
- $this->instance->addFile('lorem.txt',$textFile);
- $this->assertFalse($this->instance->fileExists('target.txt'));
- $this->instance->rename('lorem.txt','target.txt');
- $this->assertTrue($this->instance->fileExists('target.txt'));
- $this->assertFalse($this->instance->fileExists('lorem.txt'));
- $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('target.txt'));
- $this->instance->remove('target.txt');
- $this->assertFalse($this->instance->fileExists('target.txt'));
- }
-}
+++ /dev/null
-<?php
-/**
- * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-require_once('archive.php');
-
-if(is_dir(OC::$SERVERROOT.'/apps/files_archive/tests/data')){
- class Test_Archive_TAR extends Test_Archive{
- protected function getExisting(){
- $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
- return new OC_Archive_TAR($dir.'/data.tar.gz');
- }
-
- protected function getNew(){
- return new OC_Archive_TAR(OCP\Files::tmpFile('.tar.gz'));
- }
- }
-}else{
- abstract class Test_Archive_TAR extends Test_Archive{}
-}
+++ /dev/null
-<?php
-/**
- * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-require_once('archive.php');
-
-if(is_dir(OC::$SERVERROOT.'/apps/files_archive/tests/data')){
- class Test_Archive_ZIP extends Test_Archive{
- protected function getExisting(){
- $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
- return new OC_Archive_ZIP($dir.'/data.zip');
- }
-
- protected function getNew(){
- return new OC_Archive_ZIP(OCP\Files::tmpFile('.zip'));
- }
- }
-}else{
- abstract class Test_Archive_ZIP extends Test_Archive{}
-}
--- /dev/null
+<?php
+/**
+ * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+abstract class OC_Archive{
+ /**
+ * open any of the supporeted archive types
+ * @param string path
+ * @return OC_Archive
+ */
+ public static function open($path){
+ $ext=substr($path,strrpos($path,'.'));
+ switch($ext){
+ case '.zip':
+ return new OC_Archive_ZIP($path);
+ case '.gz':
+ case '.bz':
+ case '.bz2':
+ if(strpos($path,'.tar.')){
+ return new OC_Archive_TAR($path);
+ }
+ break;
+ case '.tgz':
+ return new OC_Archive_TAR($path);
+ }
+ }
+
+ abstract function __construct($source);
+ /**
+ * add an empty folder to the archive
+ * @param string path
+ * @return bool
+ */
+ abstract function addFolder($path);
+ /**
+ * add a file to the archive
+ * @param string path
+ * @param string source either a local file or string data
+ * @return bool
+ */
+ abstract function addFile($path,$source='');
+ /**
+ * rename a file or folder in the archive
+ * @param string source
+ * @param string dest
+ * @return bool
+ */
+ abstract function rename($source,$dest);
+ /**
+ * get the uncompressed size of a file in the archive
+ * @param string path
+ * @return int
+ */
+ abstract function filesize($path);
+ /**
+ * get the last modified time of a file in the archive
+ * @param string path
+ * @return int
+ */
+ abstract function mtime($path);
+ /**
+ * get the files in a folder
+ * @param path
+ * @return array
+ */
+ abstract function getFolder($path);
+ /**
+ *get all files in the archive
+ * @return array
+ */
+ abstract function getFiles();
+ /**
+ * get the content of a file
+ * @param string path
+ * @return string
+ */
+ abstract function getFile($path);
+ /**
+ * extract a single file from the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ abstract function extractFile($path,$dest);
+ /**
+ * extract the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ abstract function extract($dest);
+ /**
+ * check if a file or folder exists in the archive
+ * @param string path
+ * @return bool
+ */
+ abstract function fileExists($path);
+ /**
+ * remove a file or folder from the archive
+ * @param string path
+ * @return bool
+ */
+ abstract function remove($path);
+ /**
+ * get a file handler
+ * @param string path
+ * @param string mode
+ * @return resource
+ */
+ abstract function getStream($path,$mode);
+}
--- /dev/null
+<?php
+/**
+ * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+require_once '3rdparty/Archive/Tar.php';
+
+class OC_Archive_TAR extends OC_Archive{
+ const PLAIN=0;
+ const GZIP=1;
+ const BZIP=2;
+
+ /**
+ * @var Archive_Tar tar
+ */
+ private $tar=null;
+ private $path;
+
+ function __construct($source){
+ $types=array(null,'gz','bz');
+ $this->path=$source;
+ $this->tar=new Archive_Tar($source,$types[self::getTarType($source)]);
+ }
+
+ /**
+ * try to detect the type of tar compression
+ * @param string file
+ * @return str
+ */
+ static public function getTarType($file){
+ if(strpos($file,'.')){
+ $extension=substr($file,strrpos($file,'.'));
+ switch($extension){
+ case 'gz':
+ case 'tgz':
+ return self::GZIP;
+ case 'bz':
+ case 'bz2':
+ return self::BZIP;
+ default:
+ return self::PLAIN;
+ }
+ }else{
+ return self::PLAIN;
+ }
+ }
+
+ /**
+ * add an empty folder to the archive
+ * @param string path
+ * @return bool
+ */
+ function addFolder($path){
+ $tmpBase=get_temp_dir().'/';
+ if(substr($path,-1,1)!='/'){
+ $path.='/';
+ }
+ if($this->fileExists($path)){
+ return false;
+ }
+ mkdir($tmpBase.$path);
+ $result=$this->tar->addModify(array($tmpBase.$path),'',$tmpBase);
+ rmdir($tmpBase.$path);
+ return $result;
+ }
+ /**
+ * add a file to the archive
+ * @param string path
+ * @param string source either a local file or string data
+ * @return bool
+ */
+ function addFile($path,$source=''){
+ if($this->fileExists($path)){
+ $this->remove($path);
+ }
+ if(file_exists($source)){
+ $header=array();
+ $dummy='';
+ $this->tar->_openAppend();
+ $result=$this->tar->_addfile($source,$header,$dummy,$dummy,$path);
+ }else{
+ $result=$this->tar->addString($path,$source);
+ }
+ return $result;
+ }
+
+ /**
+ * rename a file or folder in the archive
+ * @param string source
+ * @param string dest
+ * @return bool
+ */
+ function rename($source,$dest){
+ //no proper way to delete, rename entire archive, rename file and remake archive
+ $tmp=OCP\Files::tmpFolder();
+ $this->tar->extract($tmp);
+ rename($tmp.$source,$tmp.$dest);
+ $this->tar=null;
+ unlink($this->path);
+ $types=array(null,'gz','bz');
+ $this->tar=new Archive_Tar($this->path,$types[self::getTarType($this->path)]);
+ $this->tar->createModify(array($tmp),'',$tmp.'/');
+ }
+
+ private function getHeader($file){
+ $headers=$this->tar->listContent();
+ foreach($headers as $header){
+ if($file==$header['filename'] or $file.'/'==$header['filename']){
+ return $header;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * get the uncompressed size of a file in the archive
+ * @param string path
+ * @return int
+ */
+ function filesize($path){
+ $stat=$this->getHeader($path);
+ return $stat['size'];
+ }
+ /**
+ * get the last modified time of a file in the archive
+ * @param string path
+ * @return int
+ */
+ function mtime($path){
+ $stat=$this->getHeader($path);
+ return $stat['mtime'];
+ }
+
+ /**
+ * get the files in a folder
+ * @param path
+ * @return array
+ */
+ function getFolder($path){
+ $files=$this->getFiles();
+ $folderContent=array();
+ $pathLength=strlen($path);
+ foreach($files as $file){
+ if(substr($file,0,$pathLength)==$path and $file!=$path){
+ if(strrpos(substr($file,0,-1),'/')<=$pathLength){
+ $folderContent[]=substr($file,$pathLength);
+ }
+ }
+ }
+ return $folderContent;
+ }
+ /**
+ *get all files in the archive
+ * @return array
+ */
+ function getFiles(){
+ $headers=$this->tar->listContent();
+ $files=array();
+ foreach($headers as $header){
+ $files[]=$header['filename'];
+ }
+ return $files;
+ }
+ /**
+ * get the content of a file
+ * @param string path
+ * @return string
+ */
+ function getFile($path){
+ return $this->tar->extractInString($path);
+ }
+ /**
+ * extract a single file from the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ function extractFile($path,$dest){
+ $tmp=OCP\Files::tmpFolder();
+ if(!$this->fileExists($path)){
+ return false;
+ }
+ $success=$this->tar->extractList(array($path),$tmp);
+ if($success){
+ rename($tmp.$path,$dest);
+ }
+ OCP\Files::rmdirr($tmp);
+ return $success;
+ }
+ /**
+ * extract the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ function extract($dest){
+ return $this->tar->extract($dest);
+ }
+ /**
+ * check if a file or folder exists in the archive
+ * @param string path
+ * @return bool
+ */
+ function fileExists($path){
+ return $this->getHeader($path)!==null;
+ }
+
+ /**
+ * remove a file or folder from the archive
+ * @param string path
+ * @return bool
+ */
+ function remove($path){
+ if(!$this->fileExists($path)){
+ return false;
+ }
+ //no proper way to delete, extract entire archive, delete file and remake archive
+ $tmp=OCP\Files::tmpFolder();
+ $this->tar->extract($tmp);
+ OCP\Files::rmdirr($tmp.$path);
+ $this->tar=null;
+ unlink($this->path);
+ $this->reopen();
+ $this->tar->createModify(array($tmp),'',$tmp);
+ return true;
+ }
+ /**
+ * get a file handler
+ * @param string path
+ * @param string mode
+ * @return resource
+ */
+ function getStream($path,$mode){
+ if(strrpos($path,'.')!==false){
+ $ext=substr($path,strrpos($path,'.'));
+ }else{
+ $ext='';
+ }
+ $tmpFile=OCP\Files::tmpFile($ext);
+ if($this->fileExists($path)){
+ $this->extractFile($path,$tmpFile);
+ }elseif($mode=='r' or $mode=='rb'){
+ return false;
+ }
+ if($mode=='r' or $mode=='rb'){
+ return fopen($tmpFile,$mode);
+ }else{
+ OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack');
+ self::$tempFiles[$tmpFile]=$path;
+ return fopen('close://'.$tmpFile,$mode);
+ }
+ }
+
+ private static $tempFiles=array();
+ /**
+ * write back temporary files
+ */
+ function writeBack($tmpFile){
+ if(isset(self::$tempFiles[$tmpFile])){
+ $this->addFile(self::$tempFiles[$tmpFile],$tmpFile);
+ unlink($tmpFile);
+ }
+ }
+
+ /**
+ * reopen the archive to ensure everything is written
+ */
+ private function reopen(){
+ if($this->tar){
+ $this->tar->_close();
+ $this->tar=null;
+ }
+ $types=array(null,'gz','bz');
+ $this->tar=new Archive_Tar($this->path,$types[self::getTarType($this->path)]);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+class OC_Archive_ZIP extends OC_Archive{
+ /**
+ * @var ZipArchive zip
+ */
+ private $zip=null;
+ private $success=false;
+ private $path;
+
+ function __construct($source){
+ $this->path=$source;
+ $this->zip=new ZipArchive();
+ if($this->zip->open($source,ZipArchive::CREATE)){
+ }else{
+ OCP\Util::writeLog('files_archive','Error while opening archive '.$source,OCP\Util::WARN);
+ }
+ }
+ /**
+ * add an empty folder to the archive
+ * @param string path
+ * @return bool
+ */
+ function addFolder($path){
+ return $this->zip->addEmptyDir($path);
+ }
+ /**
+ * add a file to the archive
+ * @param string path
+ * @param string source either a local file or string data
+ * @return bool
+ */
+ function addFile($path,$source=''){
+ if(file_exists($source)){
+ $result=$this->zip->addFile($source,$path);
+ }else{
+ $result=$this->zip->addFromString($path,$source);
+ }
+ if($result){
+ $this->zip->close();//close and reopen to save the zip
+ $this->zip->open($this->path);
+ }
+ return $result;
+ }
+ /**
+ * rename a file or folder in the archive
+ * @param string source
+ * @param string dest
+ * @return bool
+ */
+ function rename($source,$dest){
+ $source=$this->stripPath($source);
+ $dest=$this->stripPath($dest);
+ $this->zip->renameName($source,$dest);
+ }
+ /**
+ * get the uncompressed size of a file in the archive
+ * @param string path
+ * @return int
+ */
+ function filesize($path){
+ $stat=$this->zip->statName($path);
+ return $stat['size'];
+ }
+ /**
+ * get the last modified time of a file in the archive
+ * @param string path
+ * @return int
+ */
+ function mtime($path){
+ $stat=$this->zip->statName($path);
+ return $stat['mtime'];
+ }
+ /**
+ * get the files in a folder
+ * @param path
+ * @return array
+ */
+ function getFolder($path){
+ $files=$this->getFiles();
+ $folderContent=array();
+ $pathLength=strlen($path);
+ foreach($files as $file){
+ if(substr($file,0,$pathLength)==$path and $file!=$path){
+ if(strrpos(substr($file,0,-1),'/')<=$pathLength){
+ $folderContent[]=substr($file,$pathLength);
+ }
+ }
+ }
+ return $folderContent;
+ }
+ /**
+ *get all files in the archive
+ * @return array
+ */
+ function getFiles(){
+ $fileCount=$this->zip->numFiles;
+ $files=array();
+ for($i=0;$i<$fileCount;$i++){
+ $files[]=$this->zip->getNameIndex($i);
+ }
+ return $files;
+ }
+ /**
+ * get the content of a file
+ * @param string path
+ * @return string
+ */
+ function getFile($path){
+ return $this->zip->getFromName($path);
+ }
+ /**
+ * extract a single file from the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ function extractFile($path,$dest){
+ $fp = $this->zip->getStream($path);
+ file_put_contents($dest,$fp);
+ }
+ /**
+ * extract the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ function extract($dest){
+ return $this->zip->extractTo($dest);
+ }
+ /**
+ * check if a file or folder exists in the archive
+ * @param string path
+ * @return bool
+ */
+ function fileExists($path){
+ return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false);
+ }
+ /**
+ * remove a file or folder from the archive
+ * @param string path
+ * @return bool
+ */
+ function remove($path){
+ if($this->fileExists($path.'/')){
+ return $this->zip->deleteName($path.'/');
+ }else{
+ return $this->zip->deleteName($path);
+ }
+ }
+ /**
+ * get a file handler
+ * @param string path
+ * @param string mode
+ * @return resource
+ */
+ function getStream($path,$mode){
+ if($mode=='r' or $mode=='rb'){
+ return $this->zip->getStream($path);
+ }else{//since we cant directly get a writable stream, make a temp copy of the file and put it back in the archive when the stream is closed
+ if(strrpos($path,'.')!==false){
+ $ext=substr($path,strrpos($path,'.'));
+ }else{
+ $ext='';
+ }
+ $tmpFile=OCP\Files::tmpFile($ext);
+ OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack');
+ if($this->fileExists($path)){
+ $this->extractFile($path,$tmpFile);
+ }
+ self::$tempFiles[$tmpFile]=$path;
+ return fopen('close://'.$tmpFile,$mode);
+ }
+ }
+
+ private static $tempFiles=array();
+ /**
+ * write back temporary files
+ */
+ function writeBack($tmpFile){
+ if(isset(self::$tempFiles[$tmpFile])){
+ $this->addFile(self::$tempFiles[$tmpFile],$tmpFile);
+ unlink($tmpFile);
+ }
+ }
+
+ private function stripPath($path){
+ if(substr($path,0,1)=='/'){
+ return substr($path,1);
+ }else{
+ return $path;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+abstract class Test_Archive extends UnitTestCase {
+ /**
+ * @var OC_Archive
+ */
+ protected $instance;
+
+ /**
+ * get the existing test archive
+ * @return OC_Archive
+ */
+ abstract protected function getExisting();
+ /**
+ * get a new archive for write testing
+ * @return OC_Archive
+ */
+ abstract protected function getNew();
+
+ public function testGetFiles(){
+ $this->instance=$this->getExisting();
+ $allFiles=$this->instance->getFiles();
+ $expected=array('lorem.txt','logo-wide.png','dir/','dir/lorem.txt');
+ $this->assertEqual(4,count($allFiles),'only found '.count($allFiles).' out of 4 expected files');
+ foreach($expected as $file){
+ $this->assertNotIdentical(false,array_search($file,$allFiles),'cant find '.$file.' in archive');
+ $this->assertTrue($this->instance->fileExists($file),'file '.$file.' does not exist in archive');
+ }
+ $this->assertFalse($this->instance->fileExists('non/existing/file'));
+
+ $rootContent=$this->instance->getFolder('');
+ $expected=array('lorem.txt','logo-wide.png','dir/');
+ $this->assertEqual(3,count($rootContent));
+ foreach($expected as $file){
+ $this->assertNotIdentical(false,array_search($file,$rootContent),'cant find '.$file.' in archive');
+ }
+
+ $dirContent=$this->instance->getFolder('dir/');
+ $expected=array('lorem.txt');
+ $this->assertEqual(1,count($dirContent));
+ foreach($expected as $file){
+ $this->assertNotIdentical(false,array_search($file,$dirContent),'cant find '.$file.' in archive');
+ }
+ }
+
+ public function testContent(){
+ $this->instance=$this->getExisting();
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $textFile=$dir.'/lorem.txt';
+ $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt'));
+
+ $tmpFile=OCP\Files::tmpFile('.txt');
+ $this->instance->extractFile('lorem.txt',$tmpFile);
+ $this->assertEqual(file_get_contents($textFile),file_get_contents($tmpFile));
+ }
+
+ public function testWrite(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $textFile=$dir.'/lorem.txt';
+ $this->instance=$this->getNew();
+ $this->assertEqual(0,count($this->instance->getFiles()));
+ $this->instance->addFile('lorem.txt',$textFile);
+ $this->assertEqual(1,count($this->instance->getFiles()));
+ $this->assertTrue($this->instance->fileExists('lorem.txt'));
+ $this->assertFalse($this->instance->fileExists('lorem.txt/'));
+
+ $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt'));
+ $this->instance->addFile('lorem.txt','foobar');
+ $this->assertEqual('foobar',$this->instance->getFile('lorem.txt'));
+ }
+
+ public function testReadStream(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $this->instance=$this->getExisting();
+ $fh=$this->instance->getStream('lorem.txt','r');
+ $this->assertTrue($fh);
+ $content=fread($fh,$this->instance->filesize('lorem.txt'));
+ fclose($fh);
+ $this->assertEqual(file_get_contents($dir.'/lorem.txt'),$content);
+ }
+ public function testWriteStream(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $this->instance=$this->getNew();
+ $fh=$this->instance->getStream('lorem.txt','w');
+ $source=fopen($dir.'/lorem.txt','r');
+ OCP\Files::streamCopy($source,$fh);
+ fclose($source);
+ fclose($fh);
+ $this->assertTrue($this->instance->fileExists('lorem.txt'));
+ $this->assertEqual(file_get_contents($dir.'/lorem.txt'),$this->instance->getFile('lorem.txt'));
+ }
+ public function testFolder(){
+ $this->instance=$this->getNew();
+ $this->assertFalse($this->instance->fileExists('/test'));
+ $this->assertFalse($this->instance->fileExists('/test/'));
+ $this->instance->addFolder('/test');
+ $this->assertTrue($this->instance->fileExists('/test'));
+ $this->assertTrue($this->instance->fileExists('/test/'));
+ $this->instance->remove('/test');
+ $this->assertFalse($this->instance->fileExists('/test'));
+ $this->assertFalse($this->instance->fileExists('/test/'));
+ }
+ public function testExtract(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $this->instance=$this->getExisting();
+ $tmpDir=OCP\Files::tmpFolder();
+ $this->instance->extract($tmpDir);
+ $this->assertEqual(true,file_exists($tmpDir.'lorem.txt'));
+ $this->assertEqual(true,file_exists($tmpDir.'dir/lorem.txt'));
+ $this->assertEqual(true,file_exists($tmpDir.'logo-wide.png'));
+ $this->assertEqual(file_get_contents($dir.'/lorem.txt'),file_get_contents($tmpDir.'lorem.txt'));
+ OCP\Files::rmdirr($tmpDir);
+ }
+ public function testMoveRemove(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $textFile=$dir.'/lorem.txt';
+ $this->instance=$this->getNew();
+ $this->instance->addFile('lorem.txt',$textFile);
+ $this->assertFalse($this->instance->fileExists('target.txt'));
+ $this->instance->rename('lorem.txt','target.txt');
+ $this->assertTrue($this->instance->fileExists('target.txt'));
+ $this->assertFalse($this->instance->fileExists('lorem.txt'));
+ $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('target.txt'));
+ $this->instance->remove('target.txt');
+ $this->assertFalse($this->instance->fileExists('target.txt'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+require_once('archive.php');
+
+if(is_dir(OC::$SERVERROOT.'/apps/files_archive/tests/data')){
+ class Test_Archive_TAR extends Test_Archive{
+ protected function getExisting(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ return new OC_Archive_TAR($dir.'/data.tar.gz');
+ }
+
+ protected function getNew(){
+ return new OC_Archive_TAR(OCP\Files::tmpFile('.tar.gz'));
+ }
+ }
+}else{
+ abstract class Test_Archive_TAR extends Test_Archive{}
+}
--- /dev/null
+<?php
+/**
+ * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+require_once('archive.php');
+
+if(is_dir(OC::$SERVERROOT.'/apps/files_archive/tests/data')){
+ class Test_Archive_ZIP extends Test_Archive{
+ protected function getExisting(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ return new OC_Archive_ZIP($dir.'/data.zip');
+ }
+
+ protected function getNew(){
+ return new OC_Archive_ZIP(OCP\Files::tmpFile('.zip'));
+ }
+ }
+}else{
+ abstract class Test_Archive_ZIP extends Test_Archive{}
+}