Fixed header inclusion order.
[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 <ddk/ntddk.h>
22 #include <windows.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 WCHAR RootPathNameW[MAX_PATH];
132
133 if (lpRootPathName)
134 {
135 ULONG i = 0;
136 while ((*lpRootPathName)!=0 && i < MAX_PATH)
137 {
138 RootPathNameW[i] = *lpRootPathName;
139 lpRootPathName++;
140 i++;
141 }
142 RootPathNameW[i] = 0;
143 }
144
145 return GetDiskFreeSpaceW(lpRootPathName?RootPathNameW:NULL,
146 lpSectorsPerCluster,
147 lpBytesPerSector,
148 lpNumberOfFreeClusters,
149 lpTotalNumberOfClusters);
150 }
151
152 WINBOOL
153 STDCALL
154 GetDiskFreeSpaceW(
155 LPCWSTR lpRootPathName,
156 LPDWORD lpSectorsPerCluster,
157 LPDWORD lpBytesPerSector,
158 LPDWORD lpNumberOfFreeClusters,
159 LPDWORD lpTotalNumberOfClusters
160 )
161 {
162 FILE_FS_SIZE_INFORMATION FileFsSize;
163 IO_STATUS_BLOCK IoStatusBlock;
164 WCHAR RootPathName[MAX_PATH];
165 HANDLE hFile;
166 NTSTATUS errCode;
167
168 if (lpRootPathName)
169 {
170 wcsncpy (RootPathName, lpRootPathName, 3);
171 }
172 else
173 {
174 GetCurrentDirectoryW (MAX_PATH, RootPathName);
175 RootPathName[3] = 0;
176 }
177
178 hFile = CreateFileW(RootPathName,
179 FILE_READ_ATTRIBUTES,
180 FILE_SHARE_READ,
181 NULL,
182 OPEN_EXISTING,
183 FILE_ATTRIBUTE_NORMAL,
184 NULL);
185
186 errCode = NtQueryVolumeInformationFile(hFile,
187 &IoStatusBlock,
188 &FileFsSize,
189 sizeof(FILE_FS_SIZE_INFORMATION),
190 FileFsSizeInformation);
191 if (!NT_SUCCESS(errCode))
192 {
193 CloseHandle(hFile);
194 SetLastError(RtlNtStatusToDosError(errCode));
195 return FALSE;
196 }
197
198 *lpBytesPerSector = FileFsSize.BytesPerSector;
199 *lpSectorsPerCluster = FileFsSize.SectorsPerAllocationUnit;
200 *lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.u.LowPart;
201 *lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.u.LowPart;
202 CloseHandle(hFile);
203 return TRUE;
204 }
205
206 WINBOOL
207 STDCALL
208 GetDiskFreeSpaceExA(
209 LPCSTR lpDirectoryName,
210 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
211 PULARGE_INTEGER lpTotalNumberOfBytes,
212 PULARGE_INTEGER lpTotalNumberOfFreeBytes
213 )
214 {
215 WCHAR DirectoryNameW[MAX_PATH];
216
217 if (lpDirectoryName)
218 {
219 ULONG i = 0;
220 while ((*lpDirectoryName)!=0 && i < MAX_PATH)
221 {
222 DirectoryNameW[i] = *lpDirectoryName;
223 lpDirectoryName++;
224 i++;
225 }
226 DirectoryNameW[i] = 0;
227 }
228
229 return GetDiskFreeSpaceExW(lpDirectoryName?DirectoryNameW:NULL,
230 lpFreeBytesAvailableToCaller,
231 lpTotalNumberOfBytes,
232 lpTotalNumberOfFreeBytes);
233 }
234
235
236 WINBOOL
237 STDCALL
238 GetDiskFreeSpaceExW(
239 LPCWSTR lpDirectoryName,
240 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
241 PULARGE_INTEGER lpTotalNumberOfBytes,
242 PULARGE_INTEGER lpTotalNumberOfFreeBytes
243 )
244 {
245 FILE_FS_SIZE_INFORMATION FileFsSize;
246 IO_STATUS_BLOCK IoStatusBlock;
247 ULARGE_INTEGER BytesPerCluster;
248 WCHAR RootPathName[MAX_PATH];
249 HANDLE hFile;
250 NTSTATUS errCode;
251
252 if (lpDirectoryName)
253 {
254 wcsncpy (RootPathName, lpDirectoryName, 3);
255 }
256 else
257 {
258 GetCurrentDirectoryW (MAX_PATH, RootPathName);
259 RootPathName[3] = 0;
260 }
261
262 hFile = CreateFileW(RootPathName,
263 FILE_READ_ATTRIBUTES,
264 FILE_SHARE_READ,
265 NULL,
266 OPEN_EXISTING,
267 FILE_ATTRIBUTE_NORMAL,
268 NULL);
269
270 errCode = NtQueryVolumeInformationFile(hFile,
271 &IoStatusBlock,
272 &FileFsSize,
273 sizeof(FILE_FS_SIZE_INFORMATION),
274 FileFsSizeInformation);
275 if (!NT_SUCCESS(errCode))
276 {
277 CloseHandle(hFile);
278 SetLastError(RtlNtStatusToDosError(errCode));
279 return FALSE;
280 }
281
282 BytesPerCluster.QuadPart =
283 FileFsSize.BytesPerSector * FileFsSize.SectorsPerAllocationUnit;
284
285 // FIXME: Use quota information
286 lpFreeBytesAvailableToCaller->QuadPart =
287 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
288
289 lpTotalNumberOfBytes->QuadPart =
290 BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.QuadPart;
291 lpTotalNumberOfFreeBytes->QuadPart =
292 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
293
294 CloseHandle(hFile);
295 return TRUE;
296 }
297
298
299 UINT
300 STDCALL
301 GetDriveTypeA(
302 LPCSTR lpRootPathName
303 )
304 {
305 ULONG i;
306 WCHAR RootPathNameW[MAX_PATH];
307 i = 0;
308 while ((*lpRootPathName)!=0 && i < MAX_PATH)
309 {
310 RootPathNameW[i] = *lpRootPathName;
311 lpRootPathName++;
312 i++;
313 }
314 RootPathNameW[i] = 0;
315 return GetDriveTypeW(RootPathNameW);
316 }
317
318 UINT
319 STDCALL
320 GetDriveTypeW(
321 LPCWSTR lpRootPathName
322 )
323 {
324 FILE_FS_DEVICE_INFORMATION FileFsDevice;
325 IO_STATUS_BLOCK IoStatusBlock;
326
327 HANDLE hFile;
328 NTSTATUS errCode;
329
330 hFile = CreateFileW(
331 lpRootPathName,
332 GENERIC_ALL,
333 FILE_SHARE_READ|FILE_SHARE_WRITE,
334 NULL,
335 OPEN_EXISTING,
336 FILE_ATTRIBUTE_NORMAL,
337 NULL
338 );
339
340 errCode = NtQueryVolumeInformationFile(hFile,&IoStatusBlock,&FileFsDevice, sizeof(FILE_FS_DEVICE_INFORMATION),FileFsDeviceInformation);
341 if ( !NT_SUCCESS(errCode) ) {
342 CloseHandle(hFile);
343 SetLastError(RtlNtStatusToDosError(errCode));
344 return 0;
345 }
346 CloseHandle(hFile);
347 return (UINT)FileFsDevice.DeviceType;
348
349
350
351 }
352
353 WINBOOL
354 STDCALL
355 GetVolumeInformationA(
356 LPCSTR lpRootPathName,
357 LPSTR lpVolumeNameBuffer,
358 DWORD nVolumeNameSize,
359 LPDWORD lpVolumeSerialNumber,
360 LPDWORD lpMaximumComponentLength,
361 LPDWORD lpFileSystemFlags,
362 LPSTR lpFileSystemNameBuffer,
363 DWORD nFileSystemNameSize
364 )
365 {
366 ULONG i;
367 WCHAR RootPathNameW[MAX_PATH];
368 WCHAR VolumeNameBufferW[MAX_PATH];
369 WCHAR FileSystemNameBufferW[MAX_PATH];
370
371
372 i = 0;
373 while ((*lpRootPathName)!=0 && i < MAX_PATH)
374 {
375 RootPathNameW[i] = *lpRootPathName;
376 lpRootPathName++;
377 i++;
378 }
379 RootPathNameW[i] = 0;
380
381 if ( GetVolumeInformationW(RootPathNameW,
382 VolumeNameBufferW,
383 nVolumeNameSize,
384 lpVolumeSerialNumber,
385 lpMaximumComponentLength,
386 lpFileSystemFlags,
387 FileSystemNameBufferW,
388 nFileSystemNameSize ) ) {
389 for(i=0;i<nVolumeNameSize;i++)
390 lpVolumeNameBuffer[i] = (CHAR)VolumeNameBufferW[i];
391
392 for(i=0;i<nFileSystemNameSize;i++)
393 lpFileSystemNameBuffer[i] = (CHAR)FileSystemNameBufferW[i];
394
395 return TRUE;
396 }
397 return FALSE;
398
399 }
400
401
402
403
404 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_VOLUME_INFORMATION))
405
406 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
407
408
409 WINBOOL
410 STDCALL
411 GetVolumeInformationW(
412 LPCWSTR lpRootPathName,
413 LPWSTR lpVolumeNameBuffer,
414 DWORD nVolumeNameSize,
415 LPDWORD lpVolumeSerialNumber,
416 LPDWORD lpMaximumComponentLength,
417 LPDWORD lpFileSystemFlags,
418 LPWSTR lpFileSystemNameBuffer,
419 DWORD nFileSystemNameSize
420 )
421 {
422 PFILE_FS_VOLUME_INFORMATION FileFsVolume;
423 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
424 IO_STATUS_BLOCK IoStatusBlock;
425 USHORT Buffer[FS_VOLUME_BUFFER_SIZE];
426 USHORT Buffer2[FS_ATTRIBUTE_BUFFER_SIZE];
427
428 HANDLE hFile;
429 NTSTATUS errCode;
430
431 FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
432 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer2;
433
434 DPRINT("FileFsVolume %p\n", FileFsVolume);
435 DPRINT("FileFsAttribute %p\n", FileFsAttribute);
436
437 hFile = CreateFileW(lpRootPathName,
438 FILE_READ_ATTRIBUTES,
439 FILE_SHARE_READ|FILE_SHARE_WRITE,
440 NULL,
441 OPEN_EXISTING,
442 FILE_ATTRIBUTE_NORMAL,
443 NULL);
444
445 DPRINT("hFile: %x\n", hFile);
446 errCode = NtQueryVolumeInformationFile(hFile,
447 &IoStatusBlock,
448 FileFsVolume,
449 FS_VOLUME_BUFFER_SIZE,
450 FileFsVolumeInformation);
451 if ( !NT_SUCCESS(errCode) ) {
452 DPRINT("Status: %x\n", errCode);
453 CloseHandle(hFile);
454 SetLastError(RtlNtStatusToDosError(errCode));
455 return FALSE;
456 }
457
458 if (lpVolumeSerialNumber)
459 *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
460
461 if (lpVolumeNameBuffer)
462 wcsncpy(lpVolumeNameBuffer, FileFsVolume->VolumeLabel,min(nVolumeNameSize,MAX_PATH));
463
464 errCode = NtQueryVolumeInformationFile(hFile,&IoStatusBlock,FileFsAttribute, FS_ATTRIBUTE_BUFFER_SIZE,FileFsAttributeInformation);
465 if ( !NT_SUCCESS(errCode) ) {
466 DPRINT("Status: %x\n", errCode);
467 CloseHandle(hFile);
468 SetLastError(RtlNtStatusToDosError(errCode));
469 return FALSE;
470 }
471
472 if (lpFileSystemFlags)
473 *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
474 if (lpMaximumComponentLength)
475 *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
476 if (lpFileSystemNameBuffer)
477 wcsncpy(lpFileSystemNameBuffer, FileFsAttribute->FileSystemName,min(nFileSystemNameSize,MAX_PATH));
478
479 CloseHandle(hFile);
480 return TRUE;
481 }
482
483 WINBOOL
484 STDCALL
485 SetVolumeLabelA(
486 LPCSTR lpRootPathName,
487 LPCSTR lpVolumeName
488 )
489 {
490 WCHAR RootPathNameW[MAX_PATH];
491 WCHAR VolumeNameW[MAX_PATH];
492 UINT i;
493
494 i = 0;
495 while ((*lpRootPathName)!=0 && i < MAX_PATH)
496 {
497 RootPathNameW[i] = *lpRootPathName;
498 lpRootPathName++;
499 i++;
500 }
501 RootPathNameW[i] = 0;
502
503 i = 0;
504 while ((*lpVolumeName)!=0 && i < MAX_PATH)
505 {
506 VolumeNameW[i] = *lpVolumeName;
507 lpVolumeName++;
508 i++;
509 }
510 VolumeNameW[i] = 0;
511 return SetVolumeLabelW(RootPathNameW,VolumeNameW);
512 }
513
514 WINBOOL
515 STDCALL
516 SetVolumeLabelW(
517 LPCWSTR lpRootPathName,
518 LPCWSTR lpVolumeName
519 )
520 {
521 return FALSE;
522 }