File Coverage

blib/lib/Net/BitTorrent/Torrent/File.pm
Criterion Covered Total %
statement 159 223 71.3
branch 77 132 58.3
condition 28 63 44.4
subroutine 23 26 88.4
pod 9 9 100.0
total 296 453 65.3


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             package Net::BitTorrent::Torrent::File;
3             {
4 11     11   172275 use strict;
  11         26  
  11         473  
5 11     11   62 use warnings;
  11         23  
  11         442  
6 11     11   59 use Carp qw[carp];
  11         1219  
  11         812  
7 11     11   62 use Scalar::Util qw[blessed weaken refaddr];
  11         24  
  11         702  
8 11     11   64 use Fcntl qw[/O_/ /SEEK/ :flock];
  11         19  
  11         6639  
9 11     11   78 use version qw[qv];
  11         20  
  11         165  
10             our $VERSION_BASE = 50; our $UNSTABLE_RELEASE = 0; our $VERSION = sprintf(($UNSTABLE_RELEASE ? q[%.3f_%03d] : q[%.3f]), (version->new(($VERSION_BASE))->numify / 1000), $UNSTABLE_RELEASE);
11             my (@CONTENTS)
12             = \
13             my (%path, %torrent, %size, %index, %priority, %mode, %handle,
14             %win32_handle);
15             my %REGISTRY = ();
16              
17             sub new {
18 140     140 1 1975 my ($class, $args) = @_;
19 140         231 my $self;
20 140 100 100     934 if ((!$args) || (ref($args) ne q[HASH])) {
21 2         415 carp
22             q[Net::BitTorrentS::Torrent::File->new({}) requires parameters to be passed as a hashref];
23 2         20 return;
24             }
25 138 100       408 if (!$args->{q[Path]}) {
26 1         179 carp
27             q[Net::BitTorrent::Torrent::File->new({}) requires a 'Path' parameter];
28 1         40 return;
29             }
30 137 50 66     2796 if ( (!$args->{q[Torrent]})
      33        
31             || (!blessed $args->{q[Torrent]})
32             || (!$args->{q[Torrent]}->isa(q[Net::BitTorrent::Torrent])))
33 2         223 { carp
34             q[Net::BitTorrent::Torrent::File->new({}) requires a 'Torrent' parameter];
35 2         66 return;
36             }
37 135 100 66     1961 if ((!defined $args->{q[Size]}) || ($args->{q[Size]} !~ m[^\d+$])) {
38 4         507 carp
39             q[Net::BitTorrent::Torrent::File->new({}) requires an integer value for 'Size'];
40 4         150 return;
41             }
42 131 100 66     1537 if ((!defined $args->{q[Index]}) || ($args->{q[Index]} !~ m[^\d+$])) {
43 5         618 carp
44             q[Net::BitTorrent::Torrent::File->new({}) requires an 'Index' parameter];
45 5         151 return;
46             }
47 126         544 $self = bless \$args->{q[Path]}, $class;
48 126         956 $path{refaddr $self} = $args->{q[Path]};
49 126         7527 $torrent{refaddr $self} = $args->{q[Torrent]};
50 126         1000 weaken $torrent{refaddr $self};
51 126         525 $size{refaddr $self} = $args->{q[Size]};
52 126         560 $index{refaddr $self} = $args->{q[Index]};
53 126         418 $priority{refaddr $self} = 2;
54 126         707 weaken($REGISTRY{refaddr $self} = $self);
55 126         456 return $self;
56             }
57              
58             # Accessors | public
59 1496     1496 1 10135 sub priority { return $priority{refaddr +shift} }
60              
61             sub set_priority {
62 12     12 1 58 my ($self, $newval) = @_;
63 12 100       36 if (not defined $newval) {
64 1         95 carp
65             q[Net::BitTorrent::Torrent::File->set_priority() requires an priority parameter];
66 1         35 return;
67             }
68 11 100       58 if ($newval !~ m[^\d+$]) {
69 2         188 carp
70             q[Net::BitTorrent::Torrent::File->set_priority() requires an integer];
71 2         68 return;
72             }
73 9         48 return $priority{refaddr $self} = $newval;
74             }
75 13     13 1 96 sub mode { return $mode{refaddr +shift} }
76 2261     2261 1 23300 sub size { return $size{refaddr +shift} }
77 1     1 1 24 sub torrent { return $torrent{refaddr +shift} }
78 1     1 1 9 sub index { return $index{refaddr +shift} }
79 28     28 1 1009 sub path { return $path{refaddr +shift} }
80              
81             # Accessors | Private
82             sub _percent_complete {
83 0     0   0 my ($self) = @_;
84 0         0 my $start = 0;
85 0         0 for my $index (0 .. $index{refaddr $self} - 1) {
86 0         0 $start += $torrent{refaddr $self}->files->[$index]->size;
87             }
88 0         0 my $end = $start + $size{refaddr $self};
89 0         0 my $piece_length = $torrent{refaddr $self}->raw_data(1)
90             ->{q[info]}{q[piece length]};
91 0         0 my $have = 0;
92 0         0 my $_bitfield = $torrent{refaddr +shift}->bitfield;
93 0         0 $start = int($start / $piece_length);
94 0         0 $end = int(($end / $piece_length) + 1);
95 0         0 for my $index ($start .. $end) {
96 0         0 $have += vec($_bitfield, $index, 1);
97             }
98 0         0 my $return = ($have / ($end - $start) * 100);
99 0 0       0 return $return > 100 ? 100 : $return;
100             }
101              
102             # Methods | Private
103             sub _open {
104 329     329   536 my ($self, $mode) = @_;
105 329 100 66     1667 if ((!$mode) || ($mode !~ m[^[rw]$])) {
106 2         228 carp
107             q[Net::BitTorrent::Torrent::File->_open() requires a valid mode];
108 2         68 return;
109             }
110 327 100 100     2572 if (defined $handle{refaddr $self} and defined $mode{refaddr $self}) {
111 36 100       152 if ($mode{refaddr $self} eq $mode) {
112 25         244 return sysseek($handle{refaddr $self}, 0, SEEK_SET);
113             }
114 11 100       49 if ($mode{refaddr $self} eq q[w]) {
115 9 50       100 flock($handle{refaddr $self}, LOCK_UN) or return;
116             }
117 11         38 $self->_close;
118             }
119 302         751 $self->_mkpath;
120 302 100       711 my $mode_Fcntl = $mode eq q[r] ? O_RDONLY : O_WRONLY;
121 302 100       1021 if (not $self->_sysopen(($mode eq q[r] ? (O_RDONLY) : (O_WRONLY)))) {
    100          
122 274 0       698 $torrent{refaddr $self}->_event(
    50          
123             q[file_error],
124             {File => $self,
125             Message => sprintf(q[Cannot open file for %s: %s],
126             ($mode eq q[r] ? q[read] : q[write]), $^E
127             )
128             }
129             ) if $mode eq q[w];
130 274         1985 return;
131             }
132 28         143 $mode{refaddr $self} = $mode;
133 28 100       521 if (not flock($handle{refaddr $self},
    50          
134             (($mode{refaddr $self} eq q[r]) ? LOCK_SH : LOCK_EX)
135             )
136             )
137 0 0       0 { $torrent{refaddr $self}->_event(
138             q[file_error],
139             {File => $self,
140             Message => sprintf(q[Cannot lock file for %s: %s],
141             ($mode eq q[r] ? q[read] : q[write]), $^E
142             )
143             }
144             );
145 0 0       0 $torrent{refaddr $self}->_set_error(
146             sprintf(q[Cannot lock '%s' for %s: %s],
147             $path{refaddr $self},
148             ($mode eq q[r] ? q[read] : q[write]), $^E
149             )
150             );
151 0         0 return;
152             }
153 28         367 $torrent{refaddr $self}->_event(q[file_open],
154             {File => $self, Mode => $mode{refaddr $self}});
155 28         4446 return defined $handle{refaddr $self};
156             }
157              
158             sub _write {
159 13     13   34 my ($self, $data) = @_;
160 13 100       70 if (not defined $data) {return}
  1         5  
161 12 100       193 if (not $handle{refaddr $self}) {
    100          
    100          
162 2         28 $torrent{refaddr $self}->_event(
163             q[file_error],
164             {File => $self,
165             Message => q[Cannot write to file: File not open]
166             }
167             );
168 2         996 $torrent{refaddr $self}->_set_error(
169             sprintf(q[Cannot write to '%s': File not open],
170             $path{refaddr $self})
171             );
172 2         13 return;
173             }
174             elsif ($mode{refaddr $self} ne q[w]) {
175 1         60 $torrent{refaddr $self}->_event(
176             q[file_error],
177             {File => $self,
178             Message => q[Cannot write to file: File not open for write]
179             }
180             );
181 1         510 $torrent{refaddr $self}->_set_error(
182             sprintf(q[Cannot write to '%s': File not open for write],
183             $path{refaddr $self})
184             );
185 1         6 return;
186             }
187             elsif (($self->_systell + length($data)) > $size{refaddr $self}) {
188 2         10 $torrent{refaddr $self}->_event(
189             q[file_error],
190             {File => $self,
191             Message => sprintf(
192             q[Cannot write beyond end of file (tell: %d | data:%d bytes | size: %d) (%d > %d)],
193             $self->_systell,
194             length($data),
195             $size{refaddr $self},
196             ($self->_systell + length($data)),
197             $size{refaddr $self}
198             )
199             }
200             );
201 2         927 $torrent{refaddr $self}->_set_error(
202             sprintf(
203             <<'END', $path{refaddr $self},
204             Cannot write to '%s': Beyond end of file.
205              
206             This may be a bug in Net::BitTorrent.
207             Status for bug report: (tell: %d | data:%d bytes | size: %d) (%d > %d)
208             END
209             $self->_systell,
210             length($data),
211             $size{refaddr $self},
212             ($self->_systell + length($data)),
213             $size{refaddr $self}
214             )
215             );
216 2         13 return;
217             }
218 7 50       423 truncate($handle{refaddr $self}, $size{refaddr $self})
219             if -s $handle{refaddr $self} != $size{refaddr $self};
220 7         18 my $expected_length = length $data;
221 7         981 my $actual_length
222             = syswrite($handle{refaddr $self}, $data, $expected_length);
223 7 50       21 if (defined $actual_length) {
224 7 50       27 if ($actual_length != $expected_length) {
225 0         0 $torrent{refaddr $self}->_event(
226             q[file_error],
227             {File => $self,
228             Message => sprintf(
229             q[Cannot write %d bytes of data to file; Wrote %d bytes instead (%s)],
230             length($data), $actual_length, $^E
231             )
232             }
233             );
234 0         0 $torrent{refaddr $self}->_set_error(
235             sprintf(
236             q[Cannot write %d bytes to '%s': Wrote %d bytes instead (%s)],
237             length($data), $path{refaddr $self},
238             $actual_length, $^E
239             )
240             );
241 0         0 return;
242             }
243             }
244             else {
245 0         0 $torrent{refaddr $self}->_event(
246             q[file_error],
247             {File => $self,
248             Message => sprintf(
249             q[Cannot write %d bytes of data to file (%s)],
250             length($data), $^E
251             )
252             }
253             );
254 0         0 $torrent{refaddr $self}->_set_error(
255             sprintf(q[Cannot write %d bytes to '%s' (%s)],
256             length($data), $path{refaddr $self}, $^E
257             )
258             );
259 0         0 return;
260             }
261 7         64 $torrent{refaddr $self}->_event(q[file_write],
262             {File => $self, Length => $actual_length});
263 7         34 return $actual_length;
264             }
265              
266             sub _read {
267 41     41   81 my ($self, $length) = @_;
268 41 100 66     309 if ((!defined $length) || ($length !~ m[^\d+$])) {
269 2         271 carp
270             q[Net::BitTorrent::Torrent::File->_read( LENGTH ) requires a length];
271 2         82 return;
272             }
273 39         76 my $data = q[];
274 39 100       299 if (not $handle{refaddr $self}) {
    100          
    100          
275 1         13 $torrent{refaddr $self}->_event(
276             q[file_error],
277             {File => $self,
278             Message => q[Cannot read from file: File not open]
279             }
280             );
281 1         469 $torrent{refaddr $self}->_set_error(
282             sprintf(q[Cannot read from '%s': File not open],
283             $path{refaddr $self})
284             );
285 1         6 return;
286             }
287             elsif ($mode{refaddr $self} ne q[r]) {
288 1         15 $torrent{refaddr $self}->_event(
289             q[file_error],
290             {File => $self,
291             Message => q[Cannot read from file: File not open for read]
292             }
293             );
294 1         384 $torrent{refaddr $self}->_set_error(
295             sprintf(q[Cannot read from '%s': File not open for read],
296             $path{refaddr $self})
297             );
298 1         6 return;
299             }
300             elsif ($self->_systell + $length > $size{refaddr $self}) {
301 1         17 $torrent{refaddr $self}->_event(
302             q[file_error],
303             {File => $self,
304             Message => q[Cannot read beyond end of file]
305             }
306             );
307 1         425 $torrent{refaddr $self}->_set_error(
308             sprintf(
309             q[Cannot read from '%s': Cannot read beyond end of file],
310             $path{refaddr $self})
311             );
312 1         6 return;
313             }
314             else {
315 36 50       543 truncate($handle{refaddr $self}, $size{refaddr $self})
316             if -s $handle{refaddr $self} != $size{refaddr $self};
317 36         858 my $real_length = sysread($handle{refaddr $self}, $data, $length);
318 36 50       105 if ($real_length != $length) {
319 0         0 $torrent{refaddr $self}->_event(
320             q[file_error],
321             {File => $self,
322             Message => sprintf(q[Failed to read %d bytes from file],
323             $length)
324             }
325             );
326 0         0 $torrent{refaddr $self}->_set_error(
327             sprintf(q[Cannot read %d bytes from '%s'],
328             $length, $path{refaddr $self}
329             )
330             );
331 0         0 return;
332             }
333             }
334 36         360 $torrent{refaddr $self}->_event(q[file_read],
335             {File => $self,
336             Length => length($data)
337             }
338             );
339 36         546 return $data;
340             }
341              
342             sub _systell {
343 112     112   161 my ($self) = @_;
344 112 100       438 if (not $handle{refaddr $self}) {
345 2         18 $torrent{refaddr $self}->_event(
346             q[file_error],
347             {File => $self,
348             Message => q[Cannot get filehandle position: File not open],
349             }
350             );
351 2         987 $torrent{refaddr $self}->_set_error(
352             sprintf(
353             q[Cannot get filehandle position for '%s': File not open],
354             $path{refaddr $self})
355             );
356 2         10 return;
357             }
358 110         1303 return sysseek($handle{refaddr $self}, 0, SEEK_CUR);
359             }
360              
361             sub _sysseek {
362 50     50   94 my ($self, $position, $wence) = @_;
363 50 50       111 $wence = defined $wence ? $wence : SEEK_SET;
364 50 100 33     455 if (not defined $handle{refaddr $self}) {
    100 33        
    50 33        
    100 66        
      33        
365 1         16 $torrent{refaddr $self}->_event(
366             q[file_error],
367             {File => $self,
368             Message => q[Cannot set filehandle position: File not open]
369             }
370             );
371 1         445 $torrent{refaddr $self}->_set_error(
372             sprintf(
373             q[Cannot set filehandle position for '%s': File not open],
374             $path{refaddr $self})
375             );
376 1         5 return;
377             }
378             elsif (not defined $position) {
379 1         10 $torrent{refaddr $self}->_event(
380             q[file_error],
381             {File => $self,
382             Message => q[Cannot seek: Undefined position]
383             }
384             );
385 1         478 $torrent{refaddr $self}->_set_error(
386             sprintf(
387             q[Cannot get filehandle position for '%s': Undefined position],
388             $path{refaddr $self})
389             );
390 1         7 return;
391             }
392             elsif (
393             ( (($position < 0) and ($wence == SEEK_SET))
394             or
395             ((($position + $self->_systell()) < 0) and ($wence == SEEK_CUR))
396             )
397             or (($position > 0) and ($wence == SEEK_END))
398             )
399 0         0 { $torrent{refaddr $self}->_event(
400             q[file_error],
401             {File => $self,
402             Message =>
403             sprintf(q[Cannot seek beyond the start of file (0 > %d)],
404             $position)
405             }
406             );
407 0         0 $torrent{refaddr $self}->_set_error(
408             sprintf(
409             q[Cannot set filehandle position for '%s': Beyond start of file (0 > %d)],
410             $path{refaddr $self}, $position
411             )
412             );
413 0         0 return;
414             }
415             elsif ((abs($position) > $size{refaddr $self})) {
416 3 50       55 $torrent{refaddr $self}->_event(
417             q[file_error],
418             {File => $self,
419             Message => sprintf(
420             q[Cannot seek beyond %s of file (%d > %d)],
421             ($position > 0 ? q[start] : q[end]),
422             $position,
423             $size{refaddr $self}
424             )
425             }
426             );
427 3 50       1352 $torrent{refaddr $self}->_set_error(
428             sprintf(
429             q[Cannot set filehandle position for '%s': Beyond %s of file (%d > %d)],
430             $path{refaddr $self},
431             ($position > 0 ? q[start] : q[end]),
432             $position,
433             $size{refaddr $self}
434             )
435             );
436 3         18 return;
437             }
438 45         298 return sysseek($handle{refaddr $self}, $position, $wence);
439             }
440              
441             sub _sysopen {
442 302     302   435 my ($self, $mode) = @_;
443 302 100       729 $self->_mkpath() if $mode &= O_WRONLY;
444 302 0 33     1109 if (( $^O eq q[MSWin32]
      33        
      0        
445             and utf8::is_utf8($path{refaddr $self})
446             and require Win32API::File
447             and require Encode
448             )
449             )
450 0         0 { Win32API::File->import(qw[:ALL]);
451 0         0 Encode->import(qw[find_encoding encode]);
452 0         0 for my $null (qq[\0], q[]) {
453 0 0       0 $win32_handle{refaddr $self}
    0          
    0          
454             = CreateFileW(
455             encode(
456             q[UTF-16LE], $path{refaddr $self} . $null
457             ),
458             (($mode &= O_WRONLY) ? GENERIC_WRITE()
459             : GENERIC_READ()
460             ),
461             FILE_SHARE_READ(),
462             [],
463             (($mode &= O_WRONLY) ? OPEN_ALWAYS()
464             : OPEN_EXISTING()
465             ),
466             FILE_ATTRIBUTE_NORMAL(),
467             0
468             ) and last;
469             }
470 0 0       0 return if not $win32_handle{refaddr $self};
471 0         0 my $fd = OsFHandleOpenFd($win32_handle{refaddr $self}, $mode);
472 0 0       0 return if $fd < 0;
473             return
474 0 0       0 open($handle{refaddr $self},
475             (($mode &= O_WRONLY)
476             ? q[>&]
477             : q[<&]
478             ),
479             $fd
480             );
481             }
482             return
483 302 100       10779 sysopen($handle{refaddr $self},
484             $path{refaddr $self},
485             $mode | (($mode &= O_WRONLY)
486             ? O_CREAT
487             : 0
488             )
489             );
490             }
491              
492             sub _close {
493 79     79   268 my ($self) = @_;
494 79 100       631 return if not defined $mode{refaddr $self};
495 27 50 33     142 if (defined $win32_handle{refaddr $self} and require Win32API::File) {
496 0         0 Win32API::File::CloseHandle($win32_handle{refaddr $self});
497 0         0 delete $win32_handle{refaddr $self};
498             }
499 27         609 my $return = CORE::close($handle{refaddr $self});
500 27 50       76 if ($return) {
501 27         85 delete $mode{refaddr $self};
502 27         135 delete $handle{refaddr $self};
503 27         186 $torrent{refaddr $self}->_event(q[file_close], {File => $self});
504 27         3898 return $return;
505             }
506 0         0 $torrent{refaddr $self}->_event(
507             q[file_error],
508             {File => $self,
509             Message => sprintf(q[Cannot close file: %s], $^E)
510             }
511             );
512 0         0 return;
513             }
514              
515             sub _mkpath {
516 316     316   509 my ($self) = @_;
517 316         5053 my ($vol, $dir, $file) = File::Spec->splitpath($path{refaddr $self});
518 316 100       17338 if (not -d File::Spec->catpath($vol, $dir, q[])) {
519 19 50 33     389 if ( $^O eq q[MSWin32]
    50 33        
      0        
      0        
520             and utf8::is_utf8($path{refaddr $self})
521             and require Win32
522             and require Win32API::File
523             and require Encode)
524 0         0 { Win32API::File->import(qw[:ALL]);
525 0         0 Encode->import(qw[encode]);
526 0         0 my $path = $vol;
527 0         0 foreach my $this_dir (
528             File::Spec->splitdir(File::Spec->catdir($dir)))
529 0 0       0 { next unless length($this_dir);
530 0         0 $path = File::Spec->catdir($path, $this_dir);
531 0         0 utf8::decode($path);
532 0 0       0 next if -d $path;
533 0         0 Win32::CreateDirectory($path);
534             }
535             }
536             elsif (require File::Path) {
537 19         5806 File::Path::mkpath(File::Spec->catpath($vol, $dir, q[]),
538             {verbose => 0});
539             }
540             }
541 316         2071 return 1;
542             }
543              
544             sub as_string {
545 0     0 1 0 my ($self, $advanced) = @_;
546 0         0 my $dump = !$advanced ? $path{refaddr $self} : sprintf <<'END',
547             Net::BitTorrent::Torrent::File
548              
549             Path: %s
550             Size: %d bytes
551             Priority: %d
552             Open mode: %s
553             Complete: %3.2f%%
554              
555             Torrent: %s
556             Index: %d of %d
557             END
558             $path{refaddr $self}, $size{refaddr $self},
559             $priority{refaddr $self},
560             ( !$mode{refaddr $self} ? q[Closed]
561             : $mode{refaddr $self} eq q[ro] ? q[Read only]
562             : $mode{refaddr $self} eq q[wo] ? q[Write only]
563             : $mode{refaddr $self} eq q[rw] ? q[Read/Write]
564             : q[Closed]
565             ),
566             $self->_percent_complete,
567             $torrent{refaddr $self}->infohash, $index{refaddr $self},
568 0 0       0 scalar(@{$torrent{refaddr $self}->files});
    0          
    0          
    0          
    0          
569 0 0       0 return defined wantarray ? $dump : print STDERR qq[$dump\n];
570             }
571              
572             sub CLONE {
573 0     0   0 for my $_oID (keys %REGISTRY) {
574 0         0 my $_obj = $REGISTRY{$_oID};
575 0         0 my $_nID = refaddr $_obj;
576 0         0 for (@CONTENTS) {
577 0         0 $_->{$_nID} = $_->{$_oID};
578 0         0 delete $_->{$_oID};
579             }
580 0         0 weaken $torrent{$_nID};
581 0         0 weaken($REGISTRY{$_nID} = $_obj);
582 0         0 delete $REGISTRY{$_oID};
583             }
584 0         0 return 1;
585             }
586             DESTROY {
587 70     70   151 my ($self) = @_;
588 70         172 for (@CONTENTS) { delete $_->{refaddr $self}; }
  560         1861  
589 70         1049 return delete $REGISTRY{refaddr $self};
590             }
591             1;
592             }
593              
594             =pod
595              
596             =head1 NAME
597              
598             Net::BitTorrent::Torrent::File - BitTorrent File I/O Class
599              
600             =head1 Constructor
601              
602             =over 4
603              
604             =item C
605              
606             Creates a C object. This constructor
607             should not be used directly.
608              
609             =back
610              
611             =head1 Methods
612              
613             =over 4
614              
615             =item C
616              
617             Returns the zero based index of this file according to the related
618             L object's file
619             list.
620              
621             =item C
622              
623             Returns a value representing if and how the related file handle is open.
624             Possible values:
625              
626             'ro' - Read only
627             'wo' - Write only
628             'rw' - Read and Write
629             undef - Closed
630              
631             =item C
632              
633             Returns the absolute path of the related file.
634              
635             =item C
636              
637             Returns the download priority of this file.
638              
639             See also: L
640              
641             =item C
642              
643             Sets the download priority of this file.
644              
645             By default, all files begin with a level two (2) priority with the
646             intent being on a C<0> (skip), C<1> (low), C<2> (normal), C<3> (high)
647             priority scale but you may use any scale you want. For example, you
648             could set a file's priority to say... C<1,000,000>, leave everything
649             else at the default C<2> and and be positive we'll work on it first.
650             To avoid downloading this file, set priority to C<0>.
651              
652             See also: L
653              
654             NOTE: Setting the priority to C<0> will tell C not
655             to bother requesting these pieces however, the file will still be created
656             on disk if a piece we want overlaps onto this file. Just give me some
657             time to work on an intermediate .piece file and this problem will go
658             away.
659              
660             =item C
661              
662             Returns the L
663             object related to this file.
664              
665             =item C
666              
667             Returns the size of the file represented by this object.
668              
669             =item C
670              
671             Returns a 'ready to print' dump of the object's data structure. If
672             called in void context, the structure is printed to C.
673             C is a boolean value.
674              
675             =back
676              
677             =head1 Author
678              
679             Sanko Robinson - http://sankorobinson.com/
680              
681             CPAN ID: SANKO
682              
683             =head1 License and Legal
684              
685             Copyright (C) 2008-2009 by Sanko Robinson Esanko@cpan.orgE
686              
687             This program is free software; you can redistribute it and/or modify
688             it under the terms of The Artistic License 2.0. See the F
689             file included with this distribution or
690             http://www.perlfoundation.org/artistic_license_2_0. For
691             clarification, see http://www.perlfoundation.org/artistic_2_0_notes.
692              
693             When separated from the distribution, all POD documentation is covered
694             by the Creative Commons Attribution-Share Alike 3.0 License. See
695             http://creativecommons.org/licenses/by-sa/3.0/us/legalcode. For
696             clarification, see http://creativecommons.org/licenses/by-sa/3.0/us/.
697              
698             Neither this module nor the L is affiliated with
699             BitTorrent, Inc.
700              
701             =for svn $Id: File.pm d3c97de 2009-09-12 04:31:46Z sanko@cpan.org $
702              
703             =cut