File Coverage

blib/lib/Filesys/DfPortable.pm
Criterion Covered Total %
statement 53 79 67.0
branch 14 40 35.0
condition 2 6 33.3
subroutine 4 4 100.0
pod 0 1 0.0
total 73 130 56.1


line stmt bran cond sub pod time code
1             package Filesys::DfPortable;
2              
3 1     1   7749 use strict;
  1         2  
  1         44  
4 1     1   4 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  1         2  
  1         76  
5 1     1   11 use Carp;
  1         3  
  1         1358  
6             require Exporter;
7             require DynaLoader;
8             require 5.006;
9              
10             @ISA = qw(Exporter DynaLoader);
11             @EXPORT = qw(dfportable);
12             $VERSION = '0.85';
13             bootstrap Filesys::DfPortable $VERSION;
14              
15             sub dfportable {
16 1     1 0 113 my ($dir, $block_size) = @_;
17 1         3 my ($used, $fused);
18 0         0 my ($per, $fper);
19 0         0 my ($user_blocks, $user_used);
20 0         0 my ($user_files, $user_fused);
21 1         3 my %fs = ();
22              
23              
24 1 50       6 (defined($dir)) ||
25             (croak "Usage: dfportable\(\$dir\) or dfportable\(\$dir\, \$block_size)");
26              
27             #### If no requested block size then we will return the values in bytes
28 1 50       5 ($block_size) ||
29             ($block_size = 1);
30              
31 1         42 my ($frsize, $blocks, $bfree, $bavail, $files, $ffree, $favail) = _dfportable($dir);
32              
33             #### Some system or XS failure, something like /proc, or bad $dir
34 1 50 33     12 if($frsize == 0 || $blocks == 0) {
35 0         0 return();
36             }
37              
38             #### Change to requested or default block size
39 1 50       7 if($block_size > $frsize) {
    50          
40 0         0 my $result = $block_size / $frsize;
41 0         0 $blocks /= $result;
42 0 0       0 ($bfree != 0) &&
43             ($bfree /= $result);
44             #### Keep bavail -
45 0 0       0 ($bavail < 0) &&
46             ($result *= -1);
47              
48 0 0       0 ($bavail != 0) &&
49             ($bavail /= $result);
50             }
51              
52             elsif($block_size < $frsize) {
53 1         3 my $result = $frsize / $block_size;
54 1         3 $blocks *= $result;
55 1         3 $bfree *= $result;
56             #### Keep bavail -
57 1 50       5 ($bavail < 0) &&
58             ($result *= -1);
59 1         3 $bavail *= $result;
60             }
61              
62 1         2 $used = $blocks - $bfree;
63              
64             #### There is a reserved amount for the su
65             #### or there are disk quotas
66 1 50       4 if($bfree > $bavail) {
67 1         2 $user_blocks = $blocks - ($bfree - $bavail);
68 1         2 $user_used = $user_blocks - $bavail;
69 1 50       4 if($bavail < 0) {
70             #### over 100%
71 0         0 my $tmp_bavail = $bavail;
72 0         0 $per = ($tmp_bavail *= -1) / $user_blocks;
73             }
74            
75             else {
76 1 50       3 if($user_used == 0) {
77 0         0 $per = 0;
78             }
79              
80             else {
81 1         3 $per = $user_used / $user_blocks;
82             }
83             }
84             }
85            
86             #### No reserved amount or quotas
87             else {
88 0 0       0 if($used == 0) {
89 0         0 $per = 0;
90             }
91            
92             else {
93 0         0 $per = $used / $blocks;
94 0         0 $user_blocks = $blocks;
95 0         0 $user_used = $used;
96             }
97             }
98              
99             #### round
100 1         3 $per *= 100;
101 1         3 $per += .5;
102            
103             #### over 100%
104 1 50       5 ($bavail < 0) &&
105             ($per += 100);
106              
107 1         4 $fs{per} = int($per);
108 1         3 $fs{blocks} = $blocks;
109 1         3 $fs{bfree} = $bfree;
110 1         2 $fs{bavail} = $bavail;
111 1         3 $fs{bused} = $used;
112              
113              
114              
115             #### Handle inodes if system supports them
116 1 50 33     7 if(defined $files && $files > 0) {
117 1         24 $fused = $files - $ffree;
118             #### There is a reserved amount
119 1 50       5 if($ffree > $favail) {
120 0         0 $user_files = $files - ($ffree - $favail);
121 0         0 $user_fused = $user_files - $favail;
122 0 0       0 if($favail < 0) {
123             #### over 100%
124 0         0 my $tmp_favail = $favail;
125 0         0 $fper = ($tmp_favail *= -1) / $user_files;
126             }
127            
128             else {
129 0 0       0 if($user_fused == 0) {
130 0         0 $fper = 0;
131             }
132              
133             else {
134 0         0 $fper = $user_fused / $user_files;
135             }
136             }
137             }
138            
139             #### su and user amount are the same
140             else {
141 1 50       3 if($fused == 0) {
142 0         0 $fper = 0;
143             }
144            
145             else {
146 1         3 $fper = $fused / $files;
147             }
148            
149 1         1 $user_files = $files;
150 1         3 $user_fused = $fused;
151             }
152              
153             #### round
154 1         2 $fper *= 100;
155 1         3 $fper += .5;
156            
157             #### over 100%
158 1 50       3 ($favail < 0) &&
159             ($fper += 100);
160              
161 1         3 $fs{fper} = int($fper);
162 1         3 $fs{files} = $files;
163 1         3 $fs{ffree} = $ffree;
164 1         2 $fs{favail} = $favail;
165 1         18 $fs{fused} = $fused;
166             #$fs{user_fused} = $user_fused;
167             #$fs{user_files} = $user_files;
168             }
169            
170             #### No valid inode info. Probably Windows or NFS
171             #### Instead of undefing, just have the user call exists().
172             #else {
173             # $fs{fper} = undef;
174             # $fs{files} = undef;
175             # $fs{ffree} = undef;
176             # $fs{favail} = undef;
177             # $fs{fused} = undef;
178             # $fs{user_fused} = undef;
179             # $fs{user_files} = undef;
180             #}
181            
182              
183 1         4 return(\%fs);
184             }
185              
186             1;
187             __END__
188              
189             =head1 NAME
190              
191             Filesys::DfPortable - Perl extension for filesystem disk space information.
192              
193             =head1 SYNOPSIS
194              
195              
196             use Filesys::DfPortable;
197              
198             my $ref = dfportable("C:\\"); # Default block size is 1, which outputs bytes
199             if(defined($ref)) {
200             print"Total bytes: $ref->{blocks}\n";
201             print"Total bytes free: $ref->{bfree}\n";
202             print"Total bytes avail to me: $ref->{bavail}\n";
203             print"Total bytes used: $ref->{bused}\n";
204             print"Percent full: $ref->{per}\n"
205             }
206              
207              
208             my $ref = dfportable("/tmp", 1024); # Display output in 1K blocks
209             if(defined($ref)) {
210             print"Total 1k blocks: $ref->{blocks}\n";
211             print"Total 1k blocks free: $ref->{bfree}\n";
212             print"Total 1k blocks avail to me: $ref->{bavail}\n";
213             print"Total 1k blocks used: $ref->{bused}\n";
214             print"Percent full: $ref->{per}\n"
215             }
216              
217              
218              
219             =head1 DESCRIPTION
220              
221             This module provides a portable way to obtain filesystem disk space
222             information.
223              
224             The module should work with all versions of Windows (95 and up),
225             and with all flavors of Unix that implement the C<statvfs> or the C<statfs>
226             calls. This would include Linux, *BSD, HP-UX, AIX, Solaris, Mac OS X, Irix,
227             Cygwin, etc ...
228              
229             This module differs from Filesys::Df in that it has added support
230             for Windows, but does not support open filehandles as a argument.
231              
232             C<dfportable()> requires a directory argument that represents the filesystem
233             you want to query. There is also an optional block size argument so that
234             you can tailor the size of the values returned. The default block size
235             is 1, this will cause the function to return the values in bytes.
236             If you never use the block size argument, then you can think of any
237             instance of "blocks" in this document to really mean "bytes".
238              
239             C<dfportable()> returns a reference to a hash. The keys available in
240             the hash are as follows:
241              
242             {blocks} = Total blocks on the filesystem.
243              
244             {bfree} = Total blocks free on the filesystem.
245              
246             {bavail} = Total blocks available to the user executing the Perl
247             application. This can be different than C<{bfree}> if you have per-user
248             quotas on the filesystem, or if the super user has a reserved amount.
249             C<{bavail}> can also be a negative value because of this. For instance
250             if there is more space being used then you have available to you.
251              
252             {bused} = Total blocks used on the filesystem.
253              
254             {per} = Percent of disk space used. This is based on the disk space
255             available to the user executing the application. In other words, if
256             the filesystem has 10% of its space reserved for the superuser, then
257             the percent used can go up to 110%.
258              
259             You can obtain inode information through the module as well. But you
260             must call C<exists()> on the C<{files}> key to make sure the information is
261             available. Some filesystems may not return inode information, for
262             example Windows, and some NFS filesystems.
263              
264             Here are the available inode keys:
265              
266             {files} = Total inodes on the filesystem.
267              
268             {ffree} = Total inodes free on the filesystem.
269              
270             {favail} = Total inodes available to the user executing the application.
271             See the rules for the C<{bavail}> key.
272              
273             {fused} = Total inodes used on the filesystem.
274              
275             {fper} = Percent of inodes used on the filesystem. See rules for the C<{per}>
276             key.
277              
278             If the C<dfportable()> call fails for any reason, it will return
279             C<undef>. This will probably happen if you do anything crazy like try
280             to get information for /proc, or if you pass an invalid filesystem name,
281             or if there is an internal error. C<dfportable()> will C<croak()> if you pass
282             it a undefined value.
283              
284             Requirements:
285             Your system must contain C<statvfs()>, C<statfs()>, C<GetDiskFreeSpaceA()>, or C<GetDiskFreeSpaceEx()>.
286             You must be running Perl 5.6 or higher.
287              
288             =head1 AUTHOR
289              
290             Ian Guthrie
291             IGuthrie@aol.com
292              
293             Copyright (c) 2006 Ian Guthrie. All rights reserved.
294             This program is free software; you can redistribute it and/or
295             modify it under the same terms as Perl itself.
296              
297             =head1 SEE ALSO
298              
299             statvfs(2), statfs(2), df(1), GetDiskFreeSpaceA, GetDiskFreeSpaceEx, Filesys::Df
300              
301             perl(1).
302              
303             =cut