File Coverage

blib/lib/Win32/DriveInfo.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             # Copyright (c) 1998-2001 by Mike Blazer. All rights reserved.
2              
3             package Win32::DriveInfo;
4              
5 1     1   2307 use Win32::API;
  0            
  0            
6             use Cwd;
7             use strict 'vars';
8             use vars qw/$VERSION
9             $GetVolumeInformation $GetDriveType $GetLogicalDrives
10             $GetVersionEx $GetDiskFreeSpace $GetDiskFreeSpaceEx/;
11              
12             use constant DWORD_NULL => pack("L",0);
13             $VERSION = '0.06';
14              
15             #==================
16             sub GetVersionEx () {
17             #==================
18             # on Win95 if returning $dwBuildNumber(low word of original)
19             # is greater than 1000, the system is running OSR 2 or a later release.
20             $GetVersionEx ||= new Win32::API("kernel32", "GetVersionEx", ['P'], 'N') or return;
21              
22             my ($dwOSVersionInfoSize, $dwMajorVersion, $dwMinorVersion,
23             $dwBuildNumber, $dwPlatformId, $szCSDVersion) =
24             (148, 0, 0, 0, 0, "\0"x128);
25              
26             my $OSVERSIONINFO = pack "LLLLLa128",
27             ($dwOSVersionInfoSize, $dwMajorVersion, $dwMinorVersion,
28             $dwBuildNumber, $dwPlatformId, $szCSDVersion);
29              
30             return undef if $GetVersionEx->Call($OSVERSIONINFO) == 0;
31             ($dwOSVersionInfoSize, $dwMajorVersion, $dwMinorVersion,
32             $dwBuildNumber, $dwPlatformId, $szCSDVersion) =
33             unpack "LLLLLa128", $OSVERSIONINFO;
34              
35             $szCSDVersion =~ s/\0.*$//;
36             $szCSDVersion =~ s/^\s*(.*?)\s*$/$1/;
37             $dwBuildNumber = $dwBuildNumber & 0xffff if Win32::IsWin95();
38              
39             ($dwMajorVersion, $dwMinorVersion, $dwBuildNumber,
40             $dwPlatformId, $szCSDVersion);
41             }
42              
43             #==================
44             sub GetDiskFreeSpace ($) {
45             #==================
46             my $drive = shift;
47             return undef unless $drive =~ s/^([a-z])(:(\\)?)?$/$1:\\/i;
48              
49             $GetDiskFreeSpace ||=
50             new Win32::API("kernel32", "GetDiskFreeSpace", ['P','P','P','P','P'], 'N') or return;
51              
52             my ($lpRootPathName, $lpSectorsPerCluster, $lpBytesPerSector,
53             $lpNumberOfFreeClusters, $lpTotalNumberOfClusters) =
54             ($drive, DWORD_NULL, DWORD_NULL, DWORD_NULL, DWORD_NULL);
55              
56             return undef if $GetDiskFreeSpace->Call(
57             $lpRootPathName, $lpSectorsPerCluster, $lpBytesPerSector,
58             $lpNumberOfFreeClusters, $lpTotalNumberOfClusters
59             ) == 0;
60              
61             ($lpSectorsPerCluster, $lpBytesPerSector,
62             $lpNumberOfFreeClusters, $lpTotalNumberOfClusters) =
63             (unpack ("L",$lpSectorsPerCluster),
64             unpack ("L",$lpBytesPerSector),
65             unpack ("L",$lpNumberOfFreeClusters),
66             unpack ("L",$lpTotalNumberOfClusters));
67              
68             ($lpSectorsPerCluster, $lpBytesPerSector,
69             $lpNumberOfFreeClusters, $lpTotalNumberOfClusters);
70             }
71              
72             #==================
73             sub GetDiskFreeSpaceEx ($) {
74             #==================
75             my $drive = shift;
76             return undef unless $drive =~ s/^([a-z])(:(\\)?)?$/$1:\\/i ||
77             $drive =~ s/^(\\\\\w+\\\w+\$?)(\\)?$/$1\\/;
78              
79             $GetDiskFreeSpaceEx ||=
80             new Win32::API("kernel32", "GetDiskFreeSpaceEx", ['P','P','P','P'], 'N') or return;
81              
82             my ($lpDirectoryName, $lpFreeBytesAvailableToCaller,
83             $lpTotalNumberOfBytes, $lpTotalNumberOfFreeBytes) =
84             ($drive, "\0"x8, "\0"x8, "\0"x8);
85              
86             return undef if $GetDiskFreeSpaceEx->Call(
87             $lpDirectoryName, $lpFreeBytesAvailableToCaller,
88             $lpTotalNumberOfBytes, $lpTotalNumberOfFreeBytes
89             ) == 0;
90              
91             ($lpFreeBytesAvailableToCaller,
92             $lpTotalNumberOfBytes,
93             $lpTotalNumberOfFreeBytes) =
94             (unpack_LARGE_INTEGER ($lpFreeBytesAvailableToCaller),
95             unpack_LARGE_INTEGER ($lpTotalNumberOfBytes),
96             unpack_LARGE_INTEGER ($lpTotalNumberOfFreeBytes));
97              
98             ($lpFreeBytesAvailableToCaller, $lpTotalNumberOfBytes,
99             $lpTotalNumberOfFreeBytes);
100             }
101              
102             #==========================
103             sub unpack_LARGE_INTEGER ($) {
104             my ($b, $a) = unpack "LL", shift;
105             $a*2**32+$b;
106             }
107              
108             #==================
109             sub DriveType ($) {
110             #==================
111             my $drive = shift;
112             return undef unless $drive =~ s/^([a-z])(:(\\)?)?$/$1:\\/i ||
113             $drive =~ s/^(\\\\\w+\\\w+\$?)(\\)?$/$1\\/;
114              
115             $GetDriveType ||= new Win32::API("kernel32", "GetDriveType", ['P'], 'N') or return;
116              
117             my ($lpDirectoryName) = $drive;
118              
119             my $type = $GetDriveType->Call( $lpDirectoryName );
120             }
121              
122             #==================
123             sub DriveSpace ($) {
124             #==================
125             my $drive = shift;
126             return undef unless $drive =~ s/^([a-z])(:(\\)?)?$/$1:\\/i ||
127             $drive =~ s/^(\\\\\w+\\\w+\$?)(\\)?$/$1\\/;
128              
129             my ($MajorVersion, $MinorVersion, $BuildNumber, $PlatformId, $BuildStr) = GetVersionEx();
130             my ($FreeBytesAvailableToCaller, $TotalNumberOfBytes, $TotalNumberOfFreeBytes);
131              
132             my ($SectorsPerCluster, $BytesPerSector,
133             $NumberOfFreeClusters, $TotalNumberOfClusters) = GetDiskFreeSpace($drive);
134              
135             # return undef if ! defined $BytesPerSector;
136              
137             if (Win32::IsWinNT() || $MajorVersion > 4 ||
138             $MinorVersion > 0 || $BuildNumber > 1000) {
139             ($FreeBytesAvailableToCaller,
140             $TotalNumberOfBytes,
141             $TotalNumberOfFreeBytes) = GetDiskFreeSpaceEx($drive);
142              
143             } elsif (defined $BytesPerSector) {
144             ($FreeBytesAvailableToCaller,
145             $TotalNumberOfBytes,
146             $TotalNumberOfFreeBytes) = (
147             $SectorsPerCluster * $BytesPerSector * $NumberOfFreeClusters,
148             $SectorsPerCluster * $BytesPerSector * $TotalNumberOfClusters,
149             $SectorsPerCluster * $BytesPerSector * $NumberOfFreeClusters );
150             }
151              
152             ($SectorsPerCluster, $BytesPerSector,
153             $NumberOfFreeClusters, $TotalNumberOfClusters,
154             $FreeBytesAvailableToCaller, $TotalNumberOfBytes,
155             $TotalNumberOfFreeBytes);
156             }
157              
158             #===========================
159             sub DrivesInUse () {
160             #===========================
161             my (@dr, $i);
162             $GetLogicalDrives ||= new Win32::API("kernel32", "GetLogicalDrives", [], 'N') or return;
163              
164             my $bitmask = $GetLogicalDrives->Call;
165             for $i(0..25) {
166             push (@dr, chr(ord("A")+$i)) if $bitmask & 2**$i;
167             }
168             @dr;
169             }
170              
171             #===========================
172             sub FreeDriveLetters () {
173             #===========================
174             my (@dr, $i);
175             $GetLogicalDrives ||= new Win32::API("kernel32", "GetLogicalDrives", [], 'N') or return;
176              
177             my $bitmask = $GetLogicalDrives->Call;
178             for $i(0..25) {
179             push (@dr, (A..Z)[$i]) unless $bitmask & 2**$i;
180             }
181             @dr;
182             }
183              
184             #==================
185             sub IsReady ($) {
186             #==================
187             my $drive = shift;
188             return undef unless $drive =~ s/^([a-z])(:(\\)?)?$/$1:\\/i ||
189             $drive =~ s/^(\\\\\w+\\\w+\$?)(\\)?$/$1\\/;
190             my $dir = cwd;
191             my $rc = chdir $drive;
192             chdir $dir;
193             $rc;
194             }
195              
196             #==================
197             sub VolumeInfo ($) {
198             #==================
199             my $drive = shift;
200             return undef unless $drive =~ s/^([a-z])(:(\\)?)?$/$1:\\/i;
201              
202             $GetVolumeInformation ||=
203             new Win32::API("kernel32", "GetVolumeInformation", ['P','P','N','P','P','P','P','N'], 'N') or return;
204              
205             my ($lpRootPathName, $lpVolumeNameBuffer, $nVolumeNameSize,
206             $lpVolumeSerialNumber, $lpMaximumComponentLength, $lpFileSystemFlags,
207             $lpFileSystemNameBuffer, $nFileSystemNameSize) =
208             ($drive, "\0"x256, 256, DWORD_NULL, DWORD_NULL, DWORD_NULL, "\0"x256, 256);
209              
210             return undef if $GetVolumeInformation->Call(
211             $lpRootPathName, $lpVolumeNameBuffer, $nVolumeNameSize,
212             $lpVolumeSerialNumber, $lpMaximumComponentLength, $lpFileSystemFlags,
213             $lpFileSystemNameBuffer, $nFileSystemNameSize
214             ) == 0;
215              
216             ($lpVolumeSerialNumber, $lpMaximumComponentLength, $lpFileSystemFlags) =
217             (unpack ("L",$lpVolumeSerialNumber),
218             unpack ("L",$lpMaximumComponentLength),
219             unpack ("L",$lpFileSystemFlags));
220              
221             $lpVolumeNameBuffer =~ s/\0.*$//;
222             $lpFileSystemNameBuffer =~ s/\0.*$//;
223              
224             if ($lpVolumeSerialNumber) {
225             $lpVolumeSerialNumber = uc sprintf "%08x", $lpVolumeSerialNumber;
226             $lpVolumeSerialNumber =~ s/(....)(....)/$1:$2/;
227             } else {
228             $lpVolumeSerialNumber = "";
229             }
230              
231             my @attr;
232             if ($lpFileSystemFlags & FS_CASE_IS_PRESERVED () ) { push @attr, 1 }
233             if ($lpFileSystemFlags & FS_CASE_SENSITIVE () ) { push @attr, 2 }
234             if ($lpFileSystemFlags & FS_UNICODE_STORED_ON_DISK () ) { push @attr, 3 }
235             if ($lpFileSystemFlags & FS_PERSISTENT_ACLS () ) { push @attr, 4 }
236             if ($lpFileSystemFlags & FS_VOL_IS_COMPRESSED () ) { push @attr, 5 }
237             if ($lpFileSystemFlags & FS_FILE_COMPRESSION () ) { push @attr, 6 }
238              
239              
240             ($lpVolumeNameBuffer, $lpVolumeSerialNumber,
241             $lpMaximumComponentLength, $lpFileSystemNameBuffer, @attr);
242             }
243              
244             sub FS_CASE_IS_PRESERVED { 0x00000002 }
245             sub FS_CASE_SENSITIVE { 0x00000001 }
246             sub FS_UNICODE_STORED_ON_DISK { 0x00000004 }
247             sub FS_PERSISTENT_ACLS { 0x00000008 }
248             sub FS_VOL_IS_COMPRESSED { 0x00008000 }
249             sub FS_FILE_COMPRESSION { 0x00000010 }
250              
251              
252             1;
253              
254             __END__