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