Fix a handle leak.
[reactos.git] / reactos / lib / kernel32 / file / volume.c
1 /* $Id$
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 <k32.h>
23
24 #define NDEBUG
25 #include "../include/debug.h"
26
27
28 #define MAX_DOS_DRIVES 26
29
30
31 static HANDLE
32 InternalOpenDirW(LPCWSTR DirName,
33 BOOLEAN Write)
34 {
35 UNICODE_STRING NtPathU;
36 OBJECT_ATTRIBUTES ObjectAttributes;
37 NTSTATUS errCode;
38 IO_STATUS_BLOCK IoStatusBlock;
39 HANDLE hFile;
40
41 if (!RtlDosPathNameToNtPathName_U((LPWSTR)DirName,
42 &NtPathU,
43 NULL,
44 NULL))
45 {
46 DPRINT("Invalid path\n");
47 SetLastError(ERROR_BAD_PATHNAME);
48 return INVALID_HANDLE_VALUE;
49 }
50
51 InitializeObjectAttributes(&ObjectAttributes,
52 &NtPathU,
53 Write ? FILE_WRITE_ATTRIBUTES : FILE_READ_ATTRIBUTES,
54 NULL,
55 NULL);
56
57 errCode = NtCreateFile (&hFile,
58 Write ? FILE_GENERIC_WRITE : FILE_GENERIC_READ,
59 &ObjectAttributes,
60 &IoStatusBlock,
61 NULL,
62 0,
63 FILE_SHARE_READ|FILE_SHARE_WRITE,
64 FILE_OPEN,
65 0,
66 NULL,
67 0);
68
69 RtlFreeUnicodeString(&NtPathU);
70
71 if (!NT_SUCCESS(errCode))
72 {
73 SetLastErrorByStatus (errCode);
74 return INVALID_HANDLE_VALUE;
75 }
76 return hFile;
77 }
78
79
80 /*
81 * @implemented
82 */
83 DWORD STDCALL
84 GetLogicalDriveStringsA(DWORD nBufferLength,
85 LPSTR lpBuffer)
86 {
87 DWORD drive, count;
88 DWORD dwDriveMap;
89
90 dwDriveMap = GetLogicalDrives();
91
92 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
93 {
94 if (dwDriveMap & (1<<drive))
95 count++;
96 }
97
98
99 if (count * 4 * sizeof(char) <= nBufferLength)
100 {
101 LPSTR p = lpBuffer;
102
103 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
104 if (dwDriveMap & (1<<drive))
105 {
106 *p++ = 'A' + drive;
107 *p++ = ':';
108 *p++ = '\\';
109 *p++ = '\0';
110 }
111 *p = '\0';
112 }
113 return (count * 4 * sizeof(char));
114 }
115
116
117 /*
118 * @implemented
119 */
120 DWORD STDCALL
121 GetLogicalDriveStringsW(DWORD nBufferLength,
122 LPWSTR lpBuffer)
123 {
124 DWORD drive, count;
125 DWORD dwDriveMap;
126
127 dwDriveMap = GetLogicalDrives();
128
129 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
130 {
131 if (dwDriveMap & (1<<drive))
132 count++;
133 }
134
135 if (count * 4 * sizeof(WCHAR) <= nBufferLength)
136 {
137 LPWSTR p = lpBuffer;
138 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
139 if (dwDriveMap & (1<<drive))
140 {
141 *p++ = (WCHAR)('A' + drive);
142 *p++ = (WCHAR)':';
143 *p++ = (WCHAR)'\\';
144 *p++ = (WCHAR)'\0';
145 }
146 *p = (WCHAR)'\0';
147 }
148 return (count * 4 * sizeof(WCHAR));
149 }
150
151
152 /*
153 * @implemented
154 */
155 DWORD STDCALL
156 GetLogicalDrives(VOID)
157 {
158 NTSTATUS Status;
159 PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
160
161 /* Get the Device Map for this Process */
162 Status = NtQueryInformationProcess(NtCurrentProcess(),
163 ProcessDeviceMap,
164 &ProcessDeviceMapInfo,
165 sizeof(ProcessDeviceMapInfo),
166 NULL);
167
168 /* Return the Drive Map */
169 if (!NT_SUCCESS(Status))
170 {
171 SetLastErrorByStatus(Status);
172 return 0;
173 }
174
175 return ProcessDeviceMapInfo.Query.DriveMap;
176 }
177
178
179 /*
180 * @implemented
181 */
182 BOOL STDCALL
183 GetDiskFreeSpaceA (
184 LPCSTR lpRootPathName,
185 LPDWORD lpSectorsPerCluster,
186 LPDWORD lpBytesPerSector,
187 LPDWORD lpNumberOfFreeClusters,
188 LPDWORD lpTotalNumberOfClusters
189 )
190 {
191 PWCHAR RootPathNameW=NULL;
192
193 if (lpRootPathName)
194 {
195 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
196 return FALSE;
197 }
198
199 return GetDiskFreeSpaceW (RootPathNameW,
200 lpSectorsPerCluster,
201 lpBytesPerSector,
202 lpNumberOfFreeClusters,
203 lpTotalNumberOfClusters);
204 }
205
206
207 /*
208 * @implemented
209 */
210 BOOL STDCALL
211 GetDiskFreeSpaceW(
212 LPCWSTR lpRootPathName,
213 LPDWORD lpSectorsPerCluster,
214 LPDWORD lpBytesPerSector,
215 LPDWORD lpNumberOfFreeClusters,
216 LPDWORD lpTotalNumberOfClusters
217 )
218 {
219 FILE_FS_SIZE_INFORMATION FileFsSize;
220 IO_STATUS_BLOCK IoStatusBlock;
221 WCHAR RootPathName[MAX_PATH];
222 HANDLE hFile;
223 NTSTATUS errCode;
224
225 if (lpRootPathName)
226 {
227 wcsncpy (RootPathName, lpRootPathName, 3);
228 }
229 else
230 {
231 GetCurrentDirectoryW (MAX_PATH, RootPathName);
232 }
233 RootPathName[3] = 0;
234
235 hFile = InternalOpenDirW(RootPathName, FALSE);
236 if (INVALID_HANDLE_VALUE == hFile)
237 {
238 SetLastError(ERROR_PATH_NOT_FOUND);
239 return FALSE;
240 }
241
242 errCode = NtQueryVolumeInformationFile(hFile,
243 &IoStatusBlock,
244 &FileFsSize,
245 sizeof(FILE_FS_SIZE_INFORMATION),
246 FileFsSizeInformation);
247 if (!NT_SUCCESS(errCode))
248 {
249 CloseHandle(hFile);
250 SetLastErrorByStatus (errCode);
251 return FALSE;
252 }
253
254 *lpBytesPerSector = FileFsSize.BytesPerSector;
255 *lpSectorsPerCluster = FileFsSize.SectorsPerAllocationUnit;
256 *lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.u.LowPart;
257 *lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.u.LowPart;
258 CloseHandle(hFile);
259
260 return TRUE;
261 }
262
263
264 /*
265 * @implemented
266 */
267 BOOL STDCALL
268 GetDiskFreeSpaceExA (
269 LPCSTR lpDirectoryName OPTIONAL,
270 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
271 PULARGE_INTEGER lpTotalNumberOfBytes,
272 PULARGE_INTEGER lpTotalNumberOfFreeBytes
273 )
274 {
275 PWCHAR DirectoryNameW=NULL;
276
277 if (lpDirectoryName)
278 {
279 if (!(DirectoryNameW = FilenameA2W(lpDirectoryName, FALSE)))
280 return FALSE;
281 }
282
283 return GetDiskFreeSpaceExW (DirectoryNameW ,
284 lpFreeBytesAvailableToCaller,
285 lpTotalNumberOfBytes,
286 lpTotalNumberOfFreeBytes);
287 }
288
289
290 /*
291 * @implemented
292 */
293 BOOL STDCALL
294 GetDiskFreeSpaceExW(
295 LPCWSTR lpDirectoryName OPTIONAL,
296 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
297 PULARGE_INTEGER lpTotalNumberOfBytes,
298 PULARGE_INTEGER lpTotalNumberOfFreeBytes
299 )
300 {
301 FILE_FS_SIZE_INFORMATION FileFsSize;
302 IO_STATUS_BLOCK IoStatusBlock;
303 ULARGE_INTEGER BytesPerCluster;
304 WCHAR RootPathName[MAX_PATH];
305 HANDLE hFile;
306 NTSTATUS errCode;
307
308 /*
309 FIXME: this is obviously wrong for UNC paths, symbolic directories etc.
310 -Gunnar
311 */
312 if (lpDirectoryName)
313 {
314 wcsncpy (RootPathName, lpDirectoryName, 3);
315 }
316 else
317 {
318 GetCurrentDirectoryW (MAX_PATH, RootPathName);
319 }
320 RootPathName[3] = 0;
321
322 hFile = InternalOpenDirW(RootPathName, FALSE);
323 if (INVALID_HANDLE_VALUE == hFile)
324 {
325 return FALSE;
326 }
327
328 errCode = NtQueryVolumeInformationFile(hFile,
329 &IoStatusBlock,
330 &FileFsSize,
331 sizeof(FILE_FS_SIZE_INFORMATION),
332 FileFsSizeInformation);
333 if (!NT_SUCCESS(errCode))
334 {
335 CloseHandle(hFile);
336 SetLastErrorByStatus (errCode);
337 return FALSE;
338 }
339
340 BytesPerCluster.QuadPart =
341 FileFsSize.BytesPerSector * FileFsSize.SectorsPerAllocationUnit;
342
343 // FIXME: Use quota information
344 if (lpFreeBytesAvailableToCaller)
345 lpFreeBytesAvailableToCaller->QuadPart =
346 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
347
348 if (lpTotalNumberOfBytes)
349 lpTotalNumberOfBytes->QuadPart =
350 BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.QuadPart;
351 if (lpTotalNumberOfFreeBytes)
352 lpTotalNumberOfFreeBytes->QuadPart =
353 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
354
355 CloseHandle(hFile);
356
357 return TRUE;
358 }
359
360
361 /*
362 * @implemented
363 */
364 UINT STDCALL
365 GetDriveTypeA(LPCSTR lpRootPathName)
366 {
367 PWCHAR RootPathNameW;
368
369 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
370 return DRIVE_UNKNOWN;
371
372 return GetDriveTypeW(RootPathNameW);
373 }
374
375
376 /*
377 * @implemented
378 */
379 UINT STDCALL
380 GetDriveTypeW(LPCWSTR lpRootPathName)
381 {
382 FILE_FS_DEVICE_INFORMATION FileFsDevice;
383 IO_STATUS_BLOCK IoStatusBlock;
384
385 HANDLE hFile;
386 NTSTATUS errCode;
387
388 hFile = InternalOpenDirW(lpRootPathName, FALSE);
389 if (hFile == INVALID_HANDLE_VALUE)
390 {
391 return DRIVE_NO_ROOT_DIR; /* According to WINE regression tests */
392 }
393
394 errCode = NtQueryVolumeInformationFile (hFile,
395 &IoStatusBlock,
396 &FileFsDevice,
397 sizeof(FILE_FS_DEVICE_INFORMATION),
398 FileFsDeviceInformation);
399 if (!NT_SUCCESS(errCode))
400 {
401 CloseHandle(hFile);
402 SetLastErrorByStatus (errCode);
403 return 0;
404 }
405 CloseHandle(hFile);
406
407 switch (FileFsDevice.DeviceType)
408 {
409 case FILE_DEVICE_CD_ROM:
410 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
411 return DRIVE_CDROM;
412 case FILE_DEVICE_VIRTUAL_DISK:
413 return DRIVE_RAMDISK;
414 case FILE_DEVICE_NETWORK_FILE_SYSTEM:
415 return DRIVE_REMOTE;
416 case FILE_DEVICE_DISK:
417 case FILE_DEVICE_DISK_FILE_SYSTEM:
418 if (FileFsDevice.Characteristics & FILE_REMOTE_DEVICE)
419 return DRIVE_REMOTE;
420 if (FileFsDevice.Characteristics & FILE_REMOVABLE_MEDIA)
421 return DRIVE_REMOVABLE;
422 return DRIVE_FIXED;
423 }
424
425 DPRINT1("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice.DeviceType);
426
427 return DRIVE_UNKNOWN;
428 }
429
430
431 /*
432 * @implemented
433 */
434 BOOL STDCALL
435 GetVolumeInformationA(
436 LPCSTR lpRootPathName,
437 LPSTR lpVolumeNameBuffer,
438 DWORD nVolumeNameSize,
439 LPDWORD lpVolumeSerialNumber,
440 LPDWORD lpMaximumComponentLength,
441 LPDWORD lpFileSystemFlags,
442 LPSTR lpFileSystemNameBuffer,
443 DWORD nFileSystemNameSize
444 )
445 {
446 UNICODE_STRING FileSystemNameU;
447 UNICODE_STRING VolumeNameU = {0};
448 ANSI_STRING VolumeName;
449 ANSI_STRING FileSystemName;
450 PWCHAR RootPathNameW;
451 BOOL Result;
452
453 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
454 return FALSE;
455
456 if (lpVolumeNameBuffer)
457 {
458 VolumeNameU.MaximumLength = nVolumeNameSize * sizeof(WCHAR);
459 VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
460 0,
461 VolumeNameU.MaximumLength);
462 if (VolumeNameU.Buffer == NULL)
463 {
464 goto FailNoMem;
465 }
466 }
467
468 if (lpFileSystemNameBuffer)
469 {
470 FileSystemNameU.Length = 0;
471 FileSystemNameU.MaximumLength = nFileSystemNameSize * sizeof(WCHAR);
472 FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
473 0,
474 FileSystemNameU.MaximumLength);
475 if (FileSystemNameU.Buffer == NULL)
476 {
477 if (VolumeNameU.Buffer != NULL)
478 {
479 RtlFreeHeap(RtlGetProcessHeap(),
480 0,
481 VolumeNameU.Buffer);
482 }
483
484 FailNoMem:
485 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
486 return FALSE;
487 }
488 }
489
490 Result = GetVolumeInformationW (RootPathNameW,
491 lpVolumeNameBuffer ? VolumeNameU.Buffer : NULL,
492 nVolumeNameSize,
493 lpVolumeSerialNumber,
494 lpMaximumComponentLength,
495 lpFileSystemFlags,
496 lpFileSystemNameBuffer ? FileSystemNameU.Buffer : NULL,
497 nFileSystemNameSize);
498
499 if (Result)
500 {
501 if (lpVolumeNameBuffer)
502 {
503 VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR);
504 VolumeName.Length = 0;
505 VolumeName.MaximumLength = nVolumeNameSize;
506 VolumeName.Buffer = lpVolumeNameBuffer;
507 }
508
509 if (lpFileSystemNameBuffer)
510 {
511 FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR);
512 FileSystemName.Length = 0;
513 FileSystemName.MaximumLength = nFileSystemNameSize;
514 FileSystemName.Buffer = lpFileSystemNameBuffer;
515 }
516
517 /* convert unicode strings to ansi (or oem) */
518 if (bIsFileApiAnsi)
519 {
520 if (lpVolumeNameBuffer)
521 {
522 RtlUnicodeStringToAnsiString (&VolumeName,
523 &VolumeNameU,
524 FALSE);
525 }
526 if (lpFileSystemNameBuffer)
527 {
528 RtlUnicodeStringToAnsiString (&FileSystemName,
529 &FileSystemNameU,
530 FALSE);
531 }
532 }
533 else
534 {
535 if (lpVolumeNameBuffer)
536 {
537 RtlUnicodeStringToOemString (&VolumeName,
538 &VolumeNameU,
539 FALSE);
540 }
541 if (lpFileSystemNameBuffer)
542 {
543 RtlUnicodeStringToOemString (&FileSystemName,
544 &FileSystemNameU,
545 FALSE);
546 }
547 }
548 }
549
550 if (lpVolumeNameBuffer)
551 {
552 RtlFreeHeap (RtlGetProcessHeap (),
553 0,
554 VolumeNameU.Buffer);
555 }
556 if (lpFileSystemNameBuffer)
557 {
558 RtlFreeHeap (RtlGetProcessHeap (),
559 0,
560 FileSystemNameU.Buffer);
561 }
562
563 return Result;
564 }
565
566 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
567
568 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
569
570 /*
571 * @implemented
572 */
573 BOOL STDCALL
574 GetVolumeInformationW(
575 LPCWSTR lpRootPathName,
576 LPWSTR lpVolumeNameBuffer,
577 DWORD nVolumeNameSize,
578 LPDWORD lpVolumeSerialNumber,
579 LPDWORD lpMaximumComponentLength,
580 LPDWORD lpFileSystemFlags,
581 LPWSTR lpFileSystemNameBuffer,
582 DWORD nFileSystemNameSize
583 )
584 {
585 PFILE_FS_VOLUME_INFORMATION FileFsVolume;
586 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
587 IO_STATUS_BLOCK IoStatusBlock;
588 WCHAR RootPathName[MAX_PATH];
589 UCHAR Buffer[max(FS_VOLUME_BUFFER_SIZE, FS_ATTRIBUTE_BUFFER_SIZE)];
590
591 HANDLE hFile;
592 NTSTATUS errCode;
593
594 FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
595 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
596
597 DPRINT("FileFsVolume %p\n", FileFsVolume);
598 DPRINT("FileFsAttribute %p\n", FileFsAttribute);
599
600 if (!lpRootPathName || !wcscmp(lpRootPathName, L""))
601 {
602 GetCurrentDirectoryW (MAX_PATH, RootPathName);
603 }
604 else
605 {
606 wcsncpy (RootPathName, lpRootPathName, 3);
607 }
608 RootPathName[3] = 0;
609
610 hFile = InternalOpenDirW(RootPathName, FALSE);
611 if (hFile == INVALID_HANDLE_VALUE)
612 {
613 return FALSE;
614 }
615
616 DPRINT("hFile: %x\n", hFile);
617 errCode = NtQueryVolumeInformationFile(hFile,
618 &IoStatusBlock,
619 FileFsVolume,
620 FS_VOLUME_BUFFER_SIZE,
621 FileFsVolumeInformation);
622 if ( !NT_SUCCESS(errCode) )
623 {
624 DPRINT("Status: %x\n", errCode);
625 CloseHandle(hFile);
626 SetLastErrorByStatus (errCode);
627 return FALSE;
628 }
629
630 if (lpVolumeSerialNumber)
631 *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
632
633 if (lpVolumeNameBuffer)
634 {
635 if (nVolumeNameSize * sizeof(WCHAR) >= FileFsVolume->VolumeLabelLength + sizeof(WCHAR))
636 {
637 memcpy(lpVolumeNameBuffer,
638 FileFsVolume->VolumeLabel,
639 FileFsVolume->VolumeLabelLength);
640 lpVolumeNameBuffer[FileFsVolume->VolumeLabelLength / sizeof(WCHAR)] = 0;
641 }
642 else
643 {
644 CloseHandle(hFile);
645 SetLastError(ERROR_MORE_DATA);
646 return FALSE;
647 }
648 }
649
650 errCode = NtQueryVolumeInformationFile (hFile,
651 &IoStatusBlock,
652 FileFsAttribute,
653 FS_ATTRIBUTE_BUFFER_SIZE,
654 FileFsAttributeInformation);
655 CloseHandle(hFile);
656 if (!NT_SUCCESS(errCode))
657 {
658 DPRINT("Status: %x\n", errCode);
659 SetLastErrorByStatus (errCode);
660 return FALSE;
661 }
662
663 if (lpFileSystemFlags)
664 *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
665 if (lpMaximumComponentLength)
666 *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
667 if (lpFileSystemNameBuffer)
668 {
669 if (nFileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
670 {
671 memcpy(lpFileSystemNameBuffer,
672 FileFsAttribute->FileSystemName,
673 FileFsAttribute->FileSystemNameLength);
674 lpFileSystemNameBuffer[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
675 }
676 else
677 {
678 SetLastError(ERROR_MORE_DATA);
679 return FALSE;
680 }
681 }
682 return TRUE;
683 }
684
685
686 /*
687 * @implemented
688 */
689 BOOL
690 STDCALL
691 SetVolumeLabelA (
692 LPCSTR lpRootPathName,
693 LPCSTR lpVolumeName /* NULL if deleting label */
694 )
695 {
696 PWCHAR RootPathNameW;
697 PWCHAR VolumeNameW = NULL;
698 BOOL Result;
699
700 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
701 return FALSE;
702
703 if (lpVolumeName)
704 {
705 if (!(VolumeNameW = FilenameA2W(lpVolumeName, TRUE)))
706 return FALSE;
707 }
708
709 Result = SetVolumeLabelW (RootPathNameW,
710 VolumeNameW);
711
712 if (VolumeNameW)
713 {
714 RtlFreeHeap (RtlGetProcessHeap (),
715 0,
716 VolumeNameW );
717 }
718
719 return Result;
720 }
721
722
723 /*
724 * @implemented
725 */
726 BOOL STDCALL
727 SetVolumeLabelW(
728 LPCWSTR lpRootPathName,
729 LPCWSTR lpVolumeName /* NULL if deleting label */
730 )
731 {
732 PFILE_FS_LABEL_INFORMATION LabelInfo;
733 IO_STATUS_BLOCK IoStatusBlock;
734 ULONG LabelLength;
735 HANDLE hFile;
736 NTSTATUS Status;
737
738 LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
739 LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
740 0,
741 sizeof(FILE_FS_LABEL_INFORMATION) +
742 LabelLength);
743 if (LabelInfo == NULL)
744 {
745 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
746 return FALSE;
747 }
748 LabelInfo->VolumeLabelLength = LabelLength;
749 memcpy(LabelInfo->VolumeLabel,
750 lpVolumeName,
751 LabelLength);
752
753 hFile = InternalOpenDirW(lpRootPathName, TRUE);
754 if (INVALID_HANDLE_VALUE == hFile)
755 {
756 RtlFreeHeap(RtlGetProcessHeap(),
757 0,
758 LabelInfo);
759 return FALSE;
760 }
761
762 Status = NtSetVolumeInformationFile(hFile,
763 &IoStatusBlock,
764 LabelInfo,
765 sizeof(FILE_FS_LABEL_INFORMATION) +
766 LabelLength,
767 FileFsLabelInformation);
768
769 RtlFreeHeap(RtlGetProcessHeap(),
770 0,
771 LabelInfo);
772
773 if (!NT_SUCCESS(Status))
774 {
775 DPRINT("Status: %x\n", Status);
776 CloseHandle(hFile);
777 SetLastErrorByStatus(Status);
778 return FALSE;
779 }
780
781 CloseHandle(hFile);
782 return TRUE;
783 }
784
785 /**
786 * @name GetVolumeNameForVolumeMountPointW
787 *
788 * Return an unique volume name for a drive root or mount point.
789 *
790 * @param VolumeMountPoint
791 * Pointer to string that contains either root drive name or
792 * mount point name.
793 * @param VolumeName
794 * Pointer to buffer that is filled with resulting unique
795 * volume name on success.
796 * @param VolumeNameLength
797 * Size of VolumeName buffer in TCHARs.
798 *
799 * @return
800 * TRUE when the function succeeds and the VolumeName buffer is filled,
801 * FALSE otherwise.
802 */
803
804 BOOL WINAPI
805 GetVolumeNameForVolumeMountPointW(
806 IN LPCWSTR VolumeMountPoint,
807 OUT LPWSTR VolumeName,
808 IN DWORD VolumeNameLength)
809 {
810 UNICODE_STRING NtFileName;
811 OBJECT_ATTRIBUTES ObjectAttributes;
812 HANDLE FileHandle;
813 IO_STATUS_BLOCK Iosb;
814 ULONG BufferLength;
815 PMOUNTDEV_NAME MountDevName;
816 PMOUNTMGR_MOUNT_POINT MountPoint;
817 ULONG MountPointSize;
818 PMOUNTMGR_MOUNT_POINTS MountPoints;
819 ULONG Index;
820 PUCHAR SymbolicLinkName;
821 BOOL Result;
822 NTSTATUS Status;
823
824 /*
825 * First step is to convert the passed volume mount point name to
826 * an NT acceptable name.
827 */
828
829 if (!RtlDosPathNameToNtPathName_U(VolumeName, &NtFileName, NULL, NULL))
830 {
831 SetLastError(ERROR_PATH_NOT_FOUND);
832 return FALSE;
833 }
834
835 if (NtFileName.Length > sizeof(WCHAR) &&
836 NtFileName.Buffer[(NtFileName.Length / sizeof(WCHAR)) - 1] == '\\')
837 {
838 NtFileName.Length -= sizeof(WCHAR);
839 }
840
841 /*
842 * Query mount point device name which we will later use for determining
843 * the volume name.
844 */
845
846 InitializeObjectAttributes(&ObjectAttributes, &NtFileName, 0, NULL, NULL);
847 Status = NtOpenFile(&FileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE,
848 &ObjectAttributes, &Iosb,
849 FILE_SHARE_READ | FILE_SHARE_WRITE,
850 FILE_SYNCHRONOUS_IO_NONALERT);
851 RtlFreeUnicodeString(&NtFileName);
852 if (!NT_SUCCESS(Status))
853 {
854 SetLastErrorByStatus(Status);
855 return FALSE;
856 }
857
858 BufferLength = sizeof(MOUNTDEV_NAME) + 50 * sizeof(WCHAR);
859 do
860 {
861 MountDevName = RtlAllocateHeap(GetProcessHeap(), 0, BufferLength);
862 if (MountDevName == NULL)
863 {
864 NtClose(FileHandle);
865 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
866 return FALSE;
867 }
868
869 Status = NtDeviceIoControlFile(FileHandle, NULL, NULL, NULL, &Iosb,
870 IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
871 NULL, 0, MountDevName, BufferLength);
872 if (!NT_SUCCESS(Status))
873 {
874 RtlFreeHeap(GetProcessHeap(), 0, MountDevName);
875 if (Status == STATUS_BUFFER_OVERFLOW)
876 {
877 BufferLength = sizeof(MOUNTDEV_NAME) + MountDevName->NameLength;
878 continue;
879 }
880 else
881 {
882 NtClose(FileHandle);
883 SetLastErrorByStatus(Status);
884 return FALSE;
885 }
886 }
887 }
888 while (!NT_SUCCESS(Status));
889
890 NtClose(FileHandle);
891
892 /*
893 * Get the mount point information from mount manager.
894 */
895
896 MountPointSize = MountDevName->NameLength + sizeof(MOUNTMGR_MOUNT_POINT);
897 MountPoint = RtlAllocateHeap(GetProcessHeap(), 0, MountPointSize);
898 if (MountPoint == NULL)
899 {
900 RtlFreeHeap(GetProcessHeap(), 0, MountDevName);
901 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
902 return FALSE;
903 }
904 RtlZeroMemory(MountPoint, sizeof(MOUNTMGR_MOUNT_POINT));
905 MountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
906 MountPoint->DeviceNameLength = MountDevName->NameLength;
907 RtlCopyMemory(MountPoint + 1, MountDevName->Name, MountDevName->NameLength);
908 RtlFreeHeap(GetProcessHeap(), 0, MountDevName);
909
910 RtlInitUnicodeString(&NtFileName, L"\\??\\MountPointManager");
911 InitializeObjectAttributes(&ObjectAttributes, &NtFileName, 0, NULL, NULL);
912 Status = NtOpenFile(&FileHandle, FILE_GENERIC_READ, &ObjectAttributes,
913 &Iosb, FILE_SHARE_READ | FILE_SHARE_WRITE,
914 FILE_SYNCHRONOUS_IO_NONALERT);
915 if (!NT_SUCCESS(Status))
916 {
917 SetLastErrorByStatus(Status);
918 RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
919 return FALSE;
920 }
921
922 BufferLength = sizeof(MOUNTMGR_MOUNT_POINTS);
923 do
924 {
925 MountPoints = RtlAllocateHeap(GetProcessHeap(), 0, BufferLength);
926 if (MountPoints == NULL)
927 {
928 RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
929 NtClose(FileHandle);
930 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
931 return FALSE;
932 }
933
934 Status = NtDeviceIoControlFile(FileHandle, NULL, NULL, NULL, &Iosb,
935 IOCTL_MOUNTMGR_QUERY_POINTS,
936 MountPoint, MountPointSize,
937 MountPoints, BufferLength);
938 if (!NT_SUCCESS(Status))
939 {
940 RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
941 if (Status == STATUS_BUFFER_OVERFLOW)
942 {
943 BufferLength = MountPoints->Size;
944 continue;
945 }
946 else if (!NT_SUCCESS(Status))
947 {
948 RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
949 NtClose(FileHandle);
950 SetLastErrorByStatus(Status);
951 return FALSE;
952 }
953 }
954 }
955 while (!NT_SUCCESS(Status));
956
957 RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
958 NtClose(FileHandle);
959
960 /*
961 * Now we've gathered info about all mount points mapped to our device, so
962 * select the correct one and copy it into the output buffer.
963 */
964
965 for (Index = 0; Index < MountPoints->NumberOfMountPoints; Index++)
966 {
967 MountPoint = MountPoints->MountPoints + Index;
968 SymbolicLinkName = (PUCHAR)MountPoints + MountPoint->SymbolicLinkNameOffset;
969
970 /*
971 * Check for "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
972 * (with the last slash being optional) style symbolic links.
973 */
974
975 if (MountPoint->SymbolicLinkNameLength == 48 * sizeof(WCHAR) ||
976 (MountPoint->SymbolicLinkNameLength == 49 * sizeof(WCHAR) &&
977 SymbolicLinkName[48] == L'\\'))
978 {
979 if (RtlCompareMemory(SymbolicLinkName, L"\\??\\Volume{",
980 11 * sizeof(WCHAR)) == 11 * sizeof(WCHAR) &&
981 SymbolicLinkName[19] == L'-' && SymbolicLinkName[24] == L'-' &&
982 SymbolicLinkName[29] == L'-' && SymbolicLinkName[34] == L'-' &&
983 SymbolicLinkName[47] == L'}')
984 {
985 if (VolumeNameLength >= MountPoint->SymbolicLinkNameLength / sizeof(WCHAR))
986 {
987 RtlCopyMemory(VolumeName,
988 (PUCHAR)MountPoints + MountPoint->SymbolicLinkNameOffset,
989 MountPoint->SymbolicLinkNameLength);
990 VolumeName[1] = L'\\';
991 Result = TRUE;
992 }
993 else
994 {
995 SetLastError(ERROR_FILENAME_EXCED_RANGE);
996 Result = FALSE;
997 }
998
999 RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
1000
1001 return Result;
1002 }
1003 }
1004 }
1005
1006 RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
1007 SetLastError(ERROR_INVALID_PARAMETER);
1008
1009 return FALSE;
1010 }
1011
1012 /* EOF */