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 PWCHAR RootPathNameW
=NULL
;
195 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
199 return GetDiskFreeSpaceW (RootPathNameW
,
202 lpNumberOfFreeClusters
,
203 lpTotalNumberOfClusters
);
212 LPCWSTR lpRootPathName
,
213 LPDWORD lpSectorsPerCluster
,
214 LPDWORD lpBytesPerSector
,
215 LPDWORD lpNumberOfFreeClusters
,
216 LPDWORD lpTotalNumberOfClusters
219 FILE_FS_SIZE_INFORMATION FileFsSize
;
220 IO_STATUS_BLOCK IoStatusBlock
;
221 WCHAR RootPathName
[MAX_PATH
];
227 wcsncpy (RootPathName
, lpRootPathName
, 3);
231 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
235 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
236 if (INVALID_HANDLE_VALUE
== hFile
)
238 SetLastError(ERROR_PATH_NOT_FOUND
);
242 errCode
= NtQueryVolumeInformationFile(hFile
,
245 sizeof(FILE_FS_SIZE_INFORMATION
),
246 FileFsSizeInformation
);
247 if (!NT_SUCCESS(errCode
))
250 SetLastErrorByStatus (errCode
);
254 *lpBytesPerSector
= FileFsSize
.BytesPerSector
;
255 *lpSectorsPerCluster
= FileFsSize
.SectorsPerAllocationUnit
;
256 *lpNumberOfFreeClusters
= FileFsSize
.AvailableAllocationUnits
.u
.LowPart
;
257 *lpTotalNumberOfClusters
= FileFsSize
.TotalAllocationUnits
.u
.LowPart
;
268 GetDiskFreeSpaceExA (
269 LPCSTR lpDirectoryName OPTIONAL
,
270 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
271 PULARGE_INTEGER lpTotalNumberOfBytes
,
272 PULARGE_INTEGER lpTotalNumberOfFreeBytes
275 PWCHAR DirectoryNameW
=NULL
;
279 if (!(DirectoryNameW
= FilenameA2W(lpDirectoryName
, FALSE
)))
283 return GetDiskFreeSpaceExW (DirectoryNameW
,
284 lpFreeBytesAvailableToCaller
,
285 lpTotalNumberOfBytes
,
286 lpTotalNumberOfFreeBytes
);
295 LPCWSTR lpDirectoryName OPTIONAL
,
296 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
297 PULARGE_INTEGER lpTotalNumberOfBytes
,
298 PULARGE_INTEGER lpTotalNumberOfFreeBytes
301 FILE_FS_SIZE_INFORMATION FileFsSize
;
302 IO_STATUS_BLOCK IoStatusBlock
;
303 ULARGE_INTEGER BytesPerCluster
;
304 WCHAR RootPathName
[MAX_PATH
];
309 FIXME: this is obviously wrong for UNC paths, symbolic directories etc.
314 wcsncpy (RootPathName
, lpDirectoryName
, 3);
318 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
322 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
323 if (INVALID_HANDLE_VALUE
== hFile
)
328 errCode
= NtQueryVolumeInformationFile(hFile
,
331 sizeof(FILE_FS_SIZE_INFORMATION
),
332 FileFsSizeInformation
);
333 if (!NT_SUCCESS(errCode
))
336 SetLastErrorByStatus (errCode
);
340 BytesPerCluster
.QuadPart
=
341 FileFsSize
.BytesPerSector
* FileFsSize
.SectorsPerAllocationUnit
;
343 // FIXME: Use quota information
344 if (lpFreeBytesAvailableToCaller
)
345 lpFreeBytesAvailableToCaller
->QuadPart
=
346 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
348 if (lpTotalNumberOfBytes
)
349 lpTotalNumberOfBytes
->QuadPart
=
350 BytesPerCluster
.QuadPart
* FileFsSize
.TotalAllocationUnits
.QuadPart
;
351 if (lpTotalNumberOfFreeBytes
)
352 lpTotalNumberOfFreeBytes
->QuadPart
=
353 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
365 GetDriveTypeA(LPCSTR lpRootPathName
)
367 PWCHAR RootPathNameW
;
369 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
370 return DRIVE_UNKNOWN
;
372 return GetDriveTypeW(RootPathNameW
);
380 GetDriveTypeW(LPCWSTR lpRootPathName
)
382 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
383 IO_STATUS_BLOCK IoStatusBlock
;
388 hFile
= InternalOpenDirW(lpRootPathName
, FALSE
);
389 if (hFile
== INVALID_HANDLE_VALUE
)
391 return DRIVE_NO_ROOT_DIR
; /* According to WINE regression tests */
394 errCode
= NtQueryVolumeInformationFile (hFile
,
397 sizeof(FILE_FS_DEVICE_INFORMATION
),
398 FileFsDeviceInformation
);
399 if (!NT_SUCCESS(errCode
))
402 SetLastErrorByStatus (errCode
);
407 switch (FileFsDevice
.DeviceType
)
409 case FILE_DEVICE_CD_ROM
:
410 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
412 case FILE_DEVICE_VIRTUAL_DISK
:
413 return DRIVE_RAMDISK
;
414 case FILE_DEVICE_NETWORK_FILE_SYSTEM
:
416 case FILE_DEVICE_DISK
:
417 case FILE_DEVICE_DISK_FILE_SYSTEM
:
418 if (FileFsDevice
.Characteristics
& FILE_REMOTE_DEVICE
)
420 if (FileFsDevice
.Characteristics
& FILE_REMOVABLE_MEDIA
)
421 return DRIVE_REMOVABLE
;
425 DPRINT1("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice
.DeviceType
);
427 return DRIVE_UNKNOWN
;
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
446 UNICODE_STRING FileSystemNameU
;
447 UNICODE_STRING VolumeNameU
= {0};
448 ANSI_STRING VolumeName
;
449 ANSI_STRING FileSystemName
;
450 PWCHAR RootPathNameW
;
453 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
456 if (lpVolumeNameBuffer
)
458 VolumeNameU
.MaximumLength
= nVolumeNameSize
* sizeof(WCHAR
);
459 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
461 VolumeNameU
.MaximumLength
);
462 if (VolumeNameU
.Buffer
== NULL
)
468 if (lpFileSystemNameBuffer
)
470 FileSystemNameU
.Length
= 0;
471 FileSystemNameU
.MaximumLength
= nFileSystemNameSize
* sizeof(WCHAR
);
472 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
474 FileSystemNameU
.MaximumLength
);
475 if (FileSystemNameU
.Buffer
== NULL
)
477 if (VolumeNameU
.Buffer
!= NULL
)
479 RtlFreeHeap(RtlGetProcessHeap(),
485 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
490 Result
= GetVolumeInformationW (RootPathNameW
,
491 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
493 lpVolumeSerialNumber
,
494 lpMaximumComponentLength
,
496 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
497 nFileSystemNameSize
);
501 if (lpVolumeNameBuffer
)
503 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
504 VolumeName
.Length
= 0;
505 VolumeName
.MaximumLength
= nVolumeNameSize
;
506 VolumeName
.Buffer
= lpVolumeNameBuffer
;
509 if (lpFileSystemNameBuffer
)
511 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
512 FileSystemName
.Length
= 0;
513 FileSystemName
.MaximumLength
= nFileSystemNameSize
;
514 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
517 /* convert unicode strings to ansi (or oem) */
520 if (lpVolumeNameBuffer
)
522 RtlUnicodeStringToAnsiString (&VolumeName
,
526 if (lpFileSystemNameBuffer
)
528 RtlUnicodeStringToAnsiString (&FileSystemName
,
535 if (lpVolumeNameBuffer
)
537 RtlUnicodeStringToOemString (&VolumeName
,
541 if (lpFileSystemNameBuffer
)
543 RtlUnicodeStringToOemString (&FileSystemName
,
550 if (lpVolumeNameBuffer
)
552 RtlFreeHeap (RtlGetProcessHeap (),
556 if (lpFileSystemNameBuffer
)
558 RtlFreeHeap (RtlGetProcessHeap (),
560 FileSystemNameU
.Buffer
);
566 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
568 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
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
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
)];
594 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
595 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
597 DPRINT("FileFsVolume %p\n", FileFsVolume
);
598 DPRINT("FileFsAttribute %p\n", FileFsAttribute
);
600 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
602 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
606 wcsncpy (RootPathName
, lpRootPathName
, 3);
610 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
611 if (hFile
== INVALID_HANDLE_VALUE
)
616 DPRINT("hFile: %x\n", hFile
);
617 errCode
= NtQueryVolumeInformationFile(hFile
,
620 FS_VOLUME_BUFFER_SIZE
,
621 FileFsVolumeInformation
);
622 if ( !NT_SUCCESS(errCode
) )
624 DPRINT("Status: %x\n", errCode
);
626 SetLastErrorByStatus (errCode
);
630 if (lpVolumeSerialNumber
)
631 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
633 if (lpVolumeNameBuffer
)
635 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
637 memcpy(lpVolumeNameBuffer
,
638 FileFsVolume
->VolumeLabel
,
639 FileFsVolume
->VolumeLabelLength
);
640 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
645 SetLastError(ERROR_MORE_DATA
);
650 errCode
= NtQueryVolumeInformationFile (hFile
,
653 FS_ATTRIBUTE_BUFFER_SIZE
,
654 FileFsAttributeInformation
);
656 if (!NT_SUCCESS(errCode
))
658 DPRINT("Status: %x\n", errCode
);
659 SetLastErrorByStatus (errCode
);
663 if (lpFileSystemFlags
)
664 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
665 if (lpMaximumComponentLength
)
666 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
667 if (lpFileSystemNameBuffer
)
669 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
671 memcpy(lpFileSystemNameBuffer
,
672 FileFsAttribute
->FileSystemName
,
673 FileFsAttribute
->FileSystemNameLength
);
674 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
678 SetLastError(ERROR_MORE_DATA
);
692 LPCSTR lpRootPathName
,
693 LPCSTR lpVolumeName
/* NULL if deleting label */
696 PWCHAR RootPathNameW
;
697 PWCHAR VolumeNameW
= NULL
;
700 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
705 if (!(VolumeNameW
= FilenameA2W(lpVolumeName
, TRUE
)))
709 Result
= SetVolumeLabelW (RootPathNameW
,
714 RtlFreeHeap (RtlGetProcessHeap (),
728 LPCWSTR lpRootPathName
,
729 LPCWSTR lpVolumeName
/* NULL if deleting label */
732 PFILE_FS_LABEL_INFORMATION LabelInfo
;
733 IO_STATUS_BLOCK IoStatusBlock
;
738 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
739 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
741 sizeof(FILE_FS_LABEL_INFORMATION
) +
743 if (LabelInfo
== NULL
)
745 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
748 LabelInfo
->VolumeLabelLength
= LabelLength
;
749 memcpy(LabelInfo
->VolumeLabel
,
753 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
754 if (INVALID_HANDLE_VALUE
== hFile
)
756 RtlFreeHeap(RtlGetProcessHeap(),
762 Status
= NtSetVolumeInformationFile(hFile
,
765 sizeof(FILE_FS_LABEL_INFORMATION
) +
767 FileFsLabelInformation
);
769 RtlFreeHeap(RtlGetProcessHeap(),
773 if (!NT_SUCCESS(Status
))
775 DPRINT("Status: %x\n", Status
);
777 SetLastErrorByStatus(Status
);