This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Deprecate above \xFF in bitwise string ops
[perl5.git] / t / op / stat.t
1 #!./perl
2
3 BEGIN {
4     chdir 't' if -d 't';
5     require './test.pl';        # for which_perl() etc
6     set_up_inc('../lib');
7 }
8
9 use strict;
10 use warnings;
11 use Config;
12
13 my ($Null, $Curdir);
14 if(eval {require File::Spec; 1}) {
15     $Null = File::Spec->devnull;
16     $Curdir = File::Spec->curdir;
17 } else {
18     die $@ unless is_miniperl();
19     $Curdir = '.';
20     diag("miniperl failed to load File::Spec, error is:\n$@");
21     diag("\ncontinuing, assuming '.' for current directory. Some tests will be skipped.");
22 }
23
24 if ($^O eq 'MSWin32') {
25     # under minitest, buildcustomize sets this to 1, which means
26     # nlinks isn't populated properly, allow nlinks tests to pass
27     ${^WIN32_SLOPPY_STAT} = 0;
28 }
29
30 plan tests => 110;
31
32 my $Perl = which_perl();
33
34 $ENV{LC_ALL}   = 'C';           # Forge English error messages.
35 $ENV{LANGUAGE} = 'C';           # Ditto in GNU.
36
37 my $Is_Amiga   = $^O eq 'amigaos';
38 my $Is_Cygwin  = $^O eq 'cygwin';
39 my $Is_Darwin  = $^O eq 'darwin';
40 my $Is_Dos     = $^O eq 'dos';
41 my $Is_MSWin32 = $^O eq 'MSWin32';
42 my $Is_NetWare = $^O eq 'NetWare';
43 my $Is_OS2     = $^O eq 'os2';
44 my $Is_Solaris = $^O eq 'solaris';
45 my $Is_VMS     = $^O eq 'VMS';
46 my $Is_MPRAS   = $^O =~ /svr4/ && -f '/etc/.relid';
47 my $Is_Android = $^O =~ /android/;
48 my $Is_Dfly    = $^O eq 'dragonfly';
49
50 my $Is_Dosish  = $Is_Dos || $Is_OS2 || $Is_MSWin32 || $Is_NetWare;
51
52 my $ufs_no_ctime = ($Is_Dfly || $Is_Darwin) && (() = `df -t ufs . 2>/dev/null`) == 2;
53
54 if ($Is_Cygwin && !is_miniperl) {
55   require Win32;
56   Win32->import;
57 }
58
59 my($DEV, $INO, $MODE, $NLINK, $UID, $GID, $RDEV, $SIZE,
60    $ATIME, $MTIME, $CTIME, $BLKSIZE, $BLOCKS) = (0..12);
61
62 my $tmpfile = tempfile();
63 my $tmpfile_link = tempfile();
64
65 chmod 0666, $tmpfile;
66 unlink_all $tmpfile;
67 open(FOO, ">$tmpfile") || DIE("Can't open temp test file: $!");
68 close FOO;
69
70 open(FOO, ">$tmpfile") || DIE("Can't open temp test file: $!");
71
72 my($nlink, $mtime, $ctime) = (stat(FOO))[$NLINK, $MTIME, $CTIME];
73
74 # The clock on a network filesystem might be different from the
75 # system clock.
76 my $Filesystem_Time_Offset = abs($mtime - time); 
77
78 #nlink should if link support configured in Perl.
79 SKIP: {
80     skip "No link count - Hard link support not built in.", 1
81         unless $Config{d_link};
82
83     is($nlink, 1, 'nlink on regular file');
84 }
85
86 SKIP: {
87   skip "mtime and ctime not reliable", 2
88     if $Is_MSWin32 or $Is_NetWare or $Is_Cygwin or $Is_Dos or $Is_Darwin;
89
90   ok( $mtime,           'mtime' );
91   is( $mtime, $ctime,   'mtime == ctime' );
92 }
93
94
95 # Cygwin seems to have a 3 second granularity on its timestamps.
96 my $funky_FAT_timestamps = $Is_Cygwin;
97 sleep 3 if $funky_FAT_timestamps;
98
99 print FOO "Now is the time for all good men to come to.\n";
100 close(FOO);
101
102 sleep 2;
103
104 my $has_link = 1;
105 my $inaccurate_atime = 0;
106 if (defined &Win32::IsWinNT && Win32::IsWinNT()) {
107     if (Win32::FsType() ne 'NTFS') {
108         $has_link            = 0;
109         $inaccurate_atime    = 1;
110     }
111 }
112
113 SKIP: {
114     skip "No link on this filesystem", 6 unless $has_link;
115     unlink $tmpfile_link;
116     my $lnk_result = eval { link $tmpfile, $tmpfile_link };
117     skip "link() unimplemented", 6 if $@ =~ /unimplemented/;
118
119     is( $@, '',         'link() implemented' );
120     ok( $lnk_result,    'linked tmp testfile' );
121     ok( chmod(0644, $tmpfile),             'chmoded tmp testfile' );
122
123     my($nlink, $mtime, $ctime) = (stat($tmpfile))[$NLINK, $MTIME, $CTIME];
124
125     SKIP: {
126         skip "No link count", 1 if $Config{dont_use_nlink};
127         skip "Cygwin9X fakes hard links by copying", 1
128           if $Config{myuname} =~ /^cygwin_(?:9\d|me)\b/i;
129
130         is($nlink, 2,     'Link count on hard linked file' );
131     }
132
133     SKIP: {
134         skip_if_miniperl("File::Spec not built for minitest", 2);
135         my $cwd = File::Spec->rel2abs($Curdir);
136         skip "Solaris tmpfs has different mtime/ctime link semantics", 2
137                                      if $Is_Solaris and $cwd =~ m#^/tmp# and
138                                         $mtime && $mtime == $ctime;
139         skip "AFS has different mtime/ctime link semantics", 2
140                                      if $cwd =~ m#$Config{'afsroot'}/#;
141         skip "AmigaOS has different mtime/ctime link semantics", 2
142                                      if $Is_Amiga;
143         # Win32 could pass $mtime test but as FAT and NTFS have
144         # no ctime concept $ctime is ALWAYS == $mtime
145         # expect netware to be the same ...
146         skip "No ctime concept on this OS", 2
147                                      if $Is_MSWin32 || $ufs_no_ctime;
148
149         if( !ok($mtime, 'hard link mtime') ||
150             !isnt($mtime, $ctime, 'hard link ctime != mtime') ) {
151             print STDERR <<DIAG;
152 # Check if you are on a tmpfs of some sort.  Building in /tmp sometimes
153 # has this problem.  Building on the ClearCase VOBS filesystem may also
154 # cause this failure.
155 #
156 # Some UFS implementations don't have a ctime concept, and thus are
157 # expected to fail this test.
158 DIAG
159         }
160     }
161
162 }
163
164 # truncate and touch $tmpfile.
165 open(F, ">$tmpfile") || DIE("Can't open temp test file: $!");
166 ok(-z \*F,     '-z on empty filehandle');
167 ok(! -s \*F,   '   and -s');
168 close F;
169
170 ok(-z $tmpfile,     '-z on empty file');
171 ok(! -s $tmpfile,   '   and -s');
172
173 open(F, ">$tmpfile") || DIE("Can't open temp test file: $!");
174 print F "hi\n";
175 close F;
176
177 open(F, "<$tmpfile") || DIE("Can't open temp test file: $!");
178 ok(!-z *F,     '-z on empty filehandle');
179 ok( -s *F,   '   and -s');
180 close F;
181
182 ok(! -z $tmpfile,   '-z on non-empty file');
183 ok(-s $tmpfile,     '   and -s');
184
185
186 # Strip all access rights from the file.
187 ok( chmod(0000, $tmpfile),     'chmod 0000' );
188
189 SKIP: {
190     skip "-r, -w and -x have different meanings on VMS", 3 if $Is_VMS;
191
192     SKIP: {
193         # Going to try to switch away from root.  Might not work.
194         my $olduid = $>;
195         eval { $> = 1; };
196         skip "Can't test if an admin user in miniperl", 2,
197           if $Is_Cygwin && is_miniperl();
198         skip "Can't test -r or -w meaningfully if you're superuser", 2
199           if ($> == 0);
200
201         SKIP: {
202             skip "Can't test -r meaningfully?", 1 if $Is_Dos;
203             ok(!-r $tmpfile,    "   -r");
204         }
205
206         ok(!-w $tmpfile,    "   -w");
207
208         # switch uid back (may not be implemented)
209         eval { $> = $olduid; };
210     }
211
212     ok(! -x $tmpfile,   '   -x');
213 }
214
215
216
217 ok(chmod(0700,$tmpfile),    'chmod 0700');
218 ok(-r $tmpfile,     '   -r');
219 ok(-w $tmpfile,     '   -w');
220
221 SKIP: {
222     skip "-x simply determines if a file ends in an executable suffix", 1
223       if $Is_Dosish;
224
225     ok(-x $tmpfile,     '   -x');
226 }
227
228 ok(  -f $tmpfile,   '   -f');
229 ok(! -d $tmpfile,   '   !-d');
230
231 # Is this portable?
232 ok(  -d '.',          '-d cwd' );
233 ok(! -f '.',          '!-f cwd' );
234
235
236 SKIP: {
237     unlink($tmpfile_link);
238     my $symlink_rslt = eval { symlink $tmpfile, $tmpfile_link };
239     skip "symlink not implemented", 3 if $@ =~ /unimplemented/;
240
241     is( $@, '',     'symlink() implemented' );
242     ok( $symlink_rslt,      'symlink() ok' );
243     ok(-l $tmpfile_link,    '-l');
244 }
245
246 ok(-o $tmpfile,     '-o');
247
248 ok(-e $tmpfile,     '-e');
249
250 unlink($tmpfile_link);
251 ok(! -e $tmpfile_link,  '   -e on unlinked file');
252
253 SKIP: {
254     skip "No character, socket or block special files", 6
255       if $Is_MSWin32 || $Is_NetWare || $Is_Dos;
256     skip "/dev isn't available to test against", 6
257       unless -d '/dev' && -r '/dev' && -x '/dev';
258     skip "Skipping: unexpected ls output in MP-RAS", 6
259       if $Is_MPRAS;
260
261     # VMS problem:  If GNV or other UNIX like tool is installed, then
262     # sometimes Perl will find /bin/ls, and will try to run it.
263     # But since Perl on VMS does not know to run it under Bash, it will
264     # try to run the DCL verb LS.  And if the VMS product Language
265     # Sensitive Editor is installed, or some other LS verb, that will
266     # be run instead.  So do not do this until we can teach Perl
267     # when to use BASH on VMS.
268     skip "ls command not available to Perl in OpenVMS right now.", 6
269       if $Is_VMS;
270
271     delete $ENV{CLICOLOR_FORCE};
272     my $LS  = $Config{d_readlink} && !$Is_Android ? "ls -lL" : "ls -l";
273     my $CMD = "$LS /dev 2>/dev/null";
274     my $DEV = qx($CMD);
275
276     skip "$CMD failed", 6 if $DEV eq '';
277
278     my @DEV = do { my $dev; opendir($dev, "/dev") ? readdir($dev) : () };
279
280     skip "opendir failed: $!", 6 if @DEV == 0;
281
282     # /dev/stdout might be either character special or a named pipe,
283     # or a symlink, or a socket, depending on which OS and how are
284     # you running the test, so let's censor that one away.
285     # Similar remarks hold for stderr.
286     $DEV =~ s{^[cpls].+?\sstdout$}{}m;
287     @DEV =  grep { $_ ne 'stdout' } @DEV;
288     $DEV =~ s{^[cpls].+?\sstderr$}{}m;
289     @DEV =  grep { $_ ne 'stderr' } @DEV;
290
291     # /dev/printer is also naughty: in IRIX it shows up as
292     # Srwx-----, not srwx------.
293     $DEV =~ s{^.+?\sprinter$}{}m;
294     @DEV =  grep { $_ ne 'printer' } @DEV;
295
296     # If running as root, we will see .files in the ls result,
297     # and readdir() will see them always.  Potential for conflict,
298     # so let's weed them out.
299     $DEV =~ s{^.+?\s\..+?$}{}m;
300     @DEV =  grep { ! m{^\..+$} } @DEV;
301
302     # Irix ls -l marks sockets with 'S' while 's' is a 'XENIX semaphore'.
303     if ($^O eq 'irix') {
304         $DEV =~ s{^S(.+?)}{s$1}mg;
305     }
306
307     my $try = sub {
308         my @c1 = eval qq[\$DEV =~ /^$_[0].*/mg];
309         my @c2 = eval qq[grep { $_[1] "/dev/\$_" } \@DEV];
310         my $c1 = scalar @c1;
311         my $c2 = scalar @c2;
312         is($c1, $c2, "ls and $_[1] agreeing on /dev ($c1 $c2)");
313     };
314
315 {
316     $try->('b', '-b');
317     $try->('c', '-c');
318     $try->('s', '-S');
319 }
320
321 ok(! -b $Curdir,    '!-b cwd');
322 ok(! -c $Curdir,    '!-c cwd');
323 ok(! -S $Curdir,    '!-S cwd');
324
325 }
326
327 SKIP: {
328     my($cnt, $uid);
329     $cnt = $uid = 0;
330
331     # Find a set of directories that's very likely to have setuid files
332     # but not likely to be *all* setuid files.
333     my @bin = grep {-d && -r && -x} qw(/sbin /usr/sbin /bin /usr/bin);
334     skip "Can't find a setuid file to test with", 3 unless @bin;
335
336     for my $bin (@bin) {
337         opendir BIN, $bin or die "Can't opendir $bin: $!";
338         while (defined($_ = readdir BIN)) {
339             $_ = "$bin/$_";
340             $cnt++;
341             $uid++ if -u;
342             last if $uid && $uid < $cnt;
343         }
344     }
345     closedir BIN;
346
347     skip "No setuid programs", 3 if $uid == 0;
348
349     isnt($cnt, 0,    'found some programs');
350     isnt($uid, 0,    '  found some setuid programs');
351     ok($uid < $cnt,  "    they're not all setuid");
352 }
353
354
355 # To assist in automated testing when a controlling terminal (/dev/tty)
356 # may not be available (at, cron  rsh etc), the PERL_SKIP_TTY_TEST env var
357 # can be set to skip the tests that need a tty.
358 SKIP: {
359     skip "These tests require a TTY", 4 if $ENV{PERL_SKIP_TTY_TEST};
360
361     my $TTY = "/dev/tty";
362
363     SKIP: {
364         skip "Test uses unixisms", 2 if $Is_MSWin32 || $Is_NetWare;
365         skip "No TTY to test -t with", 2 unless -e $TTY;
366
367         open(TTY, $TTY) ||
368           warn "Can't open $TTY--run t/TEST outside of make.\n";
369         ok(-t TTY,  '-t');
370         ok(-c TTY,  'tty is -c');
371         close(TTY);
372     }
373     ok(! -t TTY,    '!-t on closed TTY filehandle');
374
375     {
376         local our $TODO = 'STDIN not a tty when output is to pipe' if $Is_VMS;
377         ok(-t,          '-t on STDIN');
378     }
379 }
380
381 SKIP: {
382     skip "No null device to test with", 1 unless -e $Null;
383     skip "We know Win32 thinks '$Null' is a TTY", 1 if $Is_MSWin32;
384
385     open(NULL, $Null) or DIE("Can't open $Null: $!");
386     ok(! -t NULL,   'null device is not a TTY');
387     close(NULL);
388 }
389
390
391 # These aren't strictly "stat" calls, but so what?
392 my $statfile = './op/stat.t';
393 ok(  -T $statfile,    '-T');
394 ok(! -B $statfile,    '!-B');
395 ok(-B $Perl,      '-B');
396 ok(! -T $Perl,    '!-T');
397
398 open(FOO,$statfile);
399 SKIP: {
400     eval { -T FOO; };
401     skip "-T/B on filehandle not implemented", 15 if $@ =~ /not implemented/;
402
403     is( $@, '',     '-T on filehandle causes no errors' );
404
405     ok(-T FOO,      '   -T');
406     ok(! -B FOO,    '   !-B');
407
408     $_ = <FOO>;
409     like($_, qr/perl/, 'after readline');
410     ok(-T FOO,      '   still -T');
411     ok(! -B FOO,    '   still -B');
412     close(FOO);
413
414     open(FOO,$statfile);
415     $_ = <FOO>;
416     like($_, qr/perl/,      'reopened and after readline');
417     ok(-T FOO,      '   still -T');
418     ok(! -B FOO,    '   still !-B');
419
420     ok(seek(FOO,0,0),   'after seek');
421     ok(-T FOO,          '   still -T');
422     ok(! -B FOO,        '   still !-B');
423
424     # It's documented this way in perlfunc *shrug*
425     () = <FOO>;
426     ok(eof FOO,         'at EOF');
427     ok(-T FOO,          '   still -T');
428     ok(-B FOO,          '   now -B');
429 }
430 close(FOO);
431
432
433 SKIP: {
434     skip "No null device to test with", 2 unless -e $Null;
435
436     ok(-T $Null,  'null device is -T');
437     ok(-B $Null,  '    and -B');
438 }
439
440
441 # and now, a few parsing tests:
442 $_ = $tmpfile;
443 ok(-f,      'bare -f   uses $_');
444 ok(-f(),    '     -f() "');
445
446 unlink $tmpfile or print "# unlink failed: $!\n";
447
448 # bug id 20011101.069 (#7861)
449 my @r = \stat($Curdir);
450 is(scalar @r, 13,   'stat returns full 13 elements');
451
452 stat $0;
453 eval { lstat _ };
454 like( $@, qr/^The stat preceding lstat\(\) wasn't an lstat/,
455     'lstat _ croaks after stat' );
456 eval { lstat *_ };
457 like( $@, qr/^The stat preceding lstat\(\) wasn't an lstat/,
458     'lstat *_ croaks after stat' );
459 eval { lstat \*_ };
460 like( $@, qr/^The stat preceding lstat\(\) wasn't an lstat/,
461     'lstat \*_ croaks after stat' );
462 eval { -l _ };
463 like( $@, qr/^The stat preceding -l _ wasn't an lstat/,
464     '-l _ croaks after stat' );
465
466 lstat $0;
467 eval { lstat _ };
468 is( "$@", "", "lstat _ ok after lstat" );
469 eval { -l _ };
470 is( "$@", "", "-l _ ok after lstat" );
471
472 eval { lstat "test.pl" };
473 {
474     open my $fh, "test.pl";
475     stat *$fh{IO};
476     eval { lstat _ }
477 }
478 like $@, qr/^The stat preceding lstat\(\) wasn't an lstat at /,
479 'stat $ioref resets stat type';
480
481 {
482     open(FOO, ">$tmpfile") || DIE("Can't open temp test file: $!");
483     my @statbuf = stat FOO;
484     stat "test.pl";
485     no warnings 'io';
486     my @lstatbuf = lstat *FOO{IO};
487     is "@lstatbuf", "@statbuf", 'lstat $ioref reverts to regular fstat';
488     close(FOO);
489     unlink $tmpfile or print "# unlink failed: $!\n";
490 }
491   
492 SKIP: {
493     skip "No lstat", 2 unless $Config{d_lstat};
494
495     # bug id 20020124.004 (#8334)
496     # If we have d_lstat, we should have symlink()
497     my $linkname = 'stat-' . rand =~ y/.//dr;
498     my $target = $Perl;
499     $target =~ s/;\d+\z// if $Is_VMS; # symlinks don't like version numbers
500     symlink $target, $linkname or die "# Can't symlink $0: $!";
501     lstat $linkname;
502     -T _;
503     eval { lstat _ };
504     like( $@, qr/^The stat preceding lstat\(\) wasn't an lstat/,
505         'lstat croaks after -T _' );
506     eval { -l _ };
507     like( $@, qr/^The stat preceding -l _ wasn't an lstat/,
508         '-l _ croaks after -T _' );
509     unlink $linkname or print "# unlink $linkname failed: $!\n";
510 }
511
512 SKIP: {
513     skip "Too much clock skew between system and filesystem", 5
514         if ($Filesystem_Time_Offset > 5);
515     print "# Zzz...\n";
516     sleep($Filesystem_Time_Offset+1);
517     my $f = 'tstamp.tmp';
518     unlink $f;
519     ok (open(S, "> $f"), 'can create tmp file');
520     close S or die;
521     my @a = stat $f;
522     print "# time=$^T, stat=(@a)\n";
523     my @b = (-M _, -A _, -C _);
524     print "# -MAC=(@b)\n";
525     ok( (-M _) < 0, 'negative -M works');
526   SKIP:
527     {
528         skip "Access timestamps inaccurate", 1 if $inaccurate_atime;
529         ok( (-A _) < 0, 'negative -A works');
530     }
531     ok( (-C _) < 0, 'negative -C works');
532     ok(unlink($f), 'unlink tmp file');
533 }
534
535 # [perl #4253]
536 {
537     ok(open(F, ">", $tmpfile), 'can create temp file');
538     close F;
539     chmod 0077, $tmpfile;
540     my @a = stat($tmpfile);
541     my $s1 = -s _;
542     -T _;
543     my $s2 = -s _;
544     is($s1, $s2, q(-T _ doesn't break the statbuffer));
545     SKIP: {
546         my $root_uid = $Is_Cygwin ? 18 : 0;
547         skip "No lstat", 1 unless $Config{d_lstat};
548         skip "uid=0", 1 if $< == $root_uid or $> == $root_uid;
549         skip "Can't check if admin user in miniperl", 1
550           if $^O =~ /^(cygwin|MSWin32|msys)$/ && is_miniperl();
551         skip "Readable by group/other means readable by me on $^O", 1 if $^O eq 'VMS'
552           or ($^O =~ /^(cygwin|MSWin32|msys)$/ and Win32::IsAdminUser());
553         lstat($tmpfile);
554         -T _;
555         ok(eval { lstat _ },
556            q(-T _ doesn't break lstat for unreadable file));
557     }
558     unlink $tmpfile;
559 }
560
561 SKIP: {
562     skip "No dirfd()", 4 unless $Config{d_dirfd} || $Config{d_dir_dd_fd};
563     ok(opendir(DIR, "."), 'Can open "." dir') || diag "Can't open '.':  $!";
564     ok(stat(DIR), "stat() on dirhandle works"); 
565     ok(-d -r _ , "chained -x's on dirhandle"); 
566     ok(-d DIR, "-d on a dirhandle works");
567     closedir DIR or die $!;
568 }
569
570 {
571     # RT #8244: *FILE{IO} does not behave like *FILE for stat() and -X() operators
572     ok(open(F, ">", $tmpfile), 'can create temp file');
573     my @thwap = stat *F{IO};
574     ok(@thwap, "stat(*F{IO}) works");    
575     ok( -f *F{IO} , "single file tests work with *F{IO}");
576     close F;
577     unlink $tmpfile;
578
579     #PVIO's hold dirhandle information, so let's test them too.
580
581     SKIP: {
582         skip "No dirfd()", 4 unless $Config{d_dirfd} || $Config{d_dir_dd_fd};
583         ok(opendir(DIR, "."), 'Can open "." dir') || diag "Can't open '.':  $!";
584         ok(stat(*DIR{IO}), "stat() on *DIR{IO} works");
585         ok(-d _ , "The special file handle _ is set correctly"); 
586         ok(-d -r *DIR{IO} , "chained -x's on *DIR{IO}");
587         closedir DIR or die $!;
588     }
589 }
590
591 # [perl #71002]
592 {
593     my $w;
594     local $SIG{__WARN__} = sub { warn shift; ++$w };
595     stat 'prepeinamehyparcheiarcheiometoonomaavto';
596     stat _;
597     is $w, undef, 'no unopened warning from stat _';
598 }
599
600 {
601     # [perl #123816]
602     # Inappropriate stacking of l?stat with filetests should either work or
603     # give a syntax error, they shouldn't crash.
604     eval { stat -t };
605     ok(1, 'can "stat -t" without crashing');
606         eval { lstat -t };
607     ok(1, 'can "lstat -t" without crashing');
608 }
609
610 # [perl #126064] stat stat stack busting
611 is join("-", 1,2,3,(stat stat stat),4,5,6), "1-2-3-4-5-6",
612   'stat inside stat gets scalar context';
613
614 # [perl #126162] stat an array should not work
615 # skip if -e '2'.
616 SKIP:
617 {
618     skip "There is a file named '2', which invalidates this test", 2 if -e '2';
619
620     my $Errno_loaded = eval { require Errno };
621     my @statarg = ($statfile, $statfile);
622     no warnings 'syntax';
623     ok !stat(@statarg),
624     'stat on an array of valid paths should warn and should not return any data';
625     my $error = 0+$!;
626     skip "Errno not available", 1
627       unless $Errno_loaded;
628     is $error, &Errno::ENOENT,
629       'stat on an array of valid paths should return ENOENT';
630 }
631
632 # [perl #131895] stat() doesn't fail on filenames containing \0 / NUL
633 {
634     no warnings 'syscalls';
635     ok !stat("TEST\0-"), 'stat on filename with \0';
636 }
637 SKIP: {
638     my $link = "stat_t_$$\_TEST.symlink";
639     my $can_symlink = eval { symlink "TEST", $link };
640     skip "cannot symlink", 1 unless $can_symlink;
641     no warnings 'syscalls';
642     ok !lstat("$link\0-"), 'lstat on filename with \0';
643     unlink $link;
644 }
645
646 END {
647     chmod 0666, $tmpfile;
648     unlink_all $tmpfile;
649 }