1 /* $Id: volume.c,v 1.41 2004/08/24 17:15:42 navaraf Exp $
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
= SharedUserData
->DosDeviceMap
;
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
= SharedUserData
->DosDeviceMap
;
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
)
158 return(SharedUserData
->DosDeviceMap
);
167 LPCSTR lpRootPathName
,
168 LPDWORD lpSectorsPerCluster
,
169 LPDWORD lpBytesPerSector
,
170 LPDWORD lpNumberOfFreeClusters
,
171 LPDWORD lpTotalNumberOfClusters
174 UNICODE_STRING RootPathNameU
;
175 ANSI_STRING RootPathName
;
178 RtlInitAnsiString (&RootPathName
,
179 (LPSTR
)lpRootPathName
);
181 RtlInitUnicodeString (&RootPathNameU
,
186 /* convert ansi (or oem) string to unicode */
188 RtlAnsiStringToUnicodeString (&RootPathNameU
,
192 RtlOemStringToUnicodeString (&RootPathNameU
,
197 Result
= GetDiskFreeSpaceW (RootPathNameU
.Buffer
,
200 lpNumberOfFreeClusters
,
201 lpTotalNumberOfClusters
);
205 RtlFreeHeap (RtlGetProcessHeap (),
207 RootPathNameU
.Buffer
);
219 LPCWSTR lpRootPathName
,
220 LPDWORD lpSectorsPerCluster
,
221 LPDWORD lpBytesPerSector
,
222 LPDWORD lpNumberOfFreeClusters
,
223 LPDWORD lpTotalNumberOfClusters
226 FILE_FS_SIZE_INFORMATION FileFsSize
;
227 IO_STATUS_BLOCK IoStatusBlock
;
228 WCHAR RootPathName
[MAX_PATH
];
234 wcsncpy (RootPathName
, lpRootPathName
, 3);
238 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
242 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
243 if (INVALID_HANDLE_VALUE
== hFile
)
245 SetLastError(ERROR_PATH_NOT_FOUND
);
249 errCode
= NtQueryVolumeInformationFile(hFile
,
252 sizeof(FILE_FS_SIZE_INFORMATION
),
253 FileFsSizeInformation
);
254 if (!NT_SUCCESS(errCode
))
257 SetLastErrorByStatus (errCode
);
261 *lpBytesPerSector
= FileFsSize
.BytesPerSector
;
262 *lpSectorsPerCluster
= FileFsSize
.SectorsPerAllocationUnit
;
263 *lpNumberOfFreeClusters
= FileFsSize
.AvailableAllocationUnits
.u
.LowPart
;
264 *lpTotalNumberOfClusters
= FileFsSize
.TotalAllocationUnits
.u
.LowPart
;
275 GetDiskFreeSpaceExA (
276 LPCSTR lpDirectoryName
,
277 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
278 PULARGE_INTEGER lpTotalNumberOfBytes
,
279 PULARGE_INTEGER lpTotalNumberOfFreeBytes
282 UNICODE_STRING DirectoryNameU
;
283 ANSI_STRING DirectoryName
;
286 RtlInitAnsiString (&DirectoryName
,
287 (LPSTR
)lpDirectoryName
);
289 RtlInitUnicodeString (&DirectoryNameU
,
294 /* convert ansi (or oem) string to unicode */
296 RtlAnsiStringToUnicodeString (&DirectoryNameU
,
300 RtlOemStringToUnicodeString (&DirectoryNameU
,
305 Result
= GetDiskFreeSpaceExW (DirectoryNameU
.Buffer
,
306 lpFreeBytesAvailableToCaller
,
307 lpTotalNumberOfBytes
,
308 lpTotalNumberOfFreeBytes
);
312 RtlFreeHeap (RtlGetProcessHeap (),
314 DirectoryNameU
.Buffer
);
326 LPCWSTR lpDirectoryName
,
327 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
328 PULARGE_INTEGER lpTotalNumberOfBytes
,
329 PULARGE_INTEGER lpTotalNumberOfFreeBytes
332 FILE_FS_SIZE_INFORMATION FileFsSize
;
333 IO_STATUS_BLOCK IoStatusBlock
;
334 ULARGE_INTEGER BytesPerCluster
;
335 WCHAR RootPathName
[MAX_PATH
];
341 wcsncpy (RootPathName
, lpDirectoryName
, 3);
345 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
349 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
350 if (INVALID_HANDLE_VALUE
== hFile
)
355 errCode
= NtQueryVolumeInformationFile(hFile
,
358 sizeof(FILE_FS_SIZE_INFORMATION
),
359 FileFsSizeInformation
);
360 if (!NT_SUCCESS(errCode
))
363 SetLastErrorByStatus (errCode
);
367 BytesPerCluster
.QuadPart
=
368 FileFsSize
.BytesPerSector
* FileFsSize
.SectorsPerAllocationUnit
;
370 // FIXME: Use quota information
371 if (lpFreeBytesAvailableToCaller
)
372 lpFreeBytesAvailableToCaller
->QuadPart
=
373 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
375 if (lpTotalNumberOfBytes
)
376 lpTotalNumberOfBytes
->QuadPart
=
377 BytesPerCluster
.QuadPart
* FileFsSize
.TotalAllocationUnits
.QuadPart
;
378 if (lpTotalNumberOfFreeBytes
)
379 lpTotalNumberOfFreeBytes
->QuadPart
=
380 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
392 GetDriveTypeA(LPCSTR lpRootPathName
)
394 UNICODE_STRING RootPathNameU
;
395 ANSI_STRING RootPathName
;
398 RtlInitAnsiString (&RootPathName
,
399 (LPSTR
)lpRootPathName
);
401 /* convert ansi (or oem) string to unicode */
403 RtlAnsiStringToUnicodeString (&RootPathNameU
,
407 RtlOemStringToUnicodeString (&RootPathNameU
,
411 Result
= GetDriveTypeW (RootPathNameU
.Buffer
);
413 RtlFreeHeap (RtlGetProcessHeap (),
415 RootPathNameU
.Buffer
);
425 GetDriveTypeW(LPCWSTR lpRootPathName
)
427 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
428 IO_STATUS_BLOCK IoStatusBlock
;
433 hFile
= InternalOpenDirW(lpRootPathName
, FALSE
);
434 if (hFile
== INVALID_HANDLE_VALUE
)
436 return DRIVE_NO_ROOT_DIR
; /* According to WINE regression tests */
439 errCode
= NtQueryVolumeInformationFile (hFile
,
442 sizeof(FILE_FS_DEVICE_INFORMATION
),
443 FileFsDeviceInformation
);
444 if (!NT_SUCCESS(errCode
))
447 SetLastErrorByStatus (errCode
);
452 switch (FileFsDevice
.DeviceType
)
454 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
456 case FILE_DEVICE_VIRTUAL_DISK
:
457 return DRIVE_RAMDISK
;
458 case FILE_DEVICE_NETWORK_FILE_SYSTEM
:
460 case FILE_DEVICE_DISK
:
461 case FILE_DEVICE_DISK_FILE_SYSTEM
:
462 if (FileFsDevice
.Characteristics
& FILE_REMOTE_DEVICE
)
464 if (FileFsDevice
.Characteristics
& FILE_REMOVABLE_MEDIA
)
465 return DRIVE_REMOVABLE
;
469 return DRIVE_UNKNOWN
;
477 GetVolumeInformationA(
478 LPCSTR lpRootPathName
,
479 LPSTR lpVolumeNameBuffer
,
480 DWORD nVolumeNameSize
,
481 LPDWORD lpVolumeSerialNumber
,
482 LPDWORD lpMaximumComponentLength
,
483 LPDWORD lpFileSystemFlags
,
484 LPSTR lpFileSystemNameBuffer
,
485 DWORD nFileSystemNameSize
488 UNICODE_STRING RootPathNameU
;
489 UNICODE_STRING FileSystemNameU
;
490 UNICODE_STRING VolumeNameU
;
491 ANSI_STRING RootPathName
;
492 ANSI_STRING VolumeName
;
493 ANSI_STRING FileSystemName
;
496 RtlInitAnsiString (&RootPathName
,
497 (LPSTR
)lpRootPathName
);
499 /* convert ansi (or oem) string to unicode */
501 RtlAnsiStringToUnicodeString (&RootPathNameU
,
505 RtlOemStringToUnicodeString (&RootPathNameU
,
509 if (lpVolumeNameBuffer
)
511 VolumeNameU
.Length
= 0;
512 VolumeNameU
.MaximumLength
= nVolumeNameSize
* sizeof(WCHAR
);
513 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
515 VolumeNameU
.MaximumLength
);
518 if (lpFileSystemNameBuffer
)
520 FileSystemNameU
.Length
= 0;
521 FileSystemNameU
.MaximumLength
= nFileSystemNameSize
* sizeof(WCHAR
);
522 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
524 FileSystemNameU
.MaximumLength
);
527 Result
= GetVolumeInformationW (RootPathNameU
.Buffer
,
528 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
530 lpVolumeSerialNumber
,
531 lpMaximumComponentLength
,
533 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
534 nFileSystemNameSize
);
538 if (lpVolumeNameBuffer
)
540 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
541 VolumeName
.Length
= 0;
542 VolumeName
.MaximumLength
= nVolumeNameSize
;
543 VolumeName
.Buffer
= lpVolumeNameBuffer
;
546 if (lpFileSystemNameBuffer
)
548 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
549 FileSystemName
.Length
= 0;
550 FileSystemName
.MaximumLength
= nFileSystemNameSize
;
551 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
554 /* convert unicode strings to ansi (or oem) */
557 if (lpVolumeNameBuffer
)
559 RtlUnicodeStringToAnsiString (&VolumeName
,
563 if (lpFileSystemNameBuffer
)
565 RtlUnicodeStringToAnsiString (&FileSystemName
,
572 if (lpVolumeNameBuffer
)
574 RtlUnicodeStringToOemString (&VolumeName
,
578 if (lpFileSystemNameBuffer
)
580 RtlUnicodeStringToOemString (&FileSystemName
,
587 RtlFreeHeap (RtlGetProcessHeap (),
589 RootPathNameU
.Buffer
);
590 if (lpVolumeNameBuffer
)
592 RtlFreeHeap (RtlGetProcessHeap (),
596 if (lpFileSystemNameBuffer
)
598 RtlFreeHeap (RtlGetProcessHeap (),
600 FileSystemNameU
.Buffer
);
606 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
608 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
614 GetVolumeInformationW(
615 LPCWSTR lpRootPathName
,
616 LPWSTR lpVolumeNameBuffer
,
617 DWORD nVolumeNameSize
,
618 LPDWORD lpVolumeSerialNumber
,
619 LPDWORD lpMaximumComponentLength
,
620 LPDWORD lpFileSystemFlags
,
621 LPWSTR lpFileSystemNameBuffer
,
622 DWORD nFileSystemNameSize
625 PFILE_FS_VOLUME_INFORMATION FileFsVolume
;
626 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
627 IO_STATUS_BLOCK IoStatusBlock
;
628 WCHAR RootPathName
[MAX_PATH
];
629 UCHAR Buffer
[max(FS_VOLUME_BUFFER_SIZE
, FS_ATTRIBUTE_BUFFER_SIZE
)];
634 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
635 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
637 DPRINT("FileFsVolume %p\n", FileFsVolume
);
638 DPRINT("FileFsAttribute %p\n", FileFsAttribute
);
640 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
642 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
646 wcsncpy (RootPathName
, lpRootPathName
, 3);
650 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
651 if (hFile
== INVALID_HANDLE_VALUE
)
656 DPRINT("hFile: %x\n", hFile
);
657 errCode
= NtQueryVolumeInformationFile(hFile
,
660 FS_VOLUME_BUFFER_SIZE
,
661 FileFsVolumeInformation
);
662 if ( !NT_SUCCESS(errCode
) )
664 DPRINT("Status: %x\n", errCode
);
666 SetLastErrorByStatus (errCode
);
670 if (lpVolumeSerialNumber
)
671 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
673 if (lpVolumeNameBuffer
)
675 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
677 memcpy(lpVolumeNameBuffer
,
678 FileFsVolume
->VolumeLabel
,
679 FileFsVolume
->VolumeLabelLength
);
680 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
685 SetLastError(ERROR_MORE_DATA
);
690 errCode
= NtQueryVolumeInformationFile (hFile
,
693 FS_ATTRIBUTE_BUFFER_SIZE
,
694 FileFsAttributeInformation
);
696 if (!NT_SUCCESS(errCode
))
698 DPRINT("Status: %x\n", errCode
);
699 SetLastErrorByStatus (errCode
);
703 if (lpFileSystemFlags
)
704 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
705 if (lpMaximumComponentLength
)
706 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
707 if (lpFileSystemNameBuffer
)
709 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
711 memcpy(lpFileSystemNameBuffer
,
712 FileFsAttribute
->FileSystemName
,
713 FileFsAttribute
->FileSystemNameLength
);
714 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
718 SetLastError(ERROR_MORE_DATA
);
732 LPCSTR lpRootPathName
,
736 UNICODE_STRING RootPathNameU
;
737 ANSI_STRING RootPathName
;
738 UNICODE_STRING VolumeNameU
;
739 ANSI_STRING VolumeName
;
742 RtlInitAnsiString (&RootPathName
,
743 (LPSTR
)lpRootPathName
);
744 RtlInitAnsiString (&VolumeName
,
745 (LPSTR
)lpVolumeName
);
747 /* convert ansi (or oem) strings to unicode */
750 RtlAnsiStringToUnicodeString (&RootPathNameU
,
753 RtlAnsiStringToUnicodeString (&VolumeNameU
,
759 RtlOemStringToUnicodeString (&RootPathNameU
,
762 RtlOemStringToUnicodeString (&VolumeNameU
,
767 Result
= SetVolumeLabelW (RootPathNameU
.Buffer
,
770 RtlFreeHeap (RtlGetProcessHeap (),
772 RootPathNameU
.Buffer
);
773 RtlFreeHeap (RtlGetProcessHeap (),
785 SetVolumeLabelW(LPCWSTR lpRootPathName
,
786 LPCWSTR lpVolumeName
)
788 PFILE_FS_LABEL_INFORMATION LabelInfo
;
789 IO_STATUS_BLOCK IoStatusBlock
;
794 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
795 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
797 sizeof(FILE_FS_LABEL_INFORMATION
) +
799 LabelInfo
->VolumeLabelLength
= LabelLength
;
800 memcpy(LabelInfo
->VolumeLabel
,
804 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
805 if (INVALID_HANDLE_VALUE
== hFile
)
807 RtlFreeHeap(RtlGetProcessHeap(),
813 Status
= NtSetVolumeInformationFile(hFile
,
816 sizeof(FILE_FS_LABEL_INFORMATION
) +
818 FileFsLabelInformation
);
820 RtlFreeHeap(RtlGetProcessHeap(),
824 if (!NT_SUCCESS(Status
))
826 DPRINT("Status: %x\n", Status
);
828 SetLastErrorByStatus(Status
);