- Added a check for valid result pointers in GetDiskFreeSpaceExW.
[reactos.git] / reactos / lib / kernel32 / file / volume.c
1 /* $Id: volume.c,v 1.23 2002/08/18 21:07:59 hbirr Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/volume.c
6 * PURPOSE: File volume functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Erik Bos, Alexandre Julliard :
9 * GetLogicalDriveStringsA,
10 * GetLogicalDriveStringsW, GetLogicalDrives
11 * UPDATE HISTORY:
12 * Created 01/11/98
13 */
14 //WINE copyright notice:
15 /*
16 * DOS drives handling functions
17 *
18 * Copyright 1993 Erik Bos
19 * Copyright 1996 Alexandre Julliard
20 */
21
22 #include <ddk/ntddk.h>
23 #include <windows.h>
24 #include <ntos/minmax.h>
25
26 #define NDEBUG
27 #include <kernel32/kernel32.h>
28 #include <kernel32/error.h>
29
30
31 #define MAX_DOS_DRIVES 26
32
33
34 DWORD STDCALL
35 GetLogicalDriveStringsA(DWORD nBufferLength,
36 LPSTR lpBuffer)
37 {
38 DWORD drive, count;
39 DWORD dwDriveMap;
40
41 dwDriveMap = SharedUserData->DosDeviceMap;
42
43 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
44 {
45 if (dwDriveMap & (1<<drive))
46 count++;
47 }
48
49
50 if (count * 4 * sizeof(char) <= nBufferLength)
51 {
52 LPSTR p = lpBuffer;
53
54 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
55 if (dwDriveMap & (1<<drive))
56 {
57 *p++ = 'A' + drive;
58 *p++ = ':';
59 *p++ = '\\';
60 *p++ = '\0';
61 }
62 *p = '\0';
63 }
64 return (count * 4 * sizeof(char));
65 }
66
67
68 DWORD STDCALL
69 GetLogicalDriveStringsW(DWORD nBufferLength,
70 LPWSTR lpBuffer)
71 {
72 DWORD drive, count;
73 DWORD dwDriveMap;
74
75 dwDriveMap = SharedUserData->DosDeviceMap;
76
77 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
78 {
79 if (dwDriveMap & (1<<drive))
80 count++;
81 }
82
83 if (count * 4 * sizeof(WCHAR) <= nBufferLength)
84 {
85 LPWSTR p = lpBuffer;
86 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
87 if (dwDriveMap & (1<<drive))
88 {
89 *p++ = (WCHAR)('A' + drive);
90 *p++ = (WCHAR)':';
91 *p++ = (WCHAR)'\\';
92 *p++ = (WCHAR)'\0';
93 }
94 *p = (WCHAR)'\0';
95 }
96 return (count * 4 * sizeof(WCHAR));
97 }
98
99
100 DWORD STDCALL
101 GetLogicalDrives(VOID)
102 {
103 return(SharedUserData->DosDeviceMap);
104 }
105
106
107 WINBOOL STDCALL
108 GetDiskFreeSpaceA (
109 LPCSTR lpRootPathName,
110 LPDWORD lpSectorsPerCluster,
111 LPDWORD lpBytesPerSector,
112 LPDWORD lpNumberOfFreeClusters,
113 LPDWORD lpTotalNumberOfClusters
114 )
115 {
116 UNICODE_STRING RootPathNameU;
117 ANSI_STRING RootPathName;
118 WINBOOL Result;
119
120 RtlInitAnsiString (&RootPathName,
121 (LPSTR)lpRootPathName);
122
123 RtlInitUnicodeString (&RootPathNameU,
124 NULL);
125
126 if (lpRootPathName)
127 {
128 /* convert ansi (or oem) string to unicode */
129 if (bIsFileApiAnsi)
130 RtlAnsiStringToUnicodeString (&RootPathNameU,
131 &RootPathName,
132 TRUE);
133 else
134 RtlOemStringToUnicodeString (&RootPathNameU,
135 &RootPathName,
136 TRUE);
137 }
138
139 Result = GetDiskFreeSpaceW (RootPathNameU.Buffer,
140 lpSectorsPerCluster,
141 lpBytesPerSector,
142 lpNumberOfFreeClusters,
143 lpTotalNumberOfClusters);
144
145 if (lpRootPathName)
146 {
147 RtlFreeHeap (RtlGetProcessHeap (),
148 0,
149 RootPathNameU.Buffer);
150 }
151
152 return Result;
153 }
154
155
156 WINBOOL STDCALL
157 GetDiskFreeSpaceW(
158 LPCWSTR lpRootPathName,
159 LPDWORD lpSectorsPerCluster,
160 LPDWORD lpBytesPerSector,
161 LPDWORD lpNumberOfFreeClusters,
162 LPDWORD lpTotalNumberOfClusters
163 )
164 {
165 FILE_FS_SIZE_INFORMATION FileFsSize;
166 IO_STATUS_BLOCK IoStatusBlock;
167 WCHAR RootPathName[MAX_PATH];
168 HANDLE hFile;
169 NTSTATUS errCode;
170
171 if (lpRootPathName)
172 {
173 wcsncpy (RootPathName, lpRootPathName, 3);
174 }
175 else
176 {
177 GetCurrentDirectoryW (MAX_PATH, RootPathName);
178 RootPathName[3] = 0;
179 }
180
181 hFile = CreateFileW(RootPathName,
182 FILE_READ_ATTRIBUTES,
183 FILE_SHARE_READ,
184 NULL,
185 OPEN_EXISTING,
186 FILE_ATTRIBUTE_NORMAL,
187 NULL);
188
189 errCode = NtQueryVolumeInformationFile(hFile,
190 &IoStatusBlock,
191 &FileFsSize,
192 sizeof(FILE_FS_SIZE_INFORMATION),
193 FileFsSizeInformation);
194 if (!NT_SUCCESS(errCode))
195 {
196 CloseHandle(hFile);
197 SetLastErrorByStatus (errCode);
198 return FALSE;
199 }
200
201 *lpBytesPerSector = FileFsSize.BytesPerSector;
202 *lpSectorsPerCluster = FileFsSize.SectorsPerAllocationUnit;
203 *lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.u.LowPart;
204 *lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.u.LowPart;
205 CloseHandle(hFile);
206 return TRUE;
207 }
208
209
210 WINBOOL STDCALL
211 GetDiskFreeSpaceExA (
212 LPCSTR lpDirectoryName,
213 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
214 PULARGE_INTEGER lpTotalNumberOfBytes,
215 PULARGE_INTEGER lpTotalNumberOfFreeBytes
216 )
217 {
218 UNICODE_STRING DirectoryNameU;
219 ANSI_STRING DirectoryName;
220 WINBOOL Result;
221
222 RtlInitAnsiString (&DirectoryName,
223 (LPSTR)lpDirectoryName);
224
225 RtlInitUnicodeString (&DirectoryNameU,
226 NULL);
227
228 if (lpDirectoryName)
229 {
230 /* convert ansi (or oem) string to unicode */
231 if (bIsFileApiAnsi)
232 RtlAnsiStringToUnicodeString (&DirectoryNameU,
233 &DirectoryName,
234 TRUE);
235 else
236 RtlOemStringToUnicodeString (&DirectoryNameU,
237 &DirectoryName,
238 TRUE);
239 }
240
241 Result = GetDiskFreeSpaceExW (DirectoryNameU.Buffer,
242 lpFreeBytesAvailableToCaller,
243 lpTotalNumberOfBytes,
244 lpTotalNumberOfFreeBytes);
245
246 if (lpDirectoryName)
247 {
248 RtlFreeHeap (RtlGetProcessHeap (),
249 0,
250 DirectoryNameU.Buffer);
251 }
252
253 return Result;
254 }
255
256
257 WINBOOL STDCALL
258 GetDiskFreeSpaceExW(
259 LPCWSTR lpDirectoryName,
260 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
261 PULARGE_INTEGER lpTotalNumberOfBytes,
262 PULARGE_INTEGER lpTotalNumberOfFreeBytes
263 )
264 {
265 FILE_FS_SIZE_INFORMATION FileFsSize;
266 IO_STATUS_BLOCK IoStatusBlock;
267 ULARGE_INTEGER BytesPerCluster;
268 WCHAR RootPathName[MAX_PATH];
269 HANDLE hFile;
270 NTSTATUS errCode;
271
272 if (lpDirectoryName)
273 {
274 wcsncpy (RootPathName, lpDirectoryName, 3);
275 }
276 else
277 {
278 GetCurrentDirectoryW (MAX_PATH, RootPathName);
279 RootPathName[3] = 0;
280 }
281
282 hFile = CreateFileW(RootPathName,
283 FILE_READ_ATTRIBUTES,
284 FILE_SHARE_READ,
285 NULL,
286 OPEN_EXISTING,
287 FILE_ATTRIBUTE_NORMAL,
288 NULL);
289
290 errCode = NtQueryVolumeInformationFile(hFile,
291 &IoStatusBlock,
292 &FileFsSize,
293 sizeof(FILE_FS_SIZE_INFORMATION),
294 FileFsSizeInformation);
295 if (!NT_SUCCESS(errCode))
296 {
297 CloseHandle(hFile);
298 SetLastErrorByStatus (errCode);
299 return FALSE;
300 }
301
302 BytesPerCluster.QuadPart =
303 FileFsSize.BytesPerSector * FileFsSize.SectorsPerAllocationUnit;
304
305 // FIXME: Use quota information
306 if (lpFreeBytesAvailableToCaller)
307 lpFreeBytesAvailableToCaller->QuadPart =
308 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
309
310 if (lpTotalNumberOfBytes)
311 lpTotalNumberOfBytes->QuadPart =
312 BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.QuadPart;
313 if (lpTotalNumberOfFreeBytes)
314 lpTotalNumberOfFreeBytes->QuadPart =
315 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
316
317 CloseHandle(hFile);
318 return TRUE;
319 }
320
321
322 UINT STDCALL
323 GetDriveTypeA(LPCSTR lpRootPathName)
324 {
325 UNICODE_STRING RootPathNameU;
326 ANSI_STRING RootPathName;
327 UINT Result;
328
329 RtlInitAnsiString (&RootPathName,
330 (LPSTR)lpRootPathName);
331
332 /* convert ansi (or oem) string to unicode */
333 if (bIsFileApiAnsi)
334 RtlAnsiStringToUnicodeString (&RootPathNameU,
335 &RootPathName,
336 TRUE);
337 else
338 RtlOemStringToUnicodeString (&RootPathNameU,
339 &RootPathName,
340 TRUE);
341
342 Result = GetDriveTypeW (RootPathNameU.Buffer);
343
344 RtlFreeHeap (RtlGetProcessHeap (),
345 0,
346 RootPathNameU.Buffer);
347
348 return Result;
349 }
350
351
352 UINT STDCALL
353 GetDriveTypeW(LPCWSTR lpRootPathName)
354 {
355 FILE_FS_DEVICE_INFORMATION FileFsDevice;
356 IO_STATUS_BLOCK IoStatusBlock;
357
358 HANDLE hFile;
359 NTSTATUS errCode;
360
361 hFile = CreateFileW (lpRootPathName,
362 GENERIC_ALL,
363 FILE_SHARE_READ|FILE_SHARE_WRITE,
364 NULL,
365 OPEN_EXISTING,
366 FILE_ATTRIBUTE_NORMAL,
367 NULL);
368
369 errCode = NtQueryVolumeInformationFile (hFile,
370 &IoStatusBlock,
371 &FileFsDevice,
372 sizeof(FILE_FS_DEVICE_INFORMATION),
373 FileFsDeviceInformation);
374 if (!NT_SUCCESS(errCode))
375 {
376 CloseHandle(hFile);
377 SetLastErrorByStatus (errCode);
378 return 0;
379 }
380 CloseHandle(hFile);
381 return (UINT)FileFsDevice.DeviceType;
382 }
383
384
385 WINBOOL STDCALL
386 GetVolumeInformationA(
387 LPCSTR lpRootPathName,
388 LPSTR lpVolumeNameBuffer,
389 DWORD nVolumeNameSize,
390 LPDWORD lpVolumeSerialNumber,
391 LPDWORD lpMaximumComponentLength,
392 LPDWORD lpFileSystemFlags,
393 LPSTR lpFileSystemNameBuffer,
394 DWORD nFileSystemNameSize
395 )
396 {
397 UNICODE_STRING RootPathNameU;
398 UNICODE_STRING FileSystemNameU;
399 UNICODE_STRING VolumeNameU;
400 ANSI_STRING RootPathName;
401 ANSI_STRING VolumeName;
402 ANSI_STRING FileSystemName;
403 WINBOOL Result;
404
405 RtlInitAnsiString (&RootPathName,
406 (LPSTR)lpRootPathName);
407
408 /* convert ansi (or oem) string to unicode */
409 if (bIsFileApiAnsi)
410 RtlAnsiStringToUnicodeString (&RootPathNameU,
411 &RootPathName,
412 TRUE);
413 else
414 RtlOemStringToUnicodeString (&RootPathNameU,
415 &RootPathName,
416 TRUE);
417
418 VolumeNameU.Length = 0;
419 VolumeNameU.MaximumLength = nVolumeNameSize * sizeof(WCHAR);
420 VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
421 0,
422 VolumeNameU.MaximumLength);
423
424 FileSystemNameU.Length = 0;
425 FileSystemNameU.MaximumLength = nFileSystemNameSize * sizeof(WCHAR);
426 FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
427 0,
428 FileSystemNameU.MaximumLength);
429
430 Result = GetVolumeInformationW (RootPathNameU.Buffer,
431 VolumeNameU.Buffer,
432 nVolumeNameSize,
433 lpVolumeSerialNumber,
434 lpMaximumComponentLength,
435 lpFileSystemFlags,
436 FileSystemNameU.Buffer,
437 nFileSystemNameSize);
438
439 if (Result)
440 {
441 VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR);
442 VolumeName.Length = 0;
443 VolumeName.MaximumLength = nVolumeNameSize;
444 VolumeName.Buffer = lpVolumeNameBuffer;
445
446 FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR);
447 FileSystemName.Length = 0;
448 FileSystemName.MaximumLength = nFileSystemNameSize;
449 FileSystemName.Buffer = lpFileSystemNameBuffer;
450
451 /* convert unicode strings to ansi (or oem) */
452 if (bIsFileApiAnsi)
453 {
454 RtlUnicodeStringToAnsiString (&VolumeName,
455 &VolumeNameU,
456 FALSE);
457 RtlUnicodeStringToAnsiString (&FileSystemName,
458 &FileSystemNameU,
459 FALSE);
460 }
461 else
462 {
463 RtlUnicodeStringToOemString (&VolumeName,
464 &VolumeNameU,
465 FALSE);
466 RtlUnicodeStringToOemString (&FileSystemName,
467 &FileSystemNameU,
468 FALSE);
469 }
470 }
471
472 RtlFreeHeap (RtlGetProcessHeap (),
473 0,
474 RootPathNameU.Buffer);
475 RtlFreeHeap (RtlGetProcessHeap (),
476 0,
477 VolumeNameU.Buffer);
478 RtlFreeHeap (RtlGetProcessHeap (),
479 0,
480 FileSystemNameU.Buffer);
481
482 return Result;
483 }
484
485
486
487
488 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_VOLUME_INFORMATION))
489
490 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
491
492
493 WINBOOL STDCALL
494 GetVolumeInformationW(
495 LPCWSTR lpRootPathName,
496 LPWSTR lpVolumeNameBuffer,
497 DWORD nVolumeNameSize,
498 LPDWORD lpVolumeSerialNumber,
499 LPDWORD lpMaximumComponentLength,
500 LPDWORD lpFileSystemFlags,
501 LPWSTR lpFileSystemNameBuffer,
502 DWORD nFileSystemNameSize
503 )
504 {
505 PFILE_FS_VOLUME_INFORMATION FileFsVolume;
506 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
507 IO_STATUS_BLOCK IoStatusBlock;
508 OBJECT_ATTRIBUTES ObjectAttributes;
509 UNICODE_STRING NtPathU;
510 USHORT Buffer[FS_VOLUME_BUFFER_SIZE];
511 USHORT Buffer2[FS_ATTRIBUTE_BUFFER_SIZE];
512
513 HANDLE hFile;
514 NTSTATUS errCode;
515
516 FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
517 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer2;
518
519 DPRINT("FileFsVolume %p\n", FileFsVolume);
520 DPRINT("FileFsAttribute %p\n", FileFsAttribute);
521
522 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpRootPathName,
523 &NtPathU,
524 NULL,
525 NULL))
526 {
527 DPRINT("Invalid path\n");
528 SetLastError(ERROR_BAD_PATHNAME);
529 return FALSE;
530 }
531
532 InitializeObjectAttributes(&ObjectAttributes,
533 &NtPathU,
534 FILE_READ_ATTRIBUTES,
535 NULL,
536 NULL);
537
538 errCode = NtCreateFile (&hFile,
539 FILE_GENERIC_READ,
540 &ObjectAttributes,
541 &IoStatusBlock,
542 NULL,
543 0,
544 FILE_SHARE_READ|FILE_SHARE_WRITE,
545 FILE_OPEN,
546 0,
547 NULL,
548 0);
549
550 RtlFreeUnicodeString(&NtPathU);
551
552 if (!NT_SUCCESS(errCode))
553 {
554 SetLastErrorByStatus (errCode);
555 return FALSE;
556 }
557
558 DPRINT("hFile: %x\n", hFile);
559 errCode = NtQueryVolumeInformationFile(hFile,
560 &IoStatusBlock,
561 FileFsVolume,
562 FS_VOLUME_BUFFER_SIZE,
563 FileFsVolumeInformation);
564 if ( !NT_SUCCESS(errCode) ) {
565 DPRINT("Status: %x\n", errCode);
566 CloseHandle(hFile);
567 SetLastErrorByStatus (errCode);
568 return FALSE;
569 }
570
571 if (lpVolumeSerialNumber)
572 *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
573
574 if (lpVolumeNameBuffer)
575 wcsncpy (lpVolumeNameBuffer,
576 FileFsVolume->VolumeLabel,
577 min(nVolumeNameSize,MAX_PATH));
578
579 errCode = NtQueryVolumeInformationFile (hFile,
580 &IoStatusBlock,
581 FileFsAttribute,
582 FS_ATTRIBUTE_BUFFER_SIZE,
583 FileFsAttributeInformation);
584 if (!NT_SUCCESS(errCode))
585 {
586 DPRINT("Status: %x\n", errCode);
587 CloseHandle(hFile);
588 SetLastErrorByStatus (errCode);
589 return FALSE;
590 }
591
592 if (lpFileSystemFlags)
593 *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
594 if (lpMaximumComponentLength)
595 *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
596 if (lpFileSystemNameBuffer)
597 wcsncpy(lpFileSystemNameBuffer, FileFsAttribute->FileSystemName,min(nFileSystemNameSize,MAX_PATH));
598
599 CloseHandle(hFile);
600 return TRUE;
601 }
602
603
604 WINBOOL
605 STDCALL
606 SetVolumeLabelA (
607 LPCSTR lpRootPathName,
608 LPCSTR lpVolumeName
609 )
610 {
611 UNICODE_STRING RootPathNameU;
612 ANSI_STRING RootPathName;
613 UNICODE_STRING VolumeNameU;
614 ANSI_STRING VolumeName;
615 WINBOOL Result;
616
617 RtlInitAnsiString (&RootPathName,
618 (LPSTR)lpRootPathName);
619 RtlInitAnsiString (&VolumeName,
620 (LPSTR)lpVolumeName);
621
622 /* convert ansi (or oem) strings to unicode */
623 if (bIsFileApiAnsi)
624 {
625 RtlAnsiStringToUnicodeString (&RootPathNameU,
626 &RootPathName,
627 TRUE);
628 RtlAnsiStringToUnicodeString (&VolumeNameU,
629 &VolumeName,
630 TRUE);
631 }
632 else
633 {
634 RtlOemStringToUnicodeString (&RootPathNameU,
635 &RootPathName,
636 TRUE);
637 RtlOemStringToUnicodeString (&VolumeNameU,
638 &VolumeName,
639 TRUE);
640 }
641
642 Result = SetVolumeLabelW (RootPathNameU.Buffer,
643 VolumeNameU.Buffer);
644
645 RtlFreeHeap (RtlGetProcessHeap (),
646 0,
647 RootPathNameU.Buffer);
648 RtlFreeHeap (RtlGetProcessHeap (),
649 0,
650 VolumeNameU.Buffer);
651
652 return Result;
653 }
654
655
656 WINBOOL STDCALL
657 SetVolumeLabelW(LPCWSTR lpRootPathName,
658 LPCWSTR lpVolumeName)
659 {
660 PFILE_FS_LABEL_INFORMATION LabelInfo;
661 IO_STATUS_BLOCK IoStatusBlock;
662 ULONG LabelLength;
663 HANDLE hFile;
664 NTSTATUS Status;
665
666 LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
667 LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
668 0,
669 sizeof(FILE_FS_LABEL_INFORMATION) +
670 LabelLength);
671 LabelInfo->VolumeLabelLength = LabelLength;
672 wcscpy(LabelInfo->VolumeLabel,
673 lpVolumeName);
674
675 hFile = CreateFileW(lpRootPathName,
676 FILE_WRITE_ATTRIBUTES,
677 FILE_SHARE_READ|FILE_SHARE_WRITE,
678 NULL,
679 OPEN_EXISTING,
680 FILE_ATTRIBUTE_NORMAL,
681 NULL);
682 DPRINT("hFile: %x\n", hFile);
683
684 Status = NtSetVolumeInformationFile(hFile,
685 &IoStatusBlock,
686 LabelInfo,
687 sizeof(FILE_FS_LABEL_INFORMATION) +
688 LabelLength,
689 FileFsLabelInformation);
690
691 RtlFreeHeap(RtlGetProcessHeap(),
692 0,
693 LabelInfo);
694
695 if (!NT_SUCCESS(Status))
696 {
697 DPRINT("Status: %x\n", Status);
698 CloseHandle(hFile);
699 SetLastErrorByStatus(Status);
700 return FALSE;
701 }
702
703 CloseHandle(hFile);
704 return TRUE;
705 }
706
707 /* EOF */