- Fixed GetVolumeInformationA/W.
[reactos.git] / reactos / lib / kernel32 / file / volume.c
1 /* $Id: volume.c,v 1.30 2003/07/20 09:40:13 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 <k32.h>
23
24 #define NDEBUG
25 #include <kernel32/kernel32.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 = SharedUserData->DosDeviceMap;
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 = SharedUserData->DosDeviceMap;
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 return(SharedUserData->DosDeviceMap);
159 }
160
161
162 /*
163 * @implemented
164 */
165 WINBOOL STDCALL
166 GetDiskFreeSpaceA (
167 LPCSTR lpRootPathName,
168 LPDWORD lpSectorsPerCluster,
169 LPDWORD lpBytesPerSector,
170 LPDWORD lpNumberOfFreeClusters,
171 LPDWORD lpTotalNumberOfClusters
172 )
173 {
174 UNICODE_STRING RootPathNameU;
175 ANSI_STRING RootPathName;
176 WINBOOL Result;
177
178 RtlInitAnsiString (&RootPathName,
179 (LPSTR)lpRootPathName);
180
181 RtlInitUnicodeString (&RootPathNameU,
182 NULL);
183
184 if (lpRootPathName)
185 {
186 /* convert ansi (or oem) string to unicode */
187 if (bIsFileApiAnsi)
188 RtlAnsiStringToUnicodeString (&RootPathNameU,
189 &RootPathName,
190 TRUE);
191 else
192 RtlOemStringToUnicodeString (&RootPathNameU,
193 &RootPathName,
194 TRUE);
195 }
196
197 Result = GetDiskFreeSpaceW (RootPathNameU.Buffer,
198 lpSectorsPerCluster,
199 lpBytesPerSector,
200 lpNumberOfFreeClusters,
201 lpTotalNumberOfClusters);
202
203 if (lpRootPathName)
204 {
205 RtlFreeHeap (RtlGetProcessHeap (),
206 0,
207 RootPathNameU.Buffer);
208 }
209
210 return Result;
211 }
212
213
214 /*
215 * @implemented
216 */
217 WINBOOL STDCALL
218 GetDiskFreeSpaceW(
219 LPCWSTR lpRootPathName,
220 LPDWORD lpSectorsPerCluster,
221 LPDWORD lpBytesPerSector,
222 LPDWORD lpNumberOfFreeClusters,
223 LPDWORD lpTotalNumberOfClusters
224 )
225 {
226 FILE_FS_SIZE_INFORMATION FileFsSize;
227 IO_STATUS_BLOCK IoStatusBlock;
228 WCHAR RootPathName[MAX_PATH];
229 HANDLE hFile;
230 NTSTATUS errCode;
231
232 if (lpRootPathName)
233 {
234 wcsncpy (RootPathName, lpRootPathName, 3);
235 }
236 else
237 {
238 GetCurrentDirectoryW (MAX_PATH, RootPathName);
239 RootPathName[3] = 0;
240 }
241
242 hFile = InternalOpenDirW(lpRootPathName, FALSE);
243 if (INVALID_HANDLE_VALUE == hFile)
244 {
245 return FALSE;
246 }
247
248 errCode = NtQueryVolumeInformationFile(hFile,
249 &IoStatusBlock,
250 &FileFsSize,
251 sizeof(FILE_FS_SIZE_INFORMATION),
252 FileFsSizeInformation);
253 if (!NT_SUCCESS(errCode))
254 {
255 CloseHandle(hFile);
256 SetLastErrorByStatus (errCode);
257 return FALSE;
258 }
259
260 *lpBytesPerSector = FileFsSize.BytesPerSector;
261 *lpSectorsPerCluster = FileFsSize.SectorsPerAllocationUnit;
262 *lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.u.LowPart;
263 *lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.u.LowPart;
264 CloseHandle(hFile);
265 return TRUE;
266 }
267
268
269 /*
270 * @implemented
271 */
272 WINBOOL STDCALL
273 GetDiskFreeSpaceExA (
274 LPCSTR lpDirectoryName,
275 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
276 PULARGE_INTEGER lpTotalNumberOfBytes,
277 PULARGE_INTEGER lpTotalNumberOfFreeBytes
278 )
279 {
280 UNICODE_STRING DirectoryNameU;
281 ANSI_STRING DirectoryName;
282 WINBOOL Result;
283
284 RtlInitAnsiString (&DirectoryName,
285 (LPSTR)lpDirectoryName);
286
287 RtlInitUnicodeString (&DirectoryNameU,
288 NULL);
289
290 if (lpDirectoryName)
291 {
292 /* convert ansi (or oem) string to unicode */
293 if (bIsFileApiAnsi)
294 RtlAnsiStringToUnicodeString (&DirectoryNameU,
295 &DirectoryName,
296 TRUE);
297 else
298 RtlOemStringToUnicodeString (&DirectoryNameU,
299 &DirectoryName,
300 TRUE);
301 }
302
303 Result = GetDiskFreeSpaceExW (DirectoryNameU.Buffer,
304 lpFreeBytesAvailableToCaller,
305 lpTotalNumberOfBytes,
306 lpTotalNumberOfFreeBytes);
307
308 if (lpDirectoryName)
309 {
310 RtlFreeHeap (RtlGetProcessHeap (),
311 0,
312 DirectoryNameU.Buffer);
313 }
314
315 return Result;
316 }
317
318
319 /*
320 * @implemented
321 */
322 WINBOOL STDCALL
323 GetDiskFreeSpaceExW(
324 LPCWSTR lpDirectoryName,
325 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
326 PULARGE_INTEGER lpTotalNumberOfBytes,
327 PULARGE_INTEGER lpTotalNumberOfFreeBytes
328 )
329 {
330 FILE_FS_SIZE_INFORMATION FileFsSize;
331 IO_STATUS_BLOCK IoStatusBlock;
332 ULARGE_INTEGER BytesPerCluster;
333 WCHAR RootPathName[MAX_PATH];
334 HANDLE hFile;
335 NTSTATUS errCode;
336
337 if (lpDirectoryName)
338 {
339 wcsncpy (RootPathName, lpDirectoryName, 3);
340 }
341 else
342 {
343 GetCurrentDirectoryW (MAX_PATH, RootPathName);
344 RootPathName[3] = 0;
345 }
346
347 hFile = InternalOpenDirW(lpDirectoryName, FALSE);
348 if (INVALID_HANDLE_VALUE == hFile)
349 {
350 return FALSE;
351 }
352
353 errCode = NtQueryVolumeInformationFile(hFile,
354 &IoStatusBlock,
355 &FileFsSize,
356 sizeof(FILE_FS_SIZE_INFORMATION),
357 FileFsSizeInformation);
358 if (!NT_SUCCESS(errCode))
359 {
360 CloseHandle(hFile);
361 SetLastErrorByStatus (errCode);
362 return FALSE;
363 }
364
365 BytesPerCluster.QuadPart =
366 FileFsSize.BytesPerSector * FileFsSize.SectorsPerAllocationUnit;
367
368 // FIXME: Use quota information
369 if (lpFreeBytesAvailableToCaller)
370 lpFreeBytesAvailableToCaller->QuadPart =
371 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
372
373 if (lpTotalNumberOfBytes)
374 lpTotalNumberOfBytes->QuadPart =
375 BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.QuadPart;
376 if (lpTotalNumberOfFreeBytes)
377 lpTotalNumberOfFreeBytes->QuadPart =
378 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
379
380 CloseHandle(hFile);
381 return TRUE;
382 }
383
384
385 /*
386 * @implemented
387 */
388 UINT STDCALL
389 GetDriveTypeA(LPCSTR lpRootPathName)
390 {
391 UNICODE_STRING RootPathNameU;
392 ANSI_STRING RootPathName;
393 UINT Result;
394
395 RtlInitAnsiString (&RootPathName,
396 (LPSTR)lpRootPathName);
397
398 /* convert ansi (or oem) string to unicode */
399 if (bIsFileApiAnsi)
400 RtlAnsiStringToUnicodeString (&RootPathNameU,
401 &RootPathName,
402 TRUE);
403 else
404 RtlOemStringToUnicodeString (&RootPathNameU,
405 &RootPathName,
406 TRUE);
407
408 Result = GetDriveTypeW (RootPathNameU.Buffer);
409
410 RtlFreeHeap (RtlGetProcessHeap (),
411 0,
412 RootPathNameU.Buffer);
413
414 return Result;
415 }
416
417
418 /*
419 * @implemented
420 */
421 UINT STDCALL
422 GetDriveTypeW(LPCWSTR lpRootPathName)
423 {
424 FILE_FS_DEVICE_INFORMATION FileFsDevice;
425 IO_STATUS_BLOCK IoStatusBlock;
426
427 HANDLE hFile;
428 NTSTATUS errCode;
429
430 hFile = InternalOpenDirW(lpRootPathName, FALSE);
431 if (hFile == INVALID_HANDLE_VALUE)
432 {
433 return 0;
434 }
435
436 errCode = NtQueryVolumeInformationFile (hFile,
437 &IoStatusBlock,
438 &FileFsDevice,
439 sizeof(FILE_FS_DEVICE_INFORMATION),
440 FileFsDeviceInformation);
441 if (!NT_SUCCESS(errCode))
442 {
443 CloseHandle(hFile);
444 SetLastErrorByStatus (errCode);
445 return 0;
446 }
447 CloseHandle(hFile);
448 return (UINT)FileFsDevice.DeviceType;
449 }
450
451
452 /*
453 * @implemented
454 */
455 WINBOOL STDCALL
456 GetVolumeInformationA(
457 LPCSTR lpRootPathName,
458 LPSTR lpVolumeNameBuffer,
459 DWORD nVolumeNameSize,
460 LPDWORD lpVolumeSerialNumber,
461 LPDWORD lpMaximumComponentLength,
462 LPDWORD lpFileSystemFlags,
463 LPSTR lpFileSystemNameBuffer,
464 DWORD nFileSystemNameSize
465 )
466 {
467 UNICODE_STRING RootPathNameU;
468 UNICODE_STRING FileSystemNameU;
469 UNICODE_STRING VolumeNameU;
470 ANSI_STRING RootPathName;
471 ANSI_STRING VolumeName;
472 ANSI_STRING FileSystemName;
473 WINBOOL Result;
474
475 RtlInitAnsiString (&RootPathName,
476 (LPSTR)lpRootPathName);
477
478 /* convert ansi (or oem) string to unicode */
479 if (bIsFileApiAnsi)
480 RtlAnsiStringToUnicodeString (&RootPathNameU,
481 &RootPathName,
482 TRUE);
483 else
484 RtlOemStringToUnicodeString (&RootPathNameU,
485 &RootPathName,
486 TRUE);
487
488 if (lpVolumeNameBuffer)
489 {
490 VolumeNameU.Length = 0;
491 VolumeNameU.MaximumLength = nVolumeNameSize * sizeof(WCHAR);
492 VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
493 0,
494 VolumeNameU.MaximumLength);
495 }
496
497 if (lpFileSystemNameBuffer)
498 {
499 FileSystemNameU.Length = 0;
500 FileSystemNameU.MaximumLength = nFileSystemNameSize * sizeof(WCHAR);
501 FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
502 0,
503 FileSystemNameU.MaximumLength);
504 }
505
506 Result = GetVolumeInformationW (RootPathNameU.Buffer,
507 lpVolumeNameBuffer ? VolumeNameU.Buffer : NULL,
508 nVolumeNameSize,
509 lpVolumeSerialNumber,
510 lpMaximumComponentLength,
511 lpFileSystemFlags,
512 lpFileSystemNameBuffer ? FileSystemNameU.Buffer : NULL,
513 nFileSystemNameSize);
514
515 if (Result)
516 {
517 if (lpVolumeNameBuffer)
518 {
519 VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR);
520 VolumeName.Length = 0;
521 VolumeName.MaximumLength = nVolumeNameSize;
522 VolumeName.Buffer = lpVolumeNameBuffer;
523 }
524
525 if (lpFileSystemNameBuffer)
526 {
527 FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR);
528 FileSystemName.Length = 0;
529 FileSystemName.MaximumLength = nFileSystemNameSize;
530 FileSystemName.Buffer = lpFileSystemNameBuffer;
531 }
532
533 /* convert unicode strings to ansi (or oem) */
534 if (bIsFileApiAnsi)
535 {
536 if (lpVolumeNameBuffer)
537 {
538 RtlUnicodeStringToAnsiString (&VolumeName,
539 &VolumeNameU,
540 FALSE);
541 }
542 if (lpFileSystemNameBuffer)
543 {
544 RtlUnicodeStringToAnsiString (&FileSystemName,
545 &FileSystemNameU,
546 FALSE);
547 }
548 }
549 else
550 {
551 if (lpVolumeNameBuffer)
552 {
553 RtlUnicodeStringToOemString (&VolumeName,
554 &VolumeNameU,
555 FALSE);
556 }
557 if (lpFileSystemNameBuffer)
558 {
559 RtlUnicodeStringToOemString (&FileSystemName,
560 &FileSystemNameU,
561 FALSE);
562 }
563 }
564 }
565
566 RtlFreeHeap (RtlGetProcessHeap (),
567 0,
568 RootPathNameU.Buffer);
569 if (lpVolumeNameBuffer)
570 {
571 RtlFreeHeap (RtlGetProcessHeap (),
572 0,
573 VolumeNameU.Buffer);
574 }
575 if (lpFileSystemNameBuffer)
576 {
577 RtlFreeHeap (RtlGetProcessHeap (),
578 0,
579 FileSystemNameU.Buffer);
580 }
581
582 return Result;
583 }
584
585 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
586
587 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
588
589 /*
590 * @implemented
591 */
592 WINBOOL STDCALL
593 GetVolumeInformationW(
594 LPCWSTR lpRootPathName,
595 LPWSTR lpVolumeNameBuffer,
596 DWORD nVolumeNameSize,
597 LPDWORD lpVolumeSerialNumber,
598 LPDWORD lpMaximumComponentLength,
599 LPDWORD lpFileSystemFlags,
600 LPWSTR lpFileSystemNameBuffer,
601 DWORD nFileSystemNameSize
602 )
603 {
604 PFILE_FS_VOLUME_INFORMATION FileFsVolume;
605 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
606 IO_STATUS_BLOCK IoStatusBlock;
607 OBJECT_ATTRIBUTES ObjectAttributes;
608 UCHAR Buffer[max(FS_VOLUME_BUFFER_SIZE, FS_ATTRIBUTE_BUFFER_SIZE)];
609
610 HANDLE hFile;
611 NTSTATUS errCode;
612
613 FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
614 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
615
616 DPRINT("FileFsVolume %p\n", FileFsVolume);
617 DPRINT("FileFsAttribute %p\n", FileFsAttribute);
618
619 hFile = InternalOpenDirW(lpRootPathName, FALSE);
620 if (hFile == INVALID_HANDLE_VALUE)
621 {
622 return FALSE;
623 }
624
625 DPRINT("hFile: %x\n", hFile);
626 errCode = NtQueryVolumeInformationFile(hFile,
627 &IoStatusBlock,
628 FileFsVolume,
629 FS_VOLUME_BUFFER_SIZE,
630 FileFsVolumeInformation);
631 if ( !NT_SUCCESS(errCode) )
632 {
633 DPRINT("Status: %x\n", errCode);
634 CloseHandle(hFile);
635 SetLastErrorByStatus (errCode);
636 return FALSE;
637 }
638
639 if (lpVolumeSerialNumber)
640 *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
641
642 if (lpVolumeNameBuffer)
643 {
644 if (nVolumeNameSize * sizeof(WCHAR) >= FileFsVolume->VolumeLabelLength + sizeof(WCHAR))
645 {
646 memcpy(lpVolumeNameBuffer,
647 FileFsVolume->VolumeLabel,
648 FileFsVolume->VolumeLabelLength);
649 lpVolumeNameBuffer[FileFsVolume->VolumeLabelLength / sizeof(WCHAR)];
650 }
651 else
652 {
653 CloseHandle(hFile);
654 SetLastError(ERROR_MORE_DATA);
655 return FALSE;
656 }
657 }
658
659 errCode = NtQueryVolumeInformationFile (hFile,
660 &IoStatusBlock,
661 FileFsAttribute,
662 FS_ATTRIBUTE_BUFFER_SIZE,
663 FileFsAttributeInformation);
664 CloseHandle(hFile);
665 if (!NT_SUCCESS(errCode))
666 {
667 DPRINT("Status: %x\n", errCode);
668 SetLastErrorByStatus (errCode);
669 return FALSE;
670 }
671
672 if (lpFileSystemFlags)
673 *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
674 if (lpMaximumComponentLength)
675 *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
676 if (lpFileSystemNameBuffer)
677 {
678 if (nFileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
679 {
680 memcpy(lpFileSystemNameBuffer,
681 FileFsAttribute->FileSystemName,
682 FileFsAttribute->FileSystemNameLength);
683 lpFileSystemNameBuffer[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
684 }
685 else
686 {
687 SetLastError(ERROR_MORE_DATA);
688 return FALSE;
689 }
690 }
691 return TRUE;
692 }
693
694
695 /*
696 * @implemented
697 */
698 WINBOOL
699 STDCALL
700 SetVolumeLabelA (
701 LPCSTR lpRootPathName,
702 LPCSTR lpVolumeName
703 )
704 {
705 UNICODE_STRING RootPathNameU;
706 ANSI_STRING RootPathName;
707 UNICODE_STRING VolumeNameU;
708 ANSI_STRING VolumeName;
709 WINBOOL Result;
710
711 RtlInitAnsiString (&RootPathName,
712 (LPSTR)lpRootPathName);
713 RtlInitAnsiString (&VolumeName,
714 (LPSTR)lpVolumeName);
715
716 /* convert ansi (or oem) strings to unicode */
717 if (bIsFileApiAnsi)
718 {
719 RtlAnsiStringToUnicodeString (&RootPathNameU,
720 &RootPathName,
721 TRUE);
722 RtlAnsiStringToUnicodeString (&VolumeNameU,
723 &VolumeName,
724 TRUE);
725 }
726 else
727 {
728 RtlOemStringToUnicodeString (&RootPathNameU,
729 &RootPathName,
730 TRUE);
731 RtlOemStringToUnicodeString (&VolumeNameU,
732 &VolumeName,
733 TRUE);
734 }
735
736 Result = SetVolumeLabelW (RootPathNameU.Buffer,
737 VolumeNameU.Buffer);
738
739 RtlFreeHeap (RtlGetProcessHeap (),
740 0,
741 RootPathNameU.Buffer);
742 RtlFreeHeap (RtlGetProcessHeap (),
743 0,
744 VolumeNameU.Buffer);
745
746 return Result;
747 }
748
749
750 /*
751 * @implemented
752 */
753 WINBOOL STDCALL
754 SetVolumeLabelW(LPCWSTR lpRootPathName,
755 LPCWSTR lpVolumeName)
756 {
757 PFILE_FS_LABEL_INFORMATION LabelInfo;
758 IO_STATUS_BLOCK IoStatusBlock;
759 ULONG LabelLength;
760 HANDLE hFile;
761 NTSTATUS Status;
762
763 LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
764 LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
765 0,
766 sizeof(FILE_FS_LABEL_INFORMATION) +
767 LabelLength);
768 LabelInfo->VolumeLabelLength = LabelLength;
769 memcpy(LabelInfo->VolumeLabel,
770 lpVolumeName,
771 LabelLength);
772
773 hFile = InternalOpenDirW(lpRootPathName, TRUE);
774 if (INVALID_HANDLE_VALUE == hFile)
775 {
776 RtlFreeHeap(RtlGetProcessHeap(),
777 0,
778 LabelInfo);
779 return FALSE;
780 }
781
782 Status = NtSetVolumeInformationFile(hFile,
783 &IoStatusBlock,
784 LabelInfo,
785 sizeof(FILE_FS_LABEL_INFORMATION) +
786 LabelLength,
787 FileFsLabelInformation);
788
789 RtlFreeHeap(RtlGetProcessHeap(),
790 0,
791 LabelInfo);
792
793 if (!NT_SUCCESS(Status))
794 {
795 DPRINT("Status: %x\n", Status);
796 CloseHandle(hFile);
797 SetLastErrorByStatus(Status);
798 return FALSE;
799 }
800
801 CloseHandle(hFile);
802 return TRUE;
803 }
804
805 /* EOF */