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
14 //WINE copyright notice:
16 * DOS drives handling functions
18 * Copyright 1993 Erik Bos
19 * Copyright 1996 Alexandre Julliard
25 #include "../include/debug.h"
28 #define MAX_DOS_DRIVES 26
32 InternalOpenDirW(LPCWSTR DirName
,
35 UNICODE_STRING NtPathU
;
36 OBJECT_ATTRIBUTES ObjectAttributes
;
38 IO_STATUS_BLOCK IoStatusBlock
;
41 if (!RtlDosPathNameToNtPathName_U((LPWSTR
)DirName
,
46 DPRINT("Invalid path\n");
47 SetLastError(ERROR_BAD_PATHNAME
);
48 return INVALID_HANDLE_VALUE
;
51 InitializeObjectAttributes(&ObjectAttributes
,
53 Write
? FILE_WRITE_ATTRIBUTES
: FILE_READ_ATTRIBUTES
,
57 errCode
= NtCreateFile (&hFile
,
58 Write
? FILE_GENERIC_WRITE
: FILE_GENERIC_READ
,
63 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
69 RtlFreeUnicodeString(&NtPathU
);
71 if (!NT_SUCCESS(errCode
))
73 SetLastErrorByStatus (errCode
);
74 return INVALID_HANDLE_VALUE
;
84 GetLogicalDriveStringsA(DWORD nBufferLength
,
90 dwDriveMap
= GetLogicalDrives();
92 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
94 if (dwDriveMap
& (1<<drive
))
99 if (count
* 4 * sizeof(char) <= nBufferLength
)
103 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
104 if (dwDriveMap
& (1<<drive
))
113 return (count
* 4 * sizeof(char));
121 GetLogicalDriveStringsW(DWORD nBufferLength
,
127 dwDriveMap
= GetLogicalDrives();
129 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
131 if (dwDriveMap
& (1<<drive
))
135 if (count
* 4 * sizeof(WCHAR
) <= nBufferLength
)
138 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
139 if (dwDriveMap
& (1<<drive
))
141 *p
++ = (WCHAR
)('A' + drive
);
148 return (count
* 4 * sizeof(WCHAR
));
156 GetLogicalDrives(VOID
)
159 PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo
;
161 /* Get the Device Map for this Process */
162 Status
= NtQueryInformationProcess(NtCurrentProcess(),
164 &ProcessDeviceMapInfo
,
165 sizeof(ProcessDeviceMapInfo
),
168 /* Return the Drive Map */
169 if (!NT_SUCCESS(Status
))
171 SetLastErrorByStatus(Status
);
175 return ProcessDeviceMapInfo
.Query
.DriveMap
;
184 LPCSTR lpRootPathName
,
185 LPDWORD lpSectorsPerCluster
,
186 LPDWORD lpBytesPerSector
,
187 LPDWORD lpNumberOfFreeClusters
,
188 LPDWORD lpTotalNumberOfClusters
191 UNICODE_STRING RootPathNameU
;
192 ANSI_STRING RootPathName
;
195 RtlInitAnsiString (&RootPathName
,
196 (LPSTR
)lpRootPathName
);
198 RtlInitUnicodeString (&RootPathNameU
,
203 /* convert ansi (or oem) string to unicode */
205 RtlAnsiStringToUnicodeString (&RootPathNameU
,
209 RtlOemStringToUnicodeString (&RootPathNameU
,
214 Result
= GetDiskFreeSpaceW (RootPathNameU
.Buffer
,
217 lpNumberOfFreeClusters
,
218 lpTotalNumberOfClusters
);
222 RtlFreeHeap (RtlGetProcessHeap (),
224 RootPathNameU
.Buffer
);
236 LPCWSTR lpRootPathName
,
237 LPDWORD lpSectorsPerCluster
,
238 LPDWORD lpBytesPerSector
,
239 LPDWORD lpNumberOfFreeClusters
,
240 LPDWORD lpTotalNumberOfClusters
243 FILE_FS_SIZE_INFORMATION FileFsSize
;
244 IO_STATUS_BLOCK IoStatusBlock
;
245 WCHAR RootPathName
[MAX_PATH
];
251 wcsncpy (RootPathName
, lpRootPathName
, 3);
255 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
259 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
260 if (INVALID_HANDLE_VALUE
== hFile
)
262 SetLastError(ERROR_PATH_NOT_FOUND
);
266 errCode
= NtQueryVolumeInformationFile(hFile
,
269 sizeof(FILE_FS_SIZE_INFORMATION
),
270 FileFsSizeInformation
);
271 if (!NT_SUCCESS(errCode
))
274 SetLastErrorByStatus (errCode
);
278 *lpBytesPerSector
= FileFsSize
.BytesPerSector
;
279 *lpSectorsPerCluster
= FileFsSize
.SectorsPerAllocationUnit
;
280 *lpNumberOfFreeClusters
= FileFsSize
.AvailableAllocationUnits
.u
.LowPart
;
281 *lpTotalNumberOfClusters
= FileFsSize
.TotalAllocationUnits
.u
.LowPart
;
292 GetDiskFreeSpaceExA (
293 LPCSTR lpDirectoryName
,
294 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
295 PULARGE_INTEGER lpTotalNumberOfBytes
,
296 PULARGE_INTEGER lpTotalNumberOfFreeBytes
299 UNICODE_STRING DirectoryNameU
;
300 ANSI_STRING DirectoryName
;
303 RtlInitAnsiString (&DirectoryName
,
304 (LPSTR
)lpDirectoryName
);
306 RtlInitUnicodeString (&DirectoryNameU
,
311 /* convert ansi (or oem) string to unicode */
313 RtlAnsiStringToUnicodeString (&DirectoryNameU
,
317 RtlOemStringToUnicodeString (&DirectoryNameU
,
322 Result
= GetDiskFreeSpaceExW (DirectoryNameU
.Buffer
,
323 lpFreeBytesAvailableToCaller
,
324 lpTotalNumberOfBytes
,
325 lpTotalNumberOfFreeBytes
);
329 RtlFreeHeap (RtlGetProcessHeap (),
331 DirectoryNameU
.Buffer
);
343 LPCWSTR lpDirectoryName
,
344 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
345 PULARGE_INTEGER lpTotalNumberOfBytes
,
346 PULARGE_INTEGER lpTotalNumberOfFreeBytes
349 FILE_FS_SIZE_INFORMATION FileFsSize
;
350 IO_STATUS_BLOCK IoStatusBlock
;
351 ULARGE_INTEGER BytesPerCluster
;
352 WCHAR RootPathName
[MAX_PATH
];
358 wcsncpy (RootPathName
, lpDirectoryName
, 3);
362 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
366 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
367 if (INVALID_HANDLE_VALUE
== hFile
)
372 errCode
= NtQueryVolumeInformationFile(hFile
,
375 sizeof(FILE_FS_SIZE_INFORMATION
),
376 FileFsSizeInformation
);
377 if (!NT_SUCCESS(errCode
))
380 SetLastErrorByStatus (errCode
);
384 BytesPerCluster
.QuadPart
=
385 FileFsSize
.BytesPerSector
* FileFsSize
.SectorsPerAllocationUnit
;
387 // FIXME: Use quota information
388 if (lpFreeBytesAvailableToCaller
)
389 lpFreeBytesAvailableToCaller
->QuadPart
=
390 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
392 if (lpTotalNumberOfBytes
)
393 lpTotalNumberOfBytes
->QuadPart
=
394 BytesPerCluster
.QuadPart
* FileFsSize
.TotalAllocationUnits
.QuadPart
;
395 if (lpTotalNumberOfFreeBytes
)
396 lpTotalNumberOfFreeBytes
->QuadPart
=
397 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
409 GetDriveTypeA(LPCSTR lpRootPathName
)
411 UNICODE_STRING RootPathNameU
;
412 ANSI_STRING RootPathName
;
415 RtlInitAnsiString (&RootPathName
,
416 (LPSTR
)lpRootPathName
);
418 /* convert ansi (or oem) string to unicode */
420 RtlAnsiStringToUnicodeString (&RootPathNameU
,
424 RtlOemStringToUnicodeString (&RootPathNameU
,
428 Result
= GetDriveTypeW (RootPathNameU
.Buffer
);
430 RtlFreeHeap (RtlGetProcessHeap (),
432 RootPathNameU
.Buffer
);
442 GetDriveTypeW(LPCWSTR lpRootPathName
)
444 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
445 IO_STATUS_BLOCK IoStatusBlock
;
450 hFile
= InternalOpenDirW(lpRootPathName
, FALSE
);
451 if (hFile
== INVALID_HANDLE_VALUE
)
453 return DRIVE_NO_ROOT_DIR
; /* According to WINE regression tests */
456 errCode
= NtQueryVolumeInformationFile (hFile
,
459 sizeof(FILE_FS_DEVICE_INFORMATION
),
460 FileFsDeviceInformation
);
461 if (!NT_SUCCESS(errCode
))
464 SetLastErrorByStatus (errCode
);
469 switch (FileFsDevice
.DeviceType
)
471 case FILE_DEVICE_CD_ROM
:
472 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
474 case FILE_DEVICE_VIRTUAL_DISK
:
475 return DRIVE_RAMDISK
;
476 case FILE_DEVICE_NETWORK_FILE_SYSTEM
:
478 case FILE_DEVICE_DISK
:
479 case FILE_DEVICE_DISK_FILE_SYSTEM
:
480 if (FileFsDevice
.Characteristics
& FILE_REMOTE_DEVICE
)
482 if (FileFsDevice
.Characteristics
& FILE_REMOVABLE_MEDIA
)
483 return DRIVE_REMOVABLE
;
487 DPRINT1("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice
.DeviceType
);
489 return DRIVE_UNKNOWN
;
497 GetVolumeInformationA(
498 LPCSTR lpRootPathName
,
499 LPSTR lpVolumeNameBuffer
,
500 DWORD nVolumeNameSize
,
501 LPDWORD lpVolumeSerialNumber
,
502 LPDWORD lpMaximumComponentLength
,
503 LPDWORD lpFileSystemFlags
,
504 LPSTR lpFileSystemNameBuffer
,
505 DWORD nFileSystemNameSize
508 UNICODE_STRING RootPathNameU
;
509 UNICODE_STRING FileSystemNameU
;
510 UNICODE_STRING VolumeNameU
;
511 ANSI_STRING RootPathName
;
512 ANSI_STRING VolumeName
;
513 ANSI_STRING FileSystemName
;
516 RtlInitAnsiString (&RootPathName
,
517 (LPSTR
)lpRootPathName
);
519 /* convert ansi (or oem) string to unicode */
521 RtlAnsiStringToUnicodeString (&RootPathNameU
,
525 RtlOemStringToUnicodeString (&RootPathNameU
,
529 if (lpVolumeNameBuffer
)
531 VolumeNameU
.Length
= 0;
532 VolumeNameU
.MaximumLength
= nVolumeNameSize
* sizeof(WCHAR
);
533 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
535 VolumeNameU
.MaximumLength
);
538 if (lpFileSystemNameBuffer
)
540 FileSystemNameU
.Length
= 0;
541 FileSystemNameU
.MaximumLength
= nFileSystemNameSize
* sizeof(WCHAR
);
542 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
544 FileSystemNameU
.MaximumLength
);
547 Result
= GetVolumeInformationW (RootPathNameU
.Buffer
,
548 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
550 lpVolumeSerialNumber
,
551 lpMaximumComponentLength
,
553 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
554 nFileSystemNameSize
);
558 if (lpVolumeNameBuffer
)
560 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
561 VolumeName
.Length
= 0;
562 VolumeName
.MaximumLength
= nVolumeNameSize
;
563 VolumeName
.Buffer
= lpVolumeNameBuffer
;
566 if (lpFileSystemNameBuffer
)
568 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
569 FileSystemName
.Length
= 0;
570 FileSystemName
.MaximumLength
= nFileSystemNameSize
;
571 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
574 /* convert unicode strings to ansi (or oem) */
577 if (lpVolumeNameBuffer
)
579 RtlUnicodeStringToAnsiString (&VolumeName
,
583 if (lpFileSystemNameBuffer
)
585 RtlUnicodeStringToAnsiString (&FileSystemName
,
592 if (lpVolumeNameBuffer
)
594 RtlUnicodeStringToOemString (&VolumeName
,
598 if (lpFileSystemNameBuffer
)
600 RtlUnicodeStringToOemString (&FileSystemName
,
607 RtlFreeHeap (RtlGetProcessHeap (),
609 RootPathNameU
.Buffer
);
610 if (lpVolumeNameBuffer
)
612 RtlFreeHeap (RtlGetProcessHeap (),
616 if (lpFileSystemNameBuffer
)
618 RtlFreeHeap (RtlGetProcessHeap (),
620 FileSystemNameU
.Buffer
);
626 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
628 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
634 GetVolumeInformationW(
635 LPCWSTR lpRootPathName
,
636 LPWSTR lpVolumeNameBuffer
,
637 DWORD nVolumeNameSize
,
638 LPDWORD lpVolumeSerialNumber
,
639 LPDWORD lpMaximumComponentLength
,
640 LPDWORD lpFileSystemFlags
,
641 LPWSTR lpFileSystemNameBuffer
,
642 DWORD nFileSystemNameSize
645 PFILE_FS_VOLUME_INFORMATION FileFsVolume
;
646 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
647 IO_STATUS_BLOCK IoStatusBlock
;
648 WCHAR RootPathName
[MAX_PATH
];
649 UCHAR Buffer
[max(FS_VOLUME_BUFFER_SIZE
, FS_ATTRIBUTE_BUFFER_SIZE
)];
654 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
655 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
657 DPRINT("FileFsVolume %p\n", FileFsVolume
);
658 DPRINT("FileFsAttribute %p\n", FileFsAttribute
);
660 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
662 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
666 wcsncpy (RootPathName
, lpRootPathName
, 3);
670 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
671 if (hFile
== INVALID_HANDLE_VALUE
)
676 DPRINT("hFile: %x\n", hFile
);
677 errCode
= NtQueryVolumeInformationFile(hFile
,
680 FS_VOLUME_BUFFER_SIZE
,
681 FileFsVolumeInformation
);
682 if ( !NT_SUCCESS(errCode
) )
684 DPRINT("Status: %x\n", errCode
);
686 SetLastErrorByStatus (errCode
);
690 if (lpVolumeSerialNumber
)
691 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
693 if (lpVolumeNameBuffer
)
695 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
697 memcpy(lpVolumeNameBuffer
,
698 FileFsVolume
->VolumeLabel
,
699 FileFsVolume
->VolumeLabelLength
);
700 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
705 SetLastError(ERROR_MORE_DATA
);
710 errCode
= NtQueryVolumeInformationFile (hFile
,
713 FS_ATTRIBUTE_BUFFER_SIZE
,
714 FileFsAttributeInformation
);
716 if (!NT_SUCCESS(errCode
))
718 DPRINT("Status: %x\n", errCode
);
719 SetLastErrorByStatus (errCode
);
723 if (lpFileSystemFlags
)
724 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
725 if (lpMaximumComponentLength
)
726 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
727 if (lpFileSystemNameBuffer
)
729 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
731 memcpy(lpFileSystemNameBuffer
,
732 FileFsAttribute
->FileSystemName
,
733 FileFsAttribute
->FileSystemNameLength
);
734 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
738 SetLastError(ERROR_MORE_DATA
);
752 LPCSTR lpRootPathName
,
756 UNICODE_STRING RootPathNameU
;
757 ANSI_STRING RootPathName
;
758 UNICODE_STRING VolumeNameU
;
759 ANSI_STRING VolumeName
;
762 RtlInitAnsiString (&RootPathName
,
763 (LPSTR
)lpRootPathName
);
764 RtlInitAnsiString (&VolumeName
,
765 (LPSTR
)lpVolumeName
);
767 /* convert ansi (or oem) strings to unicode */
770 RtlAnsiStringToUnicodeString (&RootPathNameU
,
773 RtlAnsiStringToUnicodeString (&VolumeNameU
,
779 RtlOemStringToUnicodeString (&RootPathNameU
,
782 RtlOemStringToUnicodeString (&VolumeNameU
,
787 Result
= SetVolumeLabelW (RootPathNameU
.Buffer
,
790 RtlFreeHeap (RtlGetProcessHeap (),
792 RootPathNameU
.Buffer
);
793 RtlFreeHeap (RtlGetProcessHeap (),
805 SetVolumeLabelW(LPCWSTR lpRootPathName
,
806 LPCWSTR lpVolumeName
)
808 PFILE_FS_LABEL_INFORMATION LabelInfo
;
809 IO_STATUS_BLOCK IoStatusBlock
;
814 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
815 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
817 sizeof(FILE_FS_LABEL_INFORMATION
) +
819 LabelInfo
->VolumeLabelLength
= LabelLength
;
820 memcpy(LabelInfo
->VolumeLabel
,
824 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
825 if (INVALID_HANDLE_VALUE
== hFile
)
827 RtlFreeHeap(RtlGetProcessHeap(),
833 Status
= NtSetVolumeInformationFile(hFile
,
836 sizeof(FILE_FS_LABEL_INFORMATION
) +
838 FileFsLabelInformation
);
840 RtlFreeHeap(RtlGetProcessHeap(),
844 if (!NT_SUCCESS(Status
))
846 DPRINT("Status: %x\n", Status
);
848 SetLastErrorByStatus(Status
);