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