1*0Sstevel@tonic-gate# NOTE: this file tests how large files (>2GB) work with raw system IO. 2*0Sstevel@tonic-gate# stdio: open(), tell(), seek(), print(), read() is tested in t/op/lfs.t. 3*0Sstevel@tonic-gate# If you modify/add tests here, remember to update also t/op/lfs.t. 4*0Sstevel@tonic-gate 5*0Sstevel@tonic-gateBEGIN { 6*0Sstevel@tonic-gate chdir 't' if -d 't'; 7*0Sstevel@tonic-gate @INC = '../lib'; 8*0Sstevel@tonic-gate require Config; import Config; 9*0Sstevel@tonic-gate # Don't bother if there are no quad offsets. 10*0Sstevel@tonic-gate if ($Config{lseeksize} < 8) { 11*0Sstevel@tonic-gate print "1..0 # Skip: no 64-bit file offsets\n"; 12*0Sstevel@tonic-gate exit(0); 13*0Sstevel@tonic-gate } 14*0Sstevel@tonic-gate require Fcntl; import Fcntl qw(/^O_/ /^SEEK_/); 15*0Sstevel@tonic-gate} 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gateuse strict; 18*0Sstevel@tonic-gate 19*0Sstevel@tonic-gate$| = 1; 20*0Sstevel@tonic-gate 21*0Sstevel@tonic-gateour @s; 22*0Sstevel@tonic-gateour $fail; 23*0Sstevel@tonic-gate 24*0Sstevel@tonic-gatesub zap { 25*0Sstevel@tonic-gate close(BIG); 26*0Sstevel@tonic-gate unlink("big"); 27*0Sstevel@tonic-gate unlink("big1"); 28*0Sstevel@tonic-gate unlink("big2"); 29*0Sstevel@tonic-gate} 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gatesub bye { 32*0Sstevel@tonic-gate zap(); 33*0Sstevel@tonic-gate exit(0); 34*0Sstevel@tonic-gate} 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gatemy $explained; 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gatesub explain { 39*0Sstevel@tonic-gate unless ($explained++) { 40*0Sstevel@tonic-gate print <<EOM; 41*0Sstevel@tonic-gate# 42*0Sstevel@tonic-gate# If the lfs (large file support: large meaning larger than two 43*0Sstevel@tonic-gate# gigabytes) tests are skipped or fail, it may mean either that your 44*0Sstevel@tonic-gate# process (or process group) is not allowed to write large files 45*0Sstevel@tonic-gate# (resource limits) or that the file system (the network filesystem?) 46*0Sstevel@tonic-gate# you are running the tests on doesn't let your user/group have large 47*0Sstevel@tonic-gate# files (quota) or the filesystem simply doesn't support large files. 48*0Sstevel@tonic-gate# You may even need to reconfigure your kernel. (This is all very 49*0Sstevel@tonic-gate# operating system and site-dependent.) 50*0Sstevel@tonic-gate# 51*0Sstevel@tonic-gate# Perl may still be able to support large files, once you have 52*0Sstevel@tonic-gate# such a process, enough quota, and such a (file) system. 53*0Sstevel@tonic-gate# It is just that the test failed now. 54*0Sstevel@tonic-gate# 55*0Sstevel@tonic-gateEOM 56*0Sstevel@tonic-gate } 57*0Sstevel@tonic-gate print "1..0 # Skip: @_\n" if @_; 58*0Sstevel@tonic-gate} 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gateprint "# checking whether we have sparse files...\n"; 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate# Known have-nots. 63*0Sstevel@tonic-gateif ($^O eq 'MSWin32' || $^O eq 'NetWare' || $^O eq 'VMS') { 64*0Sstevel@tonic-gate print "1..0 # Skip: no sparse files in $^O\n"; 65*0Sstevel@tonic-gate bye(); 66*0Sstevel@tonic-gate} 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate# Known haves that have problems running this test 69*0Sstevel@tonic-gate# (for example because they do not support sparse files, like UNICOS) 70*0Sstevel@tonic-gateif ($^O eq 'unicos') { 71*0Sstevel@tonic-gate print "1..0 # Skip: no sparse files in $^0, unable to test large files\n"; 72*0Sstevel@tonic-gate bye(); 73*0Sstevel@tonic-gate} 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate# Then try heuristically to deduce whether we have sparse files. 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate# We'll start off by creating a one megabyte file which has 78*0Sstevel@tonic-gate# only three "true" bytes. If we have sparseness, we should 79*0Sstevel@tonic-gate# consume less blocks than one megabyte (assuming nobody has 80*0Sstevel@tonic-gate# one megabyte blocks...) 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gatesysopen(BIG, "big1", O_WRONLY|O_CREAT|O_TRUNC) or 83*0Sstevel@tonic-gate do { warn "sysopen big1 failed: $!\n"; bye }; 84*0Sstevel@tonic-gatesysseek(BIG, 1_000_000, SEEK_SET) or 85*0Sstevel@tonic-gate do { warn "sysseek big1 failed: $!\n"; bye }; 86*0Sstevel@tonic-gatesyswrite(BIG, "big") or 87*0Sstevel@tonic-gate do { warn "syswrite big1 failed; $!\n"; bye }; 88*0Sstevel@tonic-gateclose(BIG) or 89*0Sstevel@tonic-gate do { warn "close big1 failed: $!\n"; bye }; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gatemy @s1 = stat("big1"); 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gateprint "# s1 = @s1\n"; 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gatesysopen(BIG, "big2", O_WRONLY|O_CREAT|O_TRUNC) or 96*0Sstevel@tonic-gate do { warn "sysopen big2 failed: $!\n"; bye }; 97*0Sstevel@tonic-gatesysseek(BIG, 2_000_000, SEEK_SET) or 98*0Sstevel@tonic-gate do { warn "sysseek big2 failed: $!\n"; bye }; 99*0Sstevel@tonic-gatesyswrite(BIG, "big") or 100*0Sstevel@tonic-gate do { warn "syswrite big2 failed; $!\n"; bye }; 101*0Sstevel@tonic-gateclose(BIG) or 102*0Sstevel@tonic-gate do { warn "close big2 failed: $!\n"; bye }; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gatemy @s2 = stat("big2"); 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gateprint "# s2 = @s2\n"; 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gatezap(); 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gateunless ($s1[7] == 1_000_003 && $s2[7] == 2_000_003 && 111*0Sstevel@tonic-gate $s1[11] == $s2[11] && $s1[12] == $s2[12]) { 112*0Sstevel@tonic-gate print "1..0 # Skip: no sparse files?\n"; 113*0Sstevel@tonic-gate bye; 114*0Sstevel@tonic-gate} 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gateprint "# we seem to have sparse files...\n"; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate# By now we better be sure that we do have sparse files: 119*0Sstevel@tonic-gate# if we are not, the following will hog 5 gigabytes of disk. Ooops. 120*0Sstevel@tonic-gate# This may fail by producing some signal; run in a subprocess first for safety 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate$ENV{LC_ALL} = "C"; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gatemy $r = system '../perl', '-I../lib', '-e', <<'EOF'; 125*0Sstevel@tonic-gateuse Fcntl qw(/^O_/ /^SEEK_/); 126*0Sstevel@tonic-gatesysopen(BIG, "big", O_WRONLY|O_CREAT|O_TRUNC) or die $!; 127*0Sstevel@tonic-gatemy $sysseek = sysseek(BIG, 5_000_000_000, SEEK_SET); 128*0Sstevel@tonic-gatemy $syswrite = syswrite(BIG, "big"); 129*0Sstevel@tonic-gateexit 0; 130*0Sstevel@tonic-gateEOF 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gatesysopen(BIG, "big", O_WRONLY|O_CREAT|O_TRUNC) or 133*0Sstevel@tonic-gate do { warn "sysopen 'big' failed: $!\n"; bye }; 134*0Sstevel@tonic-gatemy $sysseek = sysseek(BIG, 5_000_000_000, SEEK_SET); 135*0Sstevel@tonic-gateunless (! $r && defined $sysseek && $sysseek == 5_000_000_000) { 136*0Sstevel@tonic-gate $sysseek = 'undef' unless defined $sysseek; 137*0Sstevel@tonic-gate explain("seeking past 2GB failed: ", 138*0Sstevel@tonic-gate $r ? 'signal '.($r & 0x7f) : "$! (sysseek returned $sysseek)"); 139*0Sstevel@tonic-gate bye(); 140*0Sstevel@tonic-gate} 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate# The syswrite will fail if there are are filesize limitations (process or fs). 143*0Sstevel@tonic-gatemy $syswrite = syswrite(BIG, "big"); 144*0Sstevel@tonic-gateprint "# syswrite failed: $! (syswrite returned ", 145*0Sstevel@tonic-gate defined $syswrite ? $syswrite : 'undef', ")\n" 146*0Sstevel@tonic-gate unless defined $syswrite && $syswrite == 3; 147*0Sstevel@tonic-gatemy $close = close BIG; 148*0Sstevel@tonic-gateprint "# close failed: $!\n" unless $close; 149*0Sstevel@tonic-gateunless($syswrite && $close) { 150*0Sstevel@tonic-gate if ($! =~/too large/i) { 151*0Sstevel@tonic-gate explain("writing past 2GB failed: process limits?"); 152*0Sstevel@tonic-gate } elsif ($! =~ /quota/i) { 153*0Sstevel@tonic-gate explain("filesystem quota limits?"); 154*0Sstevel@tonic-gate } else { 155*0Sstevel@tonic-gate explain("error: $!"); 156*0Sstevel@tonic-gate } 157*0Sstevel@tonic-gate bye(); 158*0Sstevel@tonic-gate} 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate@s = stat("big"); 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gateprint "# @s\n"; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gateunless ($s[7] == 5_000_000_003) { 165*0Sstevel@tonic-gate explain("kernel/fs not configured to use large files?"); 166*0Sstevel@tonic-gate bye(); 167*0Sstevel@tonic-gate} 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gatesub fail () { 170*0Sstevel@tonic-gate print "not "; 171*0Sstevel@tonic-gate $fail++; 172*0Sstevel@tonic-gate} 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gatesub offset ($$) { 175*0Sstevel@tonic-gate my ($offset_will_be, $offset_want) = @_; 176*0Sstevel@tonic-gate my $offset_is = eval $offset_will_be; 177*0Sstevel@tonic-gate unless ($offset_is == $offset_want) { 178*0Sstevel@tonic-gate print "# bad offset $offset_is, want $offset_want\n"; 179*0Sstevel@tonic-gate my ($offset_func) = ($offset_will_be =~ /^(\w+)/); 180*0Sstevel@tonic-gate if (unpack("L", pack("L", $offset_want)) == $offset_is) { 181*0Sstevel@tonic-gate print "# 32-bit wraparound suspected in $offset_func() since\n"; 182*0Sstevel@tonic-gate print "# $offset_want cast into 32 bits equals $offset_is.\n"; 183*0Sstevel@tonic-gate } elsif ($offset_want - unpack("L", pack("L", $offset_want)) - 1 184*0Sstevel@tonic-gate == $offset_is) { 185*0Sstevel@tonic-gate print "# 32-bit wraparound suspected in $offset_func() since\n"; 186*0Sstevel@tonic-gate printf "# %s - unpack('L', pack('L', %s)) - 1 equals %s.\n", 187*0Sstevel@tonic-gate $offset_want, 188*0Sstevel@tonic-gate $offset_want, 189*0Sstevel@tonic-gate $offset_is; 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate fail; 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate} 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gateprint "1..17\n"; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate$fail = 0; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gatefail unless $s[7] == 5_000_000_003; # exercizes pp_stat 200*0Sstevel@tonic-gateprint "ok 1\n"; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gatefail unless -s "big" == 5_000_000_003; # exercizes pp_ftsize 203*0Sstevel@tonic-gateprint "ok 2\n"; 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gatefail unless -e "big"; 206*0Sstevel@tonic-gateprint "ok 3\n"; 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gatefail unless -f "big"; 209*0Sstevel@tonic-gateprint "ok 4\n"; 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gatesysopen(BIG, "big", O_RDONLY) or do { warn "sysopen failed: $!\n"; bye }; 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gateoffset('sysseek(BIG, 4_500_000_000, SEEK_SET)', 4_500_000_000); 214*0Sstevel@tonic-gateprint "ok 5\n"; 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gateoffset('sysseek(BIG, 0, SEEK_CUR)', 4_500_000_000); 217*0Sstevel@tonic-gateprint "ok 6\n"; 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gateoffset('sysseek(BIG, 1, SEEK_CUR)', 4_500_000_001); 220*0Sstevel@tonic-gateprint "ok 7\n"; 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gateoffset('sysseek(BIG, 0, SEEK_CUR)', 4_500_000_001); 223*0Sstevel@tonic-gateprint "ok 8\n"; 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gateoffset('sysseek(BIG, -1, SEEK_CUR)', 4_500_000_000); 226*0Sstevel@tonic-gateprint "ok 9\n"; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gateoffset('sysseek(BIG, 0, SEEK_CUR)', 4_500_000_000); 229*0Sstevel@tonic-gateprint "ok 10\n"; 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gateoffset('sysseek(BIG, -3, SEEK_END)', 5_000_000_000); 232*0Sstevel@tonic-gateprint "ok 11\n"; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gateoffset('sysseek(BIG, 0, SEEK_CUR)', 5_000_000_000); 235*0Sstevel@tonic-gateprint "ok 12\n"; 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gatemy $big; 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gatefail unless sysread(BIG, $big, 3) == 3; 240*0Sstevel@tonic-gateprint "ok 13\n"; 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gatefail unless $big eq "big"; 243*0Sstevel@tonic-gateprint "ok 14\n"; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate# 705_032_704 = (I32)5_000_000_000 246*0Sstevel@tonic-gate# See that we don't have "big" in the 705_... spot: 247*0Sstevel@tonic-gate# that would mean that we have a wraparound. 248*0Sstevel@tonic-gatefail unless sysseek(BIG, 705_032_704, SEEK_SET); 249*0Sstevel@tonic-gateprint "ok 15\n"; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gatemy $zero; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gatefail unless read(BIG, $zero, 3) == 3; 254*0Sstevel@tonic-gateprint "ok 16\n"; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gatefail unless $zero eq "\0\0\0"; 257*0Sstevel@tonic-gateprint "ok 17\n"; 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gateexplain() if $fail; 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gatebye(); # does the necessary cleanup 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gateEND { 264*0Sstevel@tonic-gate # unlink may fail if applied directly to a large file 265*0Sstevel@tonic-gate # be paranoid about leaving 5 gig files lying around 266*0Sstevel@tonic-gate open(BIG, ">big"); # truncate 267*0Sstevel@tonic-gate close(BIG); 268*0Sstevel@tonic-gate 1 while unlink "big"; # standard portable idiom 269*0Sstevel@tonic-gate} 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate# eof 272