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