ftruncate() does not work with user-defined stream wrappers
| Request #53888 | ftruncate() does not work with user-defined stream wrappers | ||||
|---|---|---|---|---|---|
| Submitted: | 2011-01-31 08:45 UTC | Modified: | 2011-02-17 01:25 UTC | ||
| From: | ivan dot enderlin at hoa-project dot net | Assigned: | cataphract (profile) | ||
| Status: | Closed | Package: | Filesystem function related | ||
| PHP Version: | trunk-SVN-2011-01-31 (SVN) | OS: | |||
| Private report: | No | CVE-ID: | None | ||
[2011-01-31 08:45 UTC] ivan dot enderlin at hoa-project dot net
Description:
------------
Hey :-),
Seems like ftruncate() does not reconized an user-defined stream (with stream wrapper) as a valid stream. When we use it, it raises the following error: “Can't truncate this stream!”. All the related subject about this error on the Web talks about stream wrappers. Thus, it's seem to be the real problem.
Test script:
---------------
<?php
class StreamWrapper {
private $_stream = null;
private $_streamName = null;
public $context = null;
public static function realPath ( $path ) {
return substr($path, 6);
}
public function stream_close ( ) {
if(true === @fclose($this->getStream())) {
$this->_stream = null;
$this->_streamName = null;
}
return;
}
public function stream_eof ( ) {
return feof($this->getStream());
}
public function stream_flush ( ) {
return fflush($this->getStream());
}
public function stream_lock ( $operation ) {
return flock($this->getStream(), $operation);
}
public function stream_open ( $path, $mode, $options, &$openedPath ) {
$p = self::realPath($path);
if(false === $p)
return false;
if(null === $this->context)
$openedPath = fopen(
$p,
$mode,
$options & STREAM_USE_PATH
);
else
$openedPath = fopen(
$p,
$mode,
$options & STREAM_USE_PATH,
$this->context
);
$this->_stream = $openedPath;
$this->_streamName = $p;
return true;
}
public function stream_read ( $count ) {
return fread($this->getStream(), $count);
}
public function stream_seek ( $offset, $whence = SEEK_SET ) {
return fseek($this->getStream(), $offset, $whence);
}
public function stream_stat ( ) {
return fstat($this->getStream());
}
public function stream_tell ( ) {
return ftell($this->getStream());
}
public function stream_write ( $data ) {
return fwrite($this->getStream(), $data);
}
public function dir_closedir ( ) {
if(true === $handle = @closedir($this->getStream())) {
$this->_stream = null;
$this->_streamName = null;
}
return $handle;
}
public function dir_opendir ( $path, $options ) {
$p = self::realPath($path);
$handle = null;
if(null === $this->context)
$handle = @opendir($p);
else
$handle = @opendir($p, $this->context);
if(false === $handle)
return false;
$this->_stream = $handle;
$this->_streamName = $p;
return true;
}
public function dir_readdir ( ) {
return readdir($this->getStream());
}
public function dir_rewinddir ( ) {
return rewinddir($this->getStream());
}
public function mkdir ( $path, $mode, $options ) {
if(null === $this->context)
return mkdir(
self::realPath($path),
$mode,
$options | STREAM_MKDIR_RECURSIVE
);
return mkdir(
self::realPath($path),
$mode,
$options | STREAM_MKDIR_RECURSIVE,
$this->context
);
}
public function rename ( $from, $to ) {
if(null === $this->context)
return rename(self::realPath($from), self::realPath($to));
return rename(self::realPath($from), self::realPath($to), $this->context);
}
public function rmdir ( $path, $options ) {
if(null === $this->context)
return rmdir(self::realPath($path));
return rmdir(self::realPath($path), $this->context);
}
public function unlink ( $path ) {
if(null === $this->context)
return unlink(self::realPath($path));
return unlink(self::realPath($path), $this->context);
}
public function url_stat ( $path, $flags ) {
if(false === $p = self::realPath($path))
if($flags & STREAM_URL_STAT_QUIET)
return array(); // Not sure…
else
return trigger_error(
'Path ' . $path . ' cannot be resolved.',
E_WARNING
);
if($flags & STREAM_URL_STAT_LINK)
return @lstat($p);
return @stat($p);
}
protected function getStream ( ) {
return $this->_stream;
}
protected function getStreamName ( ) {
return $this->_streamName;
}
}
stream_wrapper_register('bug', 'StreamWrapper');
var_dump($fd = fopen('bug://Test.txt', 'w+'));
var_dump(fwrite($fd, 'Foobar1' . "\n"));
var_dump(fwrite($fd, 'Foobar2' . "\n"));
var_dump(fwrite($fd, 'Foobar3' . "\n"));
var_dump(ftruncate($fd, 3));
var_dump(fclose($fd));
Expected result:
----------------
Output:
resource(7) of type (stream)
int(8)
int(8)
int(8)
bool(true)
bool(true)
Test.txt:
Foo
Actual result:
--------------
Output:
resource(7) of type (stream)
int(8)
int(8)
int(8)
PHP Warning: ftruncate(): Can't truncate this stream! in /Users/hywan/Development/Hoa/Laboratory/Bug/StreamWrapper.php on line 210
Warning: ftruncate(): Can't truncate this stream! in /Users/hywan/Development/Hoa/Laboratory/Bug/StreamWrapper.php on line 210
bool(false)
bool(true)
Test.txt:
Foobar1
Foobar2
Foobar3
Patches
Pull Requests
History
AllCommentsChangesGit/SVN commits
[2011-02-01 08:46 UTC] ivan dot enderlin at hoa-project dot net
[2011-02-01 08:49 UTC] pajoye@php.net
[2011-02-01 10:25 UTC] ivan dot enderlin at hoa-project dot net
[2011-02-01 13:57 UTC] cataphract@php.net
[2011-02-01 17:52 UTC] ivan dot enderlin at hoa-project dot net
[2011-02-18 11:45 UTC] ivan dot enderlin at hoa-project dot net