update for HEAD-2003091401
[reactos.git] / 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 <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   UCHAR Buffer[max(FS_VOLUME_BUFFER_SIZE, FS_ATTRIBUTE_BUFFER_SIZE)];
608
609   HANDLE hFile;
610   NTSTATUS errCode;
611  
612   FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
613   FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
614
615   DPRINT("FileFsVolume %p\n", FileFsVolume);
616   DPRINT("FileFsAttribute %p\n", FileFsAttribute);
617
618   hFile = InternalOpenDirW(lpRootPathName, FALSE);
619   if (hFile == INVALID_HANDLE_VALUE)
620     {
621       return FALSE;
622     }
623
624   DPRINT("hFile: %x\n", hFile);
625   errCode = NtQueryVolumeInformationFile(hFile,
626                                          &IoStatusBlock,
627                                          FileFsVolume,
628                                          FS_VOLUME_BUFFER_SIZE,
629                                          FileFsVolumeInformation);
630   if ( !NT_SUCCESS(errCode) ) 
631     {
632       DPRINT("Status: %x\n", errCode);
633       CloseHandle(hFile);
634       SetLastErrorByStatus (errCode);
635       return FALSE;
636     }
637
638   if (lpVolumeSerialNumber)
639     *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
640
641   if (lpVolumeNameBuffer)
642     {
643       if (nVolumeNameSize * sizeof(WCHAR) >= FileFsVolume->VolumeLabelLength + sizeof(WCHAR))
644         {
645           memcpy(lpVolumeNameBuffer, 
646                  FileFsVolume->VolumeLabel, 
647                  FileFsVolume->VolumeLabelLength);
648           lpVolumeNameBuffer[FileFsVolume->VolumeLabelLength / sizeof(WCHAR)] = 0;
649         }
650       else
651         {
652           CloseHandle(hFile);
653           SetLastError(ERROR_MORE_DATA);
654           return FALSE;
655         }
656     }
657
658   errCode = NtQueryVolumeInformationFile (hFile,
659                                           &IoStatusBlock,
660                                           FileFsAttribute,
661                                           FS_ATTRIBUTE_BUFFER_SIZE,
662                                           FileFsAttributeInformation);
663   CloseHandle(hFile);
664   if (!NT_SUCCESS(errCode))
665     {
666       DPRINT("Status: %x\n", errCode);
667       SetLastErrorByStatus (errCode);
668       return FALSE;
669     }
670
671   if (lpFileSystemFlags)
672     *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
673   if (lpMaximumComponentLength)
674     *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
675   if (lpFileSystemNameBuffer)
676     {
677       if (nFileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
678         {
679           memcpy(lpFileSystemNameBuffer, 
680                  FileFsAttribute->FileSystemName, 
681                  FileFsAttribute->FileSystemNameLength);
682           lpFileSystemNameBuffer[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
683         }
684       else
685         {
686           SetLastError(ERROR_MORE_DATA);
687           return FALSE;
688         }
689     }
690   return TRUE;
691 }
692
693
694 /*
695  * @implemented
696  */
697 WINBOOL
698 STDCALL
699 SetVolumeLabelA (
700         LPCSTR  lpRootPathName,
701         LPCSTR  lpVolumeName
702         )
703 {
704         UNICODE_STRING RootPathNameU;
705         ANSI_STRING RootPathName;
706         UNICODE_STRING VolumeNameU;
707         ANSI_STRING VolumeName;
708         WINBOOL Result;
709
710         RtlInitAnsiString (&RootPathName,
711                            (LPSTR)lpRootPathName);
712         RtlInitAnsiString (&VolumeName,
713                            (LPSTR)lpVolumeName);
714
715         /* convert ansi (or oem) strings to unicode */
716         if (bIsFileApiAnsi)
717         {
718                 RtlAnsiStringToUnicodeString (&RootPathNameU,
719                                               &RootPathName,
720                                               TRUE);
721                 RtlAnsiStringToUnicodeString (&VolumeNameU,
722                                               &VolumeName,
723                                               TRUE);
724         }
725         else
726         {
727                 RtlOemStringToUnicodeString (&RootPathNameU,
728                                              &RootPathName,
729                                              TRUE);
730                 RtlOemStringToUnicodeString (&VolumeNameU,
731                                              &VolumeName,
732                                              TRUE);
733         }
734
735         Result = SetVolumeLabelW (RootPathNameU.Buffer,
736                                   VolumeNameU.Buffer);
737
738         RtlFreeHeap (RtlGetProcessHeap (),
739                      0,
740                      RootPathNameU.Buffer);
741         RtlFreeHeap (RtlGetProcessHeap (),
742                      0,
743                      VolumeNameU.Buffer);
744
745         return Result;
746 }
747
748
749 /*
750  * @implemented
751  */
752 WINBOOL STDCALL
753 SetVolumeLabelW(LPCWSTR lpRootPathName,
754                 LPCWSTR lpVolumeName)
755 {
756    PFILE_FS_LABEL_INFORMATION LabelInfo;
757    IO_STATUS_BLOCK IoStatusBlock;
758    ULONG LabelLength;
759    HANDLE hFile;
760    NTSTATUS Status;
761    
762    LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
763    LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
764                                0,
765                                sizeof(FILE_FS_LABEL_INFORMATION) +
766                                LabelLength);
767    LabelInfo->VolumeLabelLength = LabelLength;
768    memcpy(LabelInfo->VolumeLabel,
769           lpVolumeName,
770           LabelLength);
771
772    hFile = InternalOpenDirW(lpRootPathName, TRUE);
773    if (INVALID_HANDLE_VALUE == hFile)
774    {
775         RtlFreeHeap(RtlGetProcessHeap(),
776                     0,
777                     LabelInfo);
778         return FALSE;
779    }
780    
781    Status = NtSetVolumeInformationFile(hFile,
782                                        &IoStatusBlock,
783                                        LabelInfo,
784                                        sizeof(FILE_FS_LABEL_INFORMATION) +
785                                        LabelLength,
786                                        FileFsLabelInformation);
787
788    RtlFreeHeap(RtlGetProcessHeap(),
789                0,
790                LabelInfo);
791
792    if (!NT_SUCCESS(Status))
793      {
794         DPRINT("Status: %x\n", Status);
795         CloseHandle(hFile);
796         SetLastErrorByStatus(Status);
797         return FALSE;
798      }
799
800    CloseHandle(hFile);
801    return TRUE;
802 }
803
804 /* EOF */