merge ROS Shell without integrated explorer part into trunk
[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;
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.Length = 0;
459 VolumeNameU.MaximumLength = nVolumeNameSize * sizeof(WCHAR);
460 VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
461 0,
462 VolumeNameU.MaximumLength);
463 }
464
465 if (lpFileSystemNameBuffer)
466 {
467 FileSystemNameU.Length = 0;
468 FileSystemNameU.MaximumLength = nFileSystemNameSize * sizeof(WCHAR);
469 FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
470 0,
471 FileSystemNameU.MaximumLength);
472 }
473
474 Result = GetVolumeInformationW (RootPathNameW,
475 lpVolumeNameBuffer ? VolumeNameU.Buffer : NULL,
476 nVolumeNameSize,
477 lpVolumeSerialNumber,
478 lpMaximumComponentLength,
479 lpFileSystemFlags,
480 lpFileSystemNameBuffer ? FileSystemNameU.Buffer : NULL,
481 nFileSystemNameSize);
482
483 if (Result)
484 {
485 if (lpVolumeNameBuffer)
486 {
487 VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR);
488 VolumeName.Length = 0;
489 VolumeName.MaximumLength = nVolumeNameSize;
490 VolumeName.Buffer = lpVolumeNameBuffer;
491 }
492
493 if (lpFileSystemNameBuffer)
494 {
495 FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR);
496 FileSystemName.Length = 0;
497 FileSystemName.MaximumLength = nFileSystemNameSize;
498 FileSystemName.Buffer = lpFileSystemNameBuffer;
499 }
500
501 /* convert unicode strings to ansi (or oem) */
502 if (bIsFileApiAnsi)
503 {
504 if (lpVolumeNameBuffer)
505 {
506 RtlUnicodeStringToAnsiString (&VolumeName,
507 &VolumeNameU,
508 FALSE);
509 }
510 if (lpFileSystemNameBuffer)
511 {
512 RtlUnicodeStringToAnsiString (&FileSystemName,
513 &FileSystemNameU,
514 FALSE);
515 }
516 }
517 else
518 {
519 if (lpVolumeNameBuffer)
520 {
521 RtlUnicodeStringToOemString (&VolumeName,
522 &VolumeNameU,
523 FALSE);
524 }
525 if (lpFileSystemNameBuffer)
526 {
527 RtlUnicodeStringToOemString (&FileSystemName,
528 &FileSystemNameU,
529 FALSE);
530 }
531 }
532 }
533
534 if (lpVolumeNameBuffer)
535 {
536 RtlFreeHeap (RtlGetProcessHeap (),
537 0,
538 VolumeNameU.Buffer);
539 }
540 if (lpFileSystemNameBuffer)
541 {
542 RtlFreeHeap (RtlGetProcessHeap (),
543 0,
544 FileSystemNameU.Buffer);
545 }
546
547 return Result;
548 }
549
550 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
551
552 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
553
554 /*
555 * @implemented
556 */
557 BOOL STDCALL
558 GetVolumeInformationW(
559 LPCWSTR lpRootPathName,
560 LPWSTR lpVolumeNameBuffer,
561 DWORD nVolumeNameSize,
562 LPDWORD lpVolumeSerialNumber,
563 LPDWORD lpMaximumComponentLength,
564 LPDWORD lpFileSystemFlags,
565 LPWSTR lpFileSystemNameBuffer,
566 DWORD nFileSystemNameSize
567 )
568 {
569 PFILE_FS_VOLUME_INFORMATION FileFsVolume;
570 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
571 IO_STATUS_BLOCK IoStatusBlock;
572 WCHAR RootPathName[MAX_PATH];
573 UCHAR Buffer[max(FS_VOLUME_BUFFER_SIZE, FS_ATTRIBUTE_BUFFER_SIZE)];
574
575 HANDLE hFile;
576 NTSTATUS errCode;
577
578 FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
579 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
580
581 DPRINT("FileFsVolume %p\n", FileFsVolume);
582 DPRINT("FileFsAttribute %p\n", FileFsAttribute);
583
584 if (!lpRootPathName || !wcscmp(lpRootPathName, L""))
585 {
586 GetCurrentDirectoryW (MAX_PATH, RootPathName);
587 }
588 else
589 {
590 wcsncpy (RootPathName, lpRootPathName, 3);
591 }
592 RootPathName[3] = 0;
593
594 hFile = InternalOpenDirW(RootPathName, FALSE);
595 if (hFile == INVALID_HANDLE_VALUE)
596 {
597 return FALSE;
598 }
599
600 DPRINT("hFile: %x\n", hFile);
601 errCode = NtQueryVolumeInformationFile(hFile,
602 &IoStatusBlock,
603 FileFsVolume,
604 FS_VOLUME_BUFFER_SIZE,
605 FileFsVolumeInformation);
606 if ( !NT_SUCCESS(errCode) )
607 {
608 DPRINT("Status: %x\n", errCode);
609 CloseHandle(hFile);
610 SetLastErrorByStatus (errCode);
611 return FALSE;
612 }
613
614 if (lpVolumeSerialNumber)
615 *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
616
617 if (lpVolumeNameBuffer)
618 {
619 if (nVolumeNameSize * sizeof(WCHAR) >= FileFsVolume->VolumeLabelLength + sizeof(WCHAR))
620 {
621 memcpy(lpVolumeNameBuffer,
622 FileFsVolume->VolumeLabel,
623 FileFsVolume->VolumeLabelLength);
624 lpVolumeNameBuffer[FileFsVolume->VolumeLabelLength / sizeof(WCHAR)] = 0;
625 }
626 else
627 {
628 CloseHandle(hFile);
629 SetLastError(ERROR_MORE_DATA);
630 return FALSE;
631 }
632 }
633
634 errCode = NtQueryVolumeInformationFile (hFile,
635 &IoStatusBlock,
636 FileFsAttribute,
637 FS_ATTRIBUTE_BUFFER_SIZE,
638 FileFsAttributeInformation);
639 CloseHandle(hFile);
640 if (!NT_SUCCESS(errCode))
641 {
642 DPRINT("Status: %x\n", errCode);
643 SetLastErrorByStatus (errCode);
644 return FALSE;
645 }
646
647 if (lpFileSystemFlags)
648 *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
649 if (lpMaximumComponentLength)
650 *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
651 if (lpFileSystemNameBuffer)
652 {
653 if (nFileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
654 {
655 memcpy(lpFileSystemNameBuffer,
656 FileFsAttribute->FileSystemName,
657 FileFsAttribute->FileSystemNameLength);
658 lpFileSystemNameBuffer[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
659 }
660 else
661 {
662 SetLastError(ERROR_MORE_DATA);
663 return FALSE;
664 }
665 }
666 return TRUE;
667 }
668
669
670 /*
671 * @implemented
672 */
673 BOOL
674 STDCALL
675 SetVolumeLabelA (
676 LPCSTR lpRootPathName,
677 LPCSTR lpVolumeName /* NULL if deleting label */
678 )
679 {
680 PWCHAR RootPathNameW;
681 PWCHAR VolumeNameW = NULL;
682 BOOL Result;
683
684 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
685 return FALSE;
686
687 if (lpVolumeName)
688 {
689 if (!(VolumeNameW = FilenameA2W(lpVolumeName, TRUE)))
690 return FALSE;
691 }
692
693 Result = SetVolumeLabelW (RootPathNameW,
694 VolumeNameW);
695
696 if (VolumeNameW)
697 {
698 RtlFreeHeap (RtlGetProcessHeap (),
699 0,
700 VolumeNameW );
701 }
702
703 return Result;
704 }
705
706
707 /*
708 * @implemented
709 */
710 BOOL STDCALL
711 SetVolumeLabelW(
712 LPCWSTR lpRootPathName,
713 LPCWSTR lpVolumeName /* NULL if deleting label */
714 )
715 {
716 PFILE_FS_LABEL_INFORMATION LabelInfo;
717 IO_STATUS_BLOCK IoStatusBlock;
718 ULONG LabelLength;
719 HANDLE hFile;
720 NTSTATUS Status;
721
722 LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
723 LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
724 0,
725 sizeof(FILE_FS_LABEL_INFORMATION) +
726 LabelLength);
727 LabelInfo->VolumeLabelLength = LabelLength;
728 memcpy(LabelInfo->VolumeLabel,
729 lpVolumeName,
730 LabelLength);
731
732 hFile = InternalOpenDirW(lpRootPathName, TRUE);
733 if (INVALID_HANDLE_VALUE == hFile)
734 {
735 RtlFreeHeap(RtlGetProcessHeap(),
736 0,
737 LabelInfo);
738 return FALSE;
739 }
740
741 Status = NtSetVolumeInformationFile(hFile,
742 &IoStatusBlock,
743 LabelInfo,
744 sizeof(FILE_FS_LABEL_INFORMATION) +
745 LabelLength,
746 FileFsLabelInformation);
747
748 RtlFreeHeap(RtlGetProcessHeap(),
749 0,
750 LabelInfo);
751
752 if (!NT_SUCCESS(Status))
753 {
754 DPRINT("Status: %x\n", Status);
755 CloseHandle(hFile);
756 SetLastErrorByStatus(Status);
757 return FALSE;
758 }
759
760 CloseHandle(hFile);
761 return TRUE;
762 }
763
764 /* EOF */