|
|
|
@ -4,28 +4,151 @@ User-space streams |
|
|
|
<?php |
|
|
|
# vim600:syn=php: |
|
|
|
|
|
|
|
class uselessstream { |
|
|
|
/* This is a fairly aggressive test that looks at |
|
|
|
* user streams and also gives the seek/gets/buffer |
|
|
|
* layer of streams a thorough testing */ |
|
|
|
|
|
|
|
$lyrics = <<<EOD |
|
|
|
...and the road becomes my bride |
|
|
|
I have stripped of all but pride |
|
|
|
so in her I do confide |
|
|
|
and she keeps me satisfied |
|
|
|
gives me all I need |
|
|
|
...and with dust in throat I crave |
|
|
|
to the game you stay a slave |
|
|
|
rover wanderer |
|
|
|
nomad vagabond |
|
|
|
call me what you will |
|
|
|
But Ill take my time anywhere |
|
|
|
Free to speak my mind anywhere |
|
|
|
and Ill redefine anywhere |
|
|
|
Anywhere I roam |
|
|
|
Where I lay my head is home |
|
|
|
...and the earth becomes my throne |
|
|
|
I adapt to the unknown |
|
|
|
under wandering stars Ive grown |
|
|
|
by myself but not alone |
|
|
|
I ask no one |
|
|
|
...and my ties are severed clean |
|
|
|
the less I have the more I gain |
|
|
|
off the beaten path I reign |
|
|
|
rover wanderer |
|
|
|
nomad vagabond |
|
|
|
call me what you will |
|
|
|
But Ill take my time anywhere |
|
|
|
Free to speak my mind anywhere |
|
|
|
and Ill never mind anywhere |
|
|
|
Anywhere I roam |
|
|
|
Where I lay my head is home |
|
|
|
But Ill take my time anywhere |
|
|
|
Free to speak my mind anywhere |
|
|
|
and Ill take my find anywhere |
|
|
|
Anywhere I roam |
|
|
|
Where I lay my head is home |
|
|
|
carved upon my stone |
|
|
|
my body lie but still I roam |
|
|
|
Wherever I may roam. |
|
|
|
|
|
|
|
Wherever I May Roam |
|
|
|
|
|
|
|
EOD; |
|
|
|
|
|
|
|
/* repeat the data a few times so that it grows larger than |
|
|
|
* the default cache chunk size and that we have something |
|
|
|
* to seek around... */ |
|
|
|
$DATA = ""; |
|
|
|
for ($i = 0; $i < 30; $i++) { |
|
|
|
if ($i % 2 == 0) |
|
|
|
$DATA .= str_rot13($lyrics); |
|
|
|
else |
|
|
|
$DATA .= $lyrics; |
|
|
|
} |
|
|
|
|
|
|
|
class mystream { |
|
|
|
/* store the data in a regular file so that we can compare |
|
|
|
* the results */ |
|
|
|
$tf = tmpfile(); |
|
|
|
fwrite($tf, $DATA); |
|
|
|
$n = ftell($tf); |
|
|
|
rewind($tf) or die("failed to rewind tmp file!"); |
|
|
|
if (ftell($tf) != 0) |
|
|
|
die("tmpfile is not at start!"); |
|
|
|
$DATALEN = strlen($DATA); |
|
|
|
if ($n != $DATALEN) |
|
|
|
die("tmpfile stored $n bytes; should be $DATALEN!"); |
|
|
|
|
|
|
|
function mystream() |
|
|
|
{ |
|
|
|
echo "MYSTREAM: constructor called!\n"; |
|
|
|
} |
|
|
|
class uselessstream { |
|
|
|
} |
|
|
|
|
|
|
|
class mystream { |
|
|
|
var $path; |
|
|
|
var $mode; |
|
|
|
var $options; |
|
|
|
|
|
|
|
var $position; |
|
|
|
var $varname; |
|
|
|
|
|
|
|
function stream_open($path, $mode, $options, &$opened_path) |
|
|
|
{ |
|
|
|
$this->path = $path; |
|
|
|
$this->mode = $mode; |
|
|
|
$this->options = $options; |
|
|
|
|
|
|
|
$split = parse_url($path); |
|
|
|
$this->varname = $split["host"]; |
|
|
|
$this->position = 0; |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
function stream_read($count) |
|
|
|
{ |
|
|
|
$ret = substr($GLOBALS[$this->varname], $this->position, $count); |
|
|
|
$this->position += strlen($ret); |
|
|
|
return $ret; |
|
|
|
} |
|
|
|
|
|
|
|
function stream_tell() |
|
|
|
{ |
|
|
|
return $this->position; |
|
|
|
} |
|
|
|
|
|
|
|
function stream_eof() |
|
|
|
{ |
|
|
|
return $this->position >= strlen($GLOBALS[$this->varname]); |
|
|
|
} |
|
|
|
|
|
|
|
function stream_seek($offset, $whence) |
|
|
|
{ |
|
|
|
switch($whence) { |
|
|
|
case SEEK_SET: |
|
|
|
if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) { |
|
|
|
$this->position = $offset; |
|
|
|
return true; |
|
|
|
} else { |
|
|
|
return false; |
|
|
|
} |
|
|
|
break; |
|
|
|
case SEEK_CUR: |
|
|
|
if ($offset >= 0) { |
|
|
|
$this->position += $offset; |
|
|
|
return true; |
|
|
|
} else { |
|
|
|
return false; |
|
|
|
} |
|
|
|
break; |
|
|
|
case SEEK_END: |
|
|
|
if (strlen($GLOBALS[$this->varname]) + $offset >= 0) { |
|
|
|
$this->position = strlen($GLOBALS[$this->varname]) + $offset; |
|
|
|
return true; |
|
|
|
} else { |
|
|
|
return false; |
|
|
|
} |
|
|
|
break; |
|
|
|
default: |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (@file_register_wrapper("bogus", "class_not_exist")) |
|
|
|
@ -42,10 +165,129 @@ $b = @fopen("bogon://url", "rb"); |
|
|
|
if (is_resource($b)) |
|
|
|
die("Opened a bogon??"); |
|
|
|
|
|
|
|
$fp = fopen("test://url", "rb"); |
|
|
|
$fp = fopen("test://DATA", "rb"); |
|
|
|
if (!is_resource($fp)) |
|
|
|
die("Failed to open resource"); |
|
|
|
|
|
|
|
/* some default seeks that will cause buffer/cache misses */ |
|
|
|
$seeks = array( |
|
|
|
array(SEEK_SET, 0, 0), |
|
|
|
array(SEEK_CUR, 8450, 8450), |
|
|
|
array(SEEK_CUR, -7904, 546), |
|
|
|
array(SEEK_CUR, 12456, 13002), |
|
|
|
|
|
|
|
/* end up at BOF so that randomly generated seek offsets |
|
|
|
* below will know where they are supposed to be */ |
|
|
|
array(SEEK_SET, 0, 0) |
|
|
|
); |
|
|
|
|
|
|
|
$whence_map = array( |
|
|
|
SEEK_CUR, |
|
|
|
SEEK_SET, |
|
|
|
SEEK_END |
|
|
|
); |
|
|
|
$whence_names = array( |
|
|
|
SEEK_CUR => "SEEK_CUR", |
|
|
|
SEEK_SET => "SEEK_SET", |
|
|
|
SEEK_END => "SEEK_END" |
|
|
|
); |
|
|
|
|
|
|
|
/* generate some random seek offsets */ |
|
|
|
$position = 0; |
|
|
|
for ($i = 0; $i < 256; $i++) { |
|
|
|
$whence = $whence_map[array_rand($whence_map, 1)]; |
|
|
|
switch($whence) { |
|
|
|
case SEEK_SET: |
|
|
|
$offset = rand(0, $DATALEN); |
|
|
|
$position = $offset; |
|
|
|
break; |
|
|
|
case SEEK_END: |
|
|
|
$offset = -rand(0, $DATALEN); |
|
|
|
$position = $DATALEN + $offset; |
|
|
|
break; |
|
|
|
case SEEK_CUR: |
|
|
|
$offset = rand(0, $DATALEN); |
|
|
|
$offset -= $position; |
|
|
|
$position += $offset; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
$seeks[] = array($whence, $offset, $position); |
|
|
|
} |
|
|
|
|
|
|
|
/* we compare the results of fgets using differing line lengths to |
|
|
|
* test the fgets layer also */ |
|
|
|
$line_lengths = array(1024, 256, 64, 16); |
|
|
|
$fail_count = 0; |
|
|
|
|
|
|
|
ob_start(); |
|
|
|
foreach($line_lengths as $line_length) { |
|
|
|
/* now compare the real stream with the user stream */ |
|
|
|
$j = 0; |
|
|
|
rewind($tf); |
|
|
|
rewind($fp); |
|
|
|
foreach($seeks as $seekdata) { |
|
|
|
list($whence, $offset, $position) = $seekdata; |
|
|
|
|
|
|
|
$rpb = ftell($tf); |
|
|
|
$rr = (int)fseek($tf, $offset, $whence); |
|
|
|
$rpa = ftell($tf); |
|
|
|
$rline = fgets($tf, $line_length); |
|
|
|
(int)fseek($tf, - strlen($rline), SEEK_CUR); |
|
|
|
|
|
|
|
$upb = ftell($fp); |
|
|
|
$ur = (int)fseek($fp, $offset, $whence); |
|
|
|
$upa = ftell($fp); |
|
|
|
$uline = fgets($fp, $line_length); |
|
|
|
(int)fseek($fp, - strlen($uline), SEEK_CUR); |
|
|
|
|
|
|
|
printf("\n--[%d] whence=%s offset=%d line_length=%d position_should_be=%d --\n", |
|
|
|
$j, $whence_names[$whence], $offset, $line_length, $position); |
|
|
|
printf("REAL: pos=(%d,%d,%d) ret=%d line=`%s'\n", $rpb, $rpa, ftell($tf), $rr, $rline); |
|
|
|
printf("USER: pos=(%d,%d,%d) ret=%d line=`%s'\n", $upb, $upa, ftell($fp), $ur, $uline); |
|
|
|
|
|
|
|
if ($rr != $ur || $rline != $uline || $rpa != $position || $upa != $position) { |
|
|
|
$fail_count++; |
|
|
|
$dat = file_get_wrapper_data($fp); |
|
|
|
var_dump($dat); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
$j++; |
|
|
|
} |
|
|
|
if ($fail_count) |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if ($fail_count == 0) { |
|
|
|
ob_end_clean(); |
|
|
|
echo "SEEK: OK\n"; |
|
|
|
} else { |
|
|
|
echo "SEEK: FAIL\n"; |
|
|
|
ob_end_flush(); |
|
|
|
} |
|
|
|
|
|
|
|
$fail_count = 0; |
|
|
|
fseek($fp, $DATALEN / 2, SEEK_SET); |
|
|
|
fseek($tf, $DATALEN / 2, SEEK_SET); |
|
|
|
|
|
|
|
while(!feof($fp)) { |
|
|
|
$uline = fgets($fp, 1024); |
|
|
|
$rline = fgets($fp, 1024); |
|
|
|
|
|
|
|
if ($uline != $rline) { |
|
|
|
echo "FGETS: FAIL\nuser=$uline\nreal=$rline\n"; |
|
|
|
$fail_count++; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if ($fail_count == 0) |
|
|
|
echo "FGETS: OK\n"; |
|
|
|
|
|
|
|
|
|
|
|
?> |
|
|
|
--EXPECT-- |
|
|
|
Registered |
|
|
|
SEEK: OK |
|
|
|
FGETS: OK |