#!./perl
BEGIN {
chdir
't'
if
-d
't'
;
require
'./test.pl'
;
set_up_inc(
'../lib'
);
}
$| = 1;
plan
tests
=> 188;
sub
ok_cloexec {
SKIP: {
skip
"no fcntl"
, 1
unless
$Config
{d_fcntl};
my
$fd
=
fileno
(
$_
[0]);
fresh_perl_is(
qq(
print open(F, "+<&=$fd")
? 1 : 0,
"\\n"
;
),
"0\n"
, {},
"not inherited across exec"
);
}
}
my
$Perl
= which_perl();
my
$afile
= tempfile();
{
unlink
(
$afile
)
if
-f
$afile
;
$! = 0;
ok(
open
(
my
$f
,
"+>$afile"
),
'open(my $f, "+>...")'
);
ok_cloexec(
$f
);
binmode
$f
;
ok( -f
$afile
,
' its a file'
);
ok( (
print
$f
"SomeData\n"
),
' we can print to it'
);
is(
tell
(
$f
), 9,
' tell()'
);
ok(
seek
(
$f
,0,0),
' seek set'
);
$b
= <
$f
>;
is(
$b
,
"SomeData\n"
,
' readline'
);
ok( -f
$f
,
' still a file'
);
eval
{
die
"Message"
};
like( $@,
qr/<\$f> line 1/
,
' die message correct'
);
ok(
close
(
$f
),
' close()'
);
ok(
unlink
(
$afile
),
' unlink()'
);
}
{
ok(
open
(
my
$f
,
'>'
,
$afile
),
"open(my \$f, '>', $afile)"
);
ok_cloexec(
$f
);
ok( (
print
$f
"a row\n"
),
' print'
);
ok(
close
(
$f
),
' close'
);
ok( -s
$afile
< 10,
' -s'
);
}
{
ok(
open
(
my
$f
,
'>>'
,
$afile
),
"open(my \$f, '>>', $afile)"
);
ok_cloexec(
$f
);
ok( (
print
$f
"a row\n"
),
' print'
);
ok(
close
(
$f
),
' close'
);
ok( -s
$afile
> 10,
' -s'
);
}
{
ok(
open
(
my
$f
,
'<'
,
$afile
),
"open(my \$f, '<', $afile)"
);
ok_cloexec(
$f
);
my
@rows
= <
$f
>;
is(
scalar
@rows
, 2,
' readline, list context'
);
is(
$rows
[0],
"a row\n"
,
' first line read'
);
is(
$rows
[1],
"a row\n"
,
' second line'
);
ok(
close
(
$f
),
' close'
);
}
{
ok( -s
$afile
< 20,
'-s'
);
ok(
open
(
my
$f
,
'+<'
,
$afile
),
'open +<'
);
ok_cloexec(
$f
);
my
@rows
= <
$f
>;
is(
scalar
@rows
, 2,
' readline, list context'
);
ok(
seek
(
$f
, 0, 1),
' seek cur'
);
ok( (
print
$f
"yet another row\n"
),
' print'
);
ok(
close
(
$f
),
' close'
);
ok( -s
$afile
> 20,
' -s'
);
unlink
(
$afile
);
}
{
ok(
open
(
my
$f
,
'-|'
,
<<EOC), 'open -|' );
$Perl -e "print qq(a row\\n); print qq(another row\\n)"
EOC
ok_cloexec(
$f
);
my
@rows
= <
$f
>;
is(
scalar
@rows
, 2,
' readline, list context'
);
ok(
close
(
$f
),
' close'
);
}
{
ok(
open
(
my
$f
,
'|-'
,
<<EOC), 'open |-' );
$Perl -pe "s/^not //"
EOC
ok_cloexec(
$f
);
my
@rows
= <
$f
>;
my
$test
= curr_test;
print
$f
"not ok $test - piped in\n"
;
next_test;
$test
= curr_test;
print
$f
"not ok $test - piped in\n"
;
next_test;
ok(
close
(
$f
),
' close'
);
sleep
1;
pass(
'flushing'
);
}
ok( !
eval
{
open
my
$f
,
'<&'
,
$afile
; 1; },
'<& on a non-filehandle'
);
like( $@,
qr/Bad filehandle:\s+$afile/
,
' right error'
);
ok( !
eval
{
*some_glob
= 1;
open
my
$f
,
'<&'
,
*some_glob
; 1; },
'<& on a non-filehandle glob'
);
like( $@,
qr/Bad filehandle:\s+some_glob/
,
' right error'
);
{
use
open
qw( :utf8 :std )
;
ok( !
eval
{
use
utf8; *ǡfilḛ = 1;
open
my
$f
,
'<&'
, *ǡfilḛ; 1; },
'<& on a non-filehandle glob'
);
like( $@,
qr/Bad filehandle:\s+ǡfilḛ/
u,
' right error'
);
}
{
unlink
(
$afile
)
if
-f
$afile
;
ok(
open
(
local
$f
,
"+>$afile"
),
'open local $f, "+>", ...'
);
ok_cloexec(
$f
);
binmode
$f
;
ok( -f
$afile
,
' -f'
);
ok( (
print
$f
"SomeData\n"
),
' print'
);
is(
tell
(
$f
), 9,
' tell'
);
ok(
seek
(
$f
,0,0),
' seek set'
);
$b
= <
$f
>;
is(
$b
,
"SomeData\n"
,
' readline'
);
ok( -f
$f
,
' still a file'
);
eval
{
die
"Message"
};
like( $@,
qr/<\$f> line 1/
,
' proper die message'
);
ok(
close
(
$f
),
' close'
);
unlink
(
$afile
);
}
{
ok(
open
(
local
$f
,
'>'
,
$afile
),
'open local $f, ">", ...'
);
ok_cloexec(
$f
);
ok( (
print
$f
"a row\n"
),
' print'
);
ok(
close
(
$f
),
' close'
);
ok( -s
$afile
< 10,
' -s'
);
}
{
ok(
open
(
local
$f
,
'>>'
,
$afile
),
'open local $f, ">>", ...'
);
ok_cloexec(
$f
);
ok( (
print
$f
"a row\n"
),
' print'
);
ok(
close
(
$f
),
' close'
);
ok( -s
$afile
> 10,
' -s'
);
}
{
ok(
open
(
local
$f
,
'<'
,
$afile
),
'open local $f, "<", ...'
);
ok_cloexec(
$f
);
my
@rows
= <
$f
>;
is(
scalar
@rows
, 2,
' readline list context'
);
ok(
close
(
$f
),
' close'
);
}
ok( -s
$afile
< 20,
' -s'
);
{
ok(
open
(
local
$f
,
'+<'
,
$afile
),
'open local $f, "+<", ...'
);
ok_cloexec(
$f
);
my
@rows
= <
$f
>;
is(
scalar
@rows
, 2,
' readline list context'
);
ok(
seek
(
$f
, 0, 1),
' seek cur'
);
ok( (
print
$f
"yet another row\n"
),
' print'
);
ok(
close
(
$f
),
' close'
);
ok( -s
$afile
> 20,
' -s'
);
unlink
(
$afile
);
}
{
ok(
open
(
local
$f
,
'-|'
,
<<EOC), 'open local $f, "-|", ...' );
$Perl -e "print qq(a row\\n); print qq(another row\\n)"
EOC
ok_cloexec(
$f
);
my
@rows
= <
$f
>;
is(
scalar
@rows
, 2,
' readline list context'
);
ok(
close
(
$f
),
' close'
);
}
{
ok(
open
(
local
$f
,
'|-'
,
<<EOC), 'open local $f, "|-", ...' );
$Perl -pe "s/^not //"
EOC
ok_cloexec(
$f
);
my
@rows
= <
$f
>;
my
$test
= curr_test;
print
$f
"not ok $test - piping\n"
;
next_test;
$test
= curr_test;
print
$f
"not ok $test - piping\n"
;
next_test;
ok(
close
(
$f
),
' close'
);
sleep
1;
pass(
"Flush"
);
}
ok( !
eval
{
open
local
$f
,
'<&'
,
$afile
; 1 },
'local <& on non-filehandle'
);
like( $@,
qr/Bad filehandle:\s+$afile/
,
' right error'
);
{
local
*F
;
for
(1..2) {
ok(
open
(F,
qq{$Perl -le "print 'ok'"|}
),
'open to pipe'
);
ok_cloexec(\
*F
);
is(
scalar
<F>,
"ok\n"
,
' readline'
);
ok(
close
F,
' close'
);
}
for
(1..2) {
ok(
open
(F,
"-|"
,
qq{$Perl -le "print 'ok'"}
),
'open -|'
);
ok_cloexec(\
*F
);
is(
scalar
<F>,
"ok\n"
,
' readline'
);
ok(
close
F,
' close'
);
}
}
{
ok(
open
(
my
$stdout
,
">&"
, \
*STDOUT
),
'dup \*STDOUT into lexical fh'
);
ok_cloexec(
$stdout
);
ok(
open
(STDOUT,
">&"
,
$stdout
),
'restore dupped STDOUT from lexical fh'
);
{
ok(
open
(
my
$stdout
,
">&"
, STDOUT),
'dup STDOUT into lexical fh'
);
ok_cloexec(
$stdout
);
}
ok(
open
(
my
$stdin
,
"<&"
,
fileno
STDIN),
'dup fileno(STDIN) into lexical fh'
) or _diag $!;
ok_cloexec(
$stdin
);
fileno
(STDIN) =~ /(.)/;
ok
open
(
$stdin
,
"<&"
, $1),
'open ... "<&", $magical_fileno'
,
|| _diag $!;
ok_cloexec(
$stdin
);
}
SKIP: {
skip
"This perl uses perlio"
, 1
if
$Config
{useperlio};
skip_if_miniperl(
"miniperl can't rely on loading %Errno"
, 1);
skip
"This system doesn't understand EINVAL"
, 1
unless
exists
${
"!"
}{EINVAL};
no
warnings
'io'
;
ok(!
open
(F,
'>'
,\
my
$s
) && ${
"!"
}{EINVAL},
'open(reference) raises EINVAL'
);
}
{
ok( !
eval
{
open
F,
"BAR"
,
"QUUX"
},
'Unknown open() mode'
);
like( $@,
qr/\QUnknown open() mode 'BAR'/
,
' right error'
);
}
{
local
$SIG
{__WARN__} =
sub
{ $@ =
shift
};
sub
gimme {
my
$tmphandle
=
shift
;
my
$line
=
scalar
<
$tmphandle
>;
warn
"gimme"
;
return
$line
;
}
open
(
$fh0
[0],
"TEST"
);
ok_cloexec(
$fh0
[0]);
gimme(
$fh0
[0]);
like($@,
qr/<\$fh0\[...\]> line 1\./
,
"autoviv fh package aelem"
);
open
(
$fh1
{k},
"TEST"
);
ok_cloexec(
$fh1
{h});
gimme(
$fh1
{k});
like($@,
qr/<\$fh1\{...}> line 1\./
,
"autoviv fh package helem"
);
my
@fh2
;
open
(
$fh2
[0],
"TEST"
);
ok_cloexec(
$fh2
[0]);
gimme(
$fh2
[0]);
like($@,
qr/<\$fh2\[...\]> line 1\./
,
"autoviv fh lexical aelem"
);
my
%fh3
;
open
(
$fh3
{k},
"TEST"
);
ok_cloexec(
$fh3
{h});
gimme(
$fh3
{k});
like($@,
qr/<\$fh3\{...}> line 1\./
,
"autoviv fh lexical helem"
);
local
$/ =
*F
;
gimme(
$fh3
{k});
like($@,
qr/<\$fh3\{...}> chunk 2\./
,
'<...> line 1 when $/ is set to a glob'
);
}
SKIP: {
skip(
"These tests use perlio"
, 5)
unless
$Config
{useperlio};
my
$w
;
local
$SIG
{__WARN__} =
sub
{
$w
=
shift
};
eval
{
open
(F,
">>>"
,
$afile
) };
like(
$w
,
qr/Invalid separator character '>' in PerlIO layer spec/
,
"bad open (>>>) warning"
);
like($@,
qr/Unknown open\(\) mode '>>>'/
,
"bad open (>>>) failure"
);
eval
{
open
(F,
">:u"
,
$afile
) };
like(
$w
,
qr/Unknown PerlIO layer "u"/
,
'bad layer ">:u" warning'
);
eval
{
open
(F,
"<:u"
,
$afile
) };
like(
$w
,
qr/Unknown PerlIO layer "u"/
,
'bad layer "<:u" warning'
);
eval
{
open
(F,
":c"
,
$afile
) };
like($@,
qr/Unknown open\(\) mode ':c'/
,
'bad layer ":c" failure'
);
}
fresh_perl_like(
'open m'
,
qr/^Search pattern not terminated at/
,
{
stderr
=> 1 },
'open m test'
);
fresh_perl_is(
'sub f { open(my $fh, "xxx"); $fh = "f"; } f; f;print "ok"'
,
'ok'
, {
stderr
=> 1 },
'#29102: Crash on assignment to lexical filehandle'
);
eval
{
open
$99,
"foo"
};
like($@,
qr/Modification of a read-only value attempted/
,
"readonly fh"
);
eval
{
no
warnings
"uninitialized"
;
"a"
=~ /(b)?/;
close
$+
};
is($@,
''
,
'no "Modification of a read-only value" when closing'
);
{
sub
TIESCALAR {
bless
{} }
sub
FETCH {
"$Perl -e 1"
}
tie
my
$p
,
'p73626'
;
ok(
open
(
my
$f
,
'-|'
,
$p
),
'open -| magic'
);
}
fresh_perl_is(
'
open
my
$fh
,
">"
, \
*STDOUT
;
print
$fh
"hello"
;
""
.
*STDOUT
;
print
"ok"
;
close
$fh
;
unlink
\
*STDOUT
;
',
'ok'
, {
stderr
=> 1 },
'[perl #77492]: open $fh, ">", \*glob causes SEGV'
);
SKIP: {
my
$var
=
*STDOUT
;
open
my
$fh
,
">"
, \
$var
;
print
$fh
"hello"
;
is
$var
,
"hello"
,
'[perl #77684]: open $fh, ">", \$glob_copy'
or
unlink
\
*STDOUT
;
}
SKIP: {
skip_if_miniperl(
"no dynamic loading on miniperl, so can't load IO::File"
, 3);
is(
$INC
{
'IO/File.pm'
},
undef
,
"IO::File not loaded"
);
my
$var
=
""
;
open
my
$fh
,
">"
, \
$var
;
ok(
eval
{
$fh
->autoflush(1); 1 },
'$fh->autoflush(1) lives'
);
ok(
$INC
{
'IO/File.pm'
},
"IO::File now loaded"
);
}
sub
_117941 {
package
_117941;
open
my
$a
,
"TEST"
}
delete
$::{
"_117941::"
};
_117941();
pass(
"no crash when open autovivifies glob in freed package"
);
{
my
$WARN
;
local
$SIG
{__WARN__} =
sub
{
$WARN
=
shift
};
my
$temp
= tempfile();
my
$temp_match
=
quotemeta
$temp
;
open
my
$temp_fh
,
">"
,
$temp
;
close
$temp_fh
;
ok(
utime
(
time
()-10,
time
(),
$temp
),
"set mtime to a known value"
);
ok(
chmod
(0666,
$temp
),
"set mode to a known value"
);
my
(
$final_mode
,
$final_mtime
) = (
stat
$temp
)[2, 9];
my
$fn
=
"$temp\0.invalid"
;
my
$fno
=
bless
\(
my
$fn2
=
"$temp\0.overload"
),
"OverloadTest"
;
is(
open
(I,
$fn
),
undef
,
"open with nul in pathnames since 5.18 [perl #117265]"
);
like(
$WARN
,
qr/^Invalid \\0 character in pathname for open: $temp_match\\0\.invalid/
,
"warn on embedded nul"
);
$WARN
=
''
;
is(
open
(I,
$fno
),
undef
,
"open with nul in pathnames since 5.18 [perl #117265] (overload)"
);
like(
$WARN
,
qr/^Invalid \\0 character in pathname for open: $temp_match\\0\.overload/
,
"warn on embedded nul"
);
$WARN
=
''
;
is(
chmod
(0444,
$fn
), 0,
"chmod fails with \\0 in name"
);
like(
$WARN
,
qr/^Invalid \\0 character in pathname for chmod: $temp_match\\0\.invalid/
,
"also on chmod"
);
$WARN
=
''
;
is(
chmod
(0444,
$fno
), 0,
"chmod fails with \\0 in name (overload)"
);
like(
$WARN
,
qr/^Invalid \\0 character in pathname for chmod: $temp_match\\0\.overload/
,
"also on chmod"
);
$WARN
=
''
;
is (
glob
(
$fn
),
undef
,
"glob fails with \\0 in name"
);
like(
$WARN
,
qr/^Invalid \\0 character in pattern for glob: $temp_match\\0\.invalid/
,
"also on glob"
);
$WARN
=
''
;
is (
glob
(
$fno
),
undef
,
"glob fails with \\0 in name (overload)"
);
like(
$WARN
,
qr/^Invalid \\0 character in pattern for glob: $temp_match\\0\.overload/
,
"also on glob"
);
$WARN
=
''
;
{
no
warnings
'syscalls'
;
$WARN
=
''
;
is(
open
(I,
$fn
),
undef
,
"open with nul with no warnings syscalls"
);
is(
$WARN
,
''
,
"ignore warning on embedded nul with no warnings syscalls"
);
}
SKIP: {
if
(is_miniperl && !
eval
'require Errno'
) {
skip
"Errno not built yet"
, 8;
}
import
Errno
'ENOENT'
;
$! = 0;
is (
unlink
(
$fn
,
$fn
), 0,
"check multiple arguments to unlink"
);
is($!+0,
&ENOENT
,
"check errno"
);
$! = 0;
is (
chmod
(0644,
$fn
,
$fn
), 0,
"check multiple arguments to chmod"
);
is($!+0,
&ENOENT
,
"check errno"
);
$! = 0;
is (
utime
(
time
,
time
,
$fn
,
$fn
), 0,
"check multiple arguments to utime"
);
is($!+0,
&ENOENT
,
"check errno"
);
SKIP: {
skip
"no chown"
, 2
unless
$Config
{d_chown};
$! = 0;
is(
chown
(-1, -1,
$fn
,
$fn
), 0,
"check multiple arguments to chown"
);
is($!+0,
&ENOENT
,
"check errno"
);
}
}
is (
unlink
(
$fn
), 0,
"unlink fails with \\0 in name"
);
like(
$WARN
,
qr/^Invalid \\0 character in pathname for unlink: $temp_match\\0\.invalid/
,
"also on unlink"
);
$WARN
=
''
;
is (
unlink
(
$fno
), 0,
"unlink fails with \\0 in name (overload)"
);
like(
$WARN
,
qr/^Invalid \\0 character in pathname for unlink: $temp_match\\0\.overload/
,
"also on unlink"
);
$WARN
=
''
;
ok(-f
$temp
,
"nothing removed the temp file"
);
is((
stat
$temp
)[2],
$final_mode
,
"nothing changed its mode"
);
is((
stat
$temp
)[9],
$final_mtime
,
"nothing changes its mtime"
);
}
{
ok(
open
(
my
$fh
,
"<"
,
"TEST"
),
"open a handle"
);
ok(
close
$fh
,
"and close it again"
);
ok(!
open
(
my
$fh2
,
">&"
,
$fh
),
"should fail to dup the closed handle"
);
unlink
"$fh"
;
}
{
}
SKIP: {
my
(
$a
,
$b
,
$s
,
$t
);
$s
=
""
;
open
(
$a
,
">:scalar:perlio"
, \
$s
) or
die
;
print
{
$a
}
"abc"
;
is
$s
,
""
,
"buffering delays writing to scalar (simple open)"
;
$a
=
undef
;
is
$s
,
"abc"
,
"buffered write happens on dropping handle ref (simple open)"
;
$t
=
""
;
open
(${\
$b
},
">:scalar:perlio"
, \
$t
) or
die
;
print
{
$b
}
"xyz"
;
is
$t
,
""
,
"buffering delays writing to scalar (complex open)"
;
$b
=
undef
;
is
$t
,
"xyz"
,
"buffered write happens on dropping handle ref (complex open)"
;
is
scalar
(
grep
{ /\A_GEN_/ }
keys
%::), 0,
"no gensym appeared in stash"
;
}
{
my
$tfile
= tempfile();
open
(
my
$twrite
,
">"
,
$tfile
) or
die
$!;
print
{
$twrite
}
"foo\nbar\n"
or
die
$!;
close
$twrite
or
die
$!;
$twrite
=
undef
;
my
$tread
=
do
{
local
*F
;
open
(F,
"<"
,
$tfile
) or
die
$!;
*F
;
};
is
scalar
(<
$tread
>),
"foo\n"
,
"IO handle returned in localised glob"
;
close
$tread
;
}