Added GetDiskFreeSpaceEx().
[reactos.git] / reactos / lib / kernel32 / file / volume.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/file/volume.c
5 * PURPOSE: File volume functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Erik Bos, Alexandre Julliard :
8 * DRIVE_IsValid, GetLogicalDriveStringsA,
9 * GetLogicalDriveStringsW, GetLogicalDrives
10 * UPDATE HISTORY:
11 * Created 01/11/98
12 */
13 //WINE copyright notice:
14 /*
15 * DOS drives handling functions
16 *
17 * Copyright 1993 Erik Bos
18 * Copyright 1996 Alexandre Julliard
19 */
20
21 #include <windows.h>
22 #include <ddk/ntddk.h>
23 #include <wchar.h>
24 #include <string.h>
25
26 #define NDEBUG
27 #include <kernel32/kernel32.h>
28
29
30 #define MAX_DOS_DRIVES 26
31
32
33 int DRIVE_IsValid( int drive )
34 {
35 char Drives[4];
36 Drives[0] = 'A';
37 Drives[1] = ':';
38 Drives[2] = '\\';
39 Drives[3] = 0;
40
41 Drives[0] = 'A' + drive -1;
42 if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
43 if ( CreateFileA(Drives,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS|FILE_ATTRIBUTE_DIRECTORY,NULL) == INVALID_HANDLE_VALUE ) {
44 return 0;
45 }
46 return drive;
47
48 }
49
50
51 DWORD
52 STDCALL
53 GetLogicalDriveStringsA(
54 DWORD nBufferLength,
55 LPSTR lpBuffer
56 )
57 {
58 int drive, count;
59
60 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
61 if (DRIVE_IsValid(drive)) count++;
62 if (count * 4 * sizeof(char) <= nBufferLength)
63 {
64 LPSTR p = lpBuffer;
65 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
66 if (DRIVE_IsValid(drive))
67 {
68 *p++ = 'A' + drive;
69 *p++ = ':';
70 *p++ = '\\';
71 *p++ = '\0';
72 }
73 *p = '\0';
74 }
75 return count * 4 * sizeof(char);
76 }
77
78
79 DWORD
80 STDCALL
81 GetLogicalDriveStringsW(
82 DWORD nBufferLength,
83 LPWSTR lpBuffer
84 )
85 {
86 int drive, count;
87
88 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
89 if (DRIVE_IsValid(drive)) count++;
90 if (count * 4 * sizeof(WCHAR) <= nBufferLength)
91 {
92 LPWSTR p = lpBuffer;
93 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
94 if (DRIVE_IsValid(drive))
95 {
96 *p++ = (WCHAR)('A' + drive);
97 *p++ = (WCHAR)':';
98 *p++ = (WCHAR)'\\';
99 *p++ = (WCHAR)'\0';
100 }
101 *p = (WCHAR)'\0';
102 }
103 return count * 4 * sizeof(WCHAR);
104 }
105
106
107 DWORD
108 STDCALL
109 GetLogicalDrives(VOID)
110 {
111 DWORD ret = 0;
112 int drive;
113
114 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
115 if (DRIVE_IsValid(drive)) ret |= (1 << drive);
116 return ret;
117 }
118
119
120
121 WINBOOL
122 STDCALL
123 GetDiskFreeSpaceA(
124 LPCSTR lpRootPathName,
125 LPDWORD lpSectorsPerCluster,
126 LPDWORD lpBytesPerSector,
127 LPDWORD lpNumberOfFreeClusters,
128 LPDWORD lpTotalNumberOfClusters
129 )
130 {
131 ULONG i;
132 WCHAR RootPathNameW[MAX_PATH];
133 i = 0;
134 while ((*lpRootPathName)!=0 && i < MAX_PATH)
135 {
136 RootPathNameW[i] = *lpRootPathName;
137 lpRootPathName++;
138 i++;
139 }
140 RootPathNameW[i] = 0;
141 return GetDiskFreeSpaceW(RootPathNameW,lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters );
142 }
143
144 WINBOOL
145 STDCALL
146 GetDiskFreeSpaceW(
147 LPCWSTR lpRootPathName,
148 LPDWORD lpSectorsPerCluster,
149 LPDWORD lpBytesPerSector,
150 LPDWORD lpNumberOfFreeClusters,
151 LPDWORD lpTotalNumberOfClusters
152 )
153 {
154 FILE_FS_SIZE_INFORMATION FileFsSize;
155 IO_STATUS_BLOCK IoStatusBlock;
156 HANDLE hFile;
157 NTSTATUS errCode;
158
159 hFile = CreateFileW(lpRootPathName,
160 FILE_READ_ATTRIBUTES,
161 FILE_SHARE_READ,
162 NULL,
163 OPEN_EXISTING,
164 FILE_ATTRIBUTE_NORMAL,
165 NULL);
166
167 errCode = NtQueryVolumeInformationFile(hFile,
168 &IoStatusBlock,
169 &FileFsSize,
170 sizeof(FILE_FS_SIZE_INFORMATION),
171 FileFsSizeInformation);
172 if (!NT_SUCCESS(errCode))
173 {
174 CloseHandle(hFile);
175 SetLastError(RtlNtStatusToDosError(errCode));
176 return FALSE;
177 }
178
179 *lpBytesPerSector = FileFsSize.BytesPerSector;
180 *lpSectorsPerCluster = FileFsSize.SectorsPerAllocationUnit;
181 *lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.LowPart;
182 *lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.LowPart;
183 CloseHandle(hFile);
184 return TRUE;
185 }
186
187 WINBOOL
188 STDCALL
189 GetDiskFreeSpaceExA(
190 LPCSTR lpDirectoryName,
191 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
192 PULARGE_INTEGER lpTotalNumberOfBytes,
193 PULARGE_INTEGER lpTotalNumberOfFreeBytes
194 )
195 {
196 WCHAR DirectoryNameW[MAX_PATH];
197 ULONG i;
198
199 i = 0;
200 while ((*lpDirectoryName)!=0 && i < MAX_PATH)
201 {
202 DirectoryNameW[i] = *lpDirectoryName;
203 lpDirectoryName++;
204 i++;
205 }
206 DirectoryNameW[i] = 0;
207 return GetDiskFreeSpaceExW(DirectoryNameW,
208 lpFreeBytesAvailableToCaller,
209 lpTotalNumberOfBytes,
210 lpTotalNumberOfFreeBytes);
211 }
212
213
214 WINBOOL
215 STDCALL
216 GetDiskFreeSpaceExW(
217 LPCWSTR lpDirectoryName,
218 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
219 PULARGE_INTEGER lpTotalNumberOfBytes,
220 PULARGE_INTEGER lpTotalNumberOfFreeBytes
221 )
222 {
223 FILE_FS_SIZE_INFORMATION FileFsSize;
224 IO_STATUS_BLOCK IoStatusBlock;
225 HANDLE hFile;
226 NTSTATUS errCode;
227 WCHAR RootPath[4];
228 ULARGE_INTEGER BytesPerCluster;
229
230 wcsncpy (RootPath, lpDirectoryName, 3);
231
232 hFile = CreateFileW(RootPath,
233 FILE_READ_ATTRIBUTES,
234 FILE_SHARE_READ,
235 NULL,
236 OPEN_EXISTING,
237 FILE_ATTRIBUTE_NORMAL,
238 NULL);
239
240 errCode = NtQueryVolumeInformationFile(hFile,
241 &IoStatusBlock,
242 &FileFsSize,
243 sizeof(FILE_FS_SIZE_INFORMATION),
244 FileFsSizeInformation);
245 if (!NT_SUCCESS(errCode))
246 {
247 CloseHandle(hFile);
248 SetLastError(RtlNtStatusToDosError(errCode));
249 return FALSE;
250 }
251
252 BytesPerCluster.QuadPart =
253 FileFsSize.BytesPerSector * FileFsSize.SectorsPerAllocationUnit;
254
255 // FIXME: Use quota information
256 lpFreeBytesAvailableToCaller->QuadPart =
257 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
258
259 lpTotalNumberOfBytes->QuadPart =
260 BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.LowPart;
261 lpTotalNumberOfFreeBytes->QuadPart =
262 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
263
264 CloseHandle(hFile);
265 return TRUE;
266 }
267
268
269 UINT
270 STDCALL
271 GetDriveTypeA(
272 LPCSTR lpRootPathName
273 )
274 {
275 ULONG i;
276 WCHAR RootPathNameW[MAX_PATH];
277 i = 0;
278 while ((*lpRootPathName)!=0 && i < MAX_PATH)
279 {
280 RootPathNameW[i] = *lpRootPathName;
281 lpRootPathName++;
282 i++;
283 }
284 RootPathNameW[i] = 0;
285 return GetDriveTypeW(RootPathNameW);
286 }
287
288 UINT
289 STDCALL
290 GetDriveTypeW(
291 LPCWSTR lpRootPathName
292 )
293 {
294 FILE_FS_DEVICE_INFORMATION FileFsDevice;
295 IO_STATUS_BLOCK IoStatusBlock;
296
297 HANDLE hFile;
298 NTSTATUS errCode;
299
300 hFile = CreateFileW(
301 lpRootPathName,
302 GENERIC_ALL,
303 FILE_SHARE_READ|FILE_SHARE_WRITE,
304 NULL,
305 OPEN_EXISTING,
306 FILE_ATTRIBUTE_NORMAL,
307 NULL
308 );
309
310 errCode = NtQueryVolumeInformationFile(hFile,&IoStatusBlock,&FileFsDevice, sizeof(FILE_FS_DEVICE_INFORMATION),FileFsDeviceInformation);
311 if ( !NT_SUCCESS(errCode) ) {
312 CloseHandle(hFile);
313 SetLastError(RtlNtStatusToDosError(errCode));
314 return 0;
315 }
316 CloseHandle(hFile);
317 return (UINT)FileFsDevice.DeviceType;
318
319
320
321 }
322
323 WINBOOL
324 STDCALL
325 GetVolumeInformationA(
326 LPCSTR lpRootPathName,
327 LPSTR lpVolumeNameBuffer,
328 DWORD nVolumeNameSize,
329 LPDWORD lpVolumeSerialNumber,
330 LPDWORD lpMaximumComponentLength,
331 LPDWORD lpFileSystemFlags,
332 LPSTR lpFileSystemNameBuffer,
333 DWORD nFileSystemNameSize
334 )
335 {
336 ULONG i;
337 WCHAR RootPathNameW[MAX_PATH];
338 WCHAR VolumeNameBufferW[MAX_PATH];
339 WCHAR FileSystemNameBufferW[MAX_PATH];
340
341
342 i = 0;
343 while ((*lpRootPathName)!=0 && i < MAX_PATH)
344 {
345 RootPathNameW[i] = *lpRootPathName;
346 lpRootPathName++;
347 i++;
348 }
349 RootPathNameW[i] = 0;
350
351 if ( GetVolumeInformationW(RootPathNameW,
352 VolumeNameBufferW,
353 nVolumeNameSize,
354 lpVolumeSerialNumber,
355 lpMaximumComponentLength,
356 lpFileSystemFlags,
357 FileSystemNameBufferW,
358 nFileSystemNameSize ) ) {
359 for(i=0;i<nVolumeNameSize;i++)
360 lpVolumeNameBuffer[i] = (CHAR)VolumeNameBufferW[i];
361
362 for(i=0;i<nFileSystemNameSize;i++)
363 lpFileSystemNameBuffer[i] = (CHAR)FileSystemNameBufferW[i];
364
365 return TRUE;
366 }
367 return FALSE;
368
369 }
370
371
372
373
374 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_VOLUME_INFORMATION))
375
376 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
377
378
379 WINBOOL
380 STDCALL
381 GetVolumeInformationW(
382 LPCWSTR lpRootPathName,
383 LPWSTR lpVolumeNameBuffer,
384 DWORD nVolumeNameSize,
385 LPDWORD lpVolumeSerialNumber,
386 LPDWORD lpMaximumComponentLength,
387 LPDWORD lpFileSystemFlags,
388 LPWSTR lpFileSystemNameBuffer,
389 DWORD nFileSystemNameSize
390 )
391 {
392 PFILE_FS_VOLUME_INFORMATION FileFsVolume;
393 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
394 IO_STATUS_BLOCK IoStatusBlock;
395 USHORT Buffer[FS_VOLUME_BUFFER_SIZE];
396 USHORT Buffer2[FS_ATTRIBUTE_BUFFER_SIZE];
397
398 HANDLE hFile;
399 NTSTATUS errCode;
400
401 FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
402 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer2;
403
404 DPRINT("FileFsVolume %p\n", FileFsVolume);
405 DPRINT("FileFsAttribute %p\n", FileFsAttribute);
406
407 hFile = CreateFileW(lpRootPathName,
408 FILE_READ_ATTRIBUTES,
409 FILE_SHARE_READ|FILE_SHARE_WRITE,
410 NULL,
411 OPEN_EXISTING,
412 FILE_ATTRIBUTE_NORMAL,
413 NULL);
414
415 DPRINT("hFile: %x\n", hFile);
416 errCode = NtQueryVolumeInformationFile(hFile,
417 &IoStatusBlock,
418 FileFsVolume,
419 FS_VOLUME_BUFFER_SIZE,
420 FileFsVolumeInformation);
421 if ( !NT_SUCCESS(errCode) ) {
422 DPRINT("Status: %x\n", errCode);
423 CloseHandle(hFile);
424 SetLastError(RtlNtStatusToDosError(errCode));
425 return FALSE;
426 }
427
428 if (lpVolumeSerialNumber)
429 *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
430
431 if (lpVolumeNameBuffer)
432 wcsncpy(lpVolumeNameBuffer, FileFsVolume->VolumeLabel,min(nVolumeNameSize,MAX_PATH));
433
434 errCode = NtQueryVolumeInformationFile(hFile,&IoStatusBlock,FileFsAttribute, FS_ATTRIBUTE_BUFFER_SIZE,FileFsAttributeInformation);
435 if ( !NT_SUCCESS(errCode) ) {
436 DPRINT("Status: %x\n", errCode);
437 CloseHandle(hFile);
438 SetLastError(RtlNtStatusToDosError(errCode));
439 return FALSE;
440 }
441
442 if (lpFileSystemFlags)
443 *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
444 if (lpMaximumComponentLength)
445 *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
446 if (lpFileSystemNameBuffer)
447 wcsncpy(lpFileSystemNameBuffer, FileFsAttribute->FileSystemName,min(nFileSystemNameSize,MAX_PATH));
448
449 CloseHandle(hFile);
450 return TRUE;
451 }
452
453 WINBOOL
454 STDCALL
455 SetVolumeLabelA(
456 LPCSTR lpRootPathName,
457 LPCSTR lpVolumeName
458 )
459 {
460 WCHAR RootPathNameW[MAX_PATH];
461 WCHAR VolumeNameW[MAX_PATH];
462 UINT i;
463
464 i = 0;
465 while ((*lpRootPathName)!=0 && i < MAX_PATH)
466 {
467 RootPathNameW[i] = *lpRootPathName;
468 lpRootPathName++;
469 i++;
470 }
471 RootPathNameW[i] = 0;
472
473 i = 0;
474 while ((*lpVolumeName)!=0 && i < MAX_PATH)
475 {
476 VolumeNameW[i] = *lpVolumeName;
477 lpVolumeName++;
478 i++;
479 }
480 VolumeNameW[i] = 0;
481 return SetVolumeLabelW(RootPathNameW,VolumeNameW);
482 }
483
484 WINBOOL
485 STDCALL
486 SetVolumeLabelW(
487 LPCWSTR lpRootPathName,
488 LPCWSTR lpVolumeName
489 )
490 {
491 return FALSE;
492 }