From 48fe85d9bd7fc6a82f54d23befe06c2457b590bc Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 2 Mar 2012 18:42:23 +0100 Subject: [PATCH] add streamwrapper that provides a callback on stream close --- lib/base.php | 1 + lib/streamwrappers.php | 86 ++++++++++++++++++++++++++++++++++++ tests/lib/streamwrappers.php | 31 +++++++++++++ 3 files changed, 118 insertions(+) diff --git a/lib/base.php b/lib/base.php index 336ff9fa231..4e24f9f44ac 100644 --- a/lib/base.php +++ b/lib/base.php @@ -148,6 +148,7 @@ class OC{ require_once('streamwrappers.php'); stream_wrapper_register("fakedir", "OC_FakeDirStream"); stream_wrapper_register('static', 'OC_StaticStreamWrapper'); + stream_wrapper_register('close', 'OC_CloseStreamWrapper'); // calculate the documentroot OC::$DOCUMENTROOT=realpath($_SERVER['DOCUMENT_ROOT']); diff --git a/lib/streamwrappers.php b/lib/streamwrappers.php index 05d5598819a..f1e0fa0e1d9 100644 --- a/lib/streamwrappers.php +++ b/lib/streamwrappers.php @@ -218,3 +218,89 @@ class OC_StaticStreamWrapper { return false; } } + +/** + * stream wrapper that provides a callback on stream close + */ +class OC_CloseStreamWrapper{ + public static $callBacks=array(); + private $path=''; + private $source; + private static $open=array(); + public function stream_open($path, $mode, $options, &$opened_path){ + $path=substr($path,strlen('close://')); + $this->path=$path; + $this->source=fopen($path,$mode); + if(is_resource($this->source)){ + $this->meta=stream_get_meta_data($this->source); + } + self::$open[]=$path; + return is_resource($this->source); + } + + public function stream_seek($offset, $whence=SEEK_SET){ + fseek($this->source,$offset,$whence); + } + + public function stream_tell(){ + return ftell($this->source); + } + + public function stream_read($count){ + return fread($this->source,$count); + } + + public function stream_write($data){ + return fwrite($this->source,$data); + } + + public function stream_set_option($option,$arg1,$arg2){ + switch($option){ + case STREAM_OPTION_BLOCKING: + stream_set_blocking($this->source,$arg1); + break; + case STREAM_OPTION_READ_TIMEOUT: + stream_set_timeout($this->source,$arg1,$arg2); + break; + case STREAM_OPTION_WRITE_BUFFER: + stream_set_write_buffer($this->source,$arg1,$arg2); + } + } + + public function stream_stat(){ + return fstat($this->source); + } + + public function stream_lock($mode){ + flock($this->source,$mode); + } + + public function stream_flush(){ + return fflush($this->source); + } + + public function stream_eof(){ + return feof($this->source); + } + + public function url_stat($path) { + $path=substr($path,strlen('close://')); + if(file_exists($path)){ + return stat($path); + }else{ + return false; + } + } + + public function stream_close(){ + fclose($this->source); + if(isset(self::$callBacks[$this->path])){ + call_user_func(self::$callBacks[$this->path],$this->path); + } + } + + public function unlink($path){ + $path=substr($path,strlen('close://')); + return unlink($path); + } +} diff --git a/tests/lib/streamwrappers.php b/tests/lib/streamwrappers.php index c4784a62976..17a92c6658c 100644 --- a/tests/lib/streamwrappers.php +++ b/tests/lib/streamwrappers.php @@ -44,4 +44,35 @@ class Test_StreamWrappers extends UnitTestCase { clearstatcache(); $this->assertFalse(file_exists($staticFile)); } + + public function testCloseStream(){ + //ensure all basic stream stuff works + $sourceFile=OC::$SERVERROOT.'/tests/data/lorem.txt'; + $tmpFile=OC_Helper::TmpFile('.txt'); + $file='close://'.$tmpFile; + $this->assertTrue(file_exists($file)); + file_put_contents($file,file_get_contents($sourceFile)); + $this->assertEqual(file_get_contents($sourceFile),file_get_contents($file)); + unlink($file); + clearstatcache(); + $this->assertFalse(file_exists($file)); + + //test callback + $tmpFile=OC_Helper::TmpFile('.txt'); + $file='close://'.$tmpFile; + OC_CloseStreamWrapper::$callBacks[$tmpFile]=array('Test_StreamWrappers','closeCallBack'); + $fh=fopen($file,'w'); + fwrite($fh,'asd'); + try{ + fclose($fh); + $this->fail('Expected exception'); + }catch(Exception $e){ + $path=$e->getMessage(); + $this->assertEqual($path,$tmpFile); + } + } + + public static function closeCallBack($path){ + throw new Exception($path); + } } \ No newline at end of file -- 2.39.5