1 /* $Id: volume.c,v 1.36 2004/01/17 23:04:28 gvg 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 <kernel32/kernel32.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
;
274 GetDiskFreeSpaceExA (
275 LPCSTR lpDirectoryName
,
276 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
277 PULARGE_INTEGER lpTotalNumberOfBytes
,
278 PULARGE_INTEGER lpTotalNumberOfFreeBytes
281 UNICODE_STRING DirectoryNameU
;
282 ANSI_STRING DirectoryName
;
285 RtlInitAnsiString (&DirectoryName
,
286 (LPSTR
)lpDirectoryName
);
288 RtlInitUnicodeString (&DirectoryNameU
,
293 /* convert ansi (or oem) string to unicode */
295 RtlAnsiStringToUnicodeString (&DirectoryNameU
,
299 RtlOemStringToUnicodeString (&DirectoryNameU
,
304 Result
= GetDiskFreeSpaceExW (DirectoryNameU
.Buffer
,
305 lpFreeBytesAvailableToCaller
,
306 lpTotalNumberOfBytes
,
307 lpTotalNumberOfFreeBytes
);
311 RtlFreeHeap (RtlGetProcessHeap (),
313 DirectoryNameU
.Buffer
);
325 LPCWSTR lpDirectoryName
,
326 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
327 PULARGE_INTEGER lpTotalNumberOfBytes
,
328 PULARGE_INTEGER lpTotalNumberOfFreeBytes
331 FILE_FS_SIZE_INFORMATION FileFsSize
;
332 IO_STATUS_BLOCK IoStatusBlock
;
333 ULARGE_INTEGER BytesPerCluster
;
334 WCHAR RootPathName
[MAX_PATH
];
340 wcsncpy (RootPathName
, lpDirectoryName
, 3);
344 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
348 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
349 if (INVALID_HANDLE_VALUE
== hFile
)
354 errCode
= NtQueryVolumeInformationFile(hFile
,
357 sizeof(FILE_FS_SIZE_INFORMATION
),
358 FileFsSizeInformation
);
359 if (!NT_SUCCESS(errCode
))
362 SetLastErrorByStatus (errCode
);
366 BytesPerCluster
.QuadPart
=
367 FileFsSize
.BytesPerSector
* FileFsSize
.SectorsPerAllocationUnit
;
369 // FIXME: Use quota information
370 if (lpFreeBytesAvailableToCaller
)
371 lpFreeBytesAvailableToCaller
->QuadPart
=
372 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
374 if (lpTotalNumberOfBytes
)
375 lpTotalNumberOfBytes
->QuadPart
=
376 BytesPerCluster
.QuadPart
* FileFsSize
.TotalAllocationUnits
.QuadPart
;
377 if (lpTotalNumberOfFreeBytes
)
378 lpTotalNumberOfFreeBytes
->QuadPart
=
379 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
390 GetDriveTypeA(LPCSTR lpRootPathName
)
392 UNICODE_STRING RootPathNameU
;
393 ANSI_STRING RootPathName
;
396 RtlInitAnsiString (&RootPathName
,
397 (LPSTR
)lpRootPathName
);
399 /* convert ansi (or oem) string to unicode */
401 RtlAnsiStringToUnicodeString (&RootPathNameU
,
405 RtlOemStringToUnicodeString (&RootPathNameU
,
409 Result
= GetDriveTypeW (RootPathNameU
.Buffer
);
411 RtlFreeHeap (RtlGetProcessHeap (),
413 RootPathNameU
.Buffer
);
423 GetDriveTypeW(LPCWSTR lpRootPathName
)
425 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
426 IO_STATUS_BLOCK IoStatusBlock
;
431 hFile
= InternalOpenDirW(lpRootPathName
, FALSE
);
432 if (hFile
== INVALID_HANDLE_VALUE
)
434 return DRIVE_NO_ROOT_DIR
; /* According to WINE regression tests */
437 errCode
= NtQueryVolumeInformationFile (hFile
,
440 sizeof(FILE_FS_DEVICE_INFORMATION
),
441 FileFsDeviceInformation
);
442 if (!NT_SUCCESS(errCode
))
445 SetLastErrorByStatus (errCode
);
449 return (UINT
)FileFsDevice
.DeviceType
;
457 GetVolumeInformationA(
458 LPCSTR lpRootPathName
,
459 LPSTR lpVolumeNameBuffer
,
460 DWORD nVolumeNameSize
,
461 LPDWORD lpVolumeSerialNumber
,
462 LPDWORD lpMaximumComponentLength
,
463 LPDWORD lpFileSystemFlags
,
464 LPSTR lpFileSystemNameBuffer
,
465 DWORD nFileSystemNameSize
468 UNICODE_STRING RootPathNameU
;
469 UNICODE_STRING FileSystemNameU
;
470 UNICODE_STRING VolumeNameU
;
471 ANSI_STRING RootPathName
;
472 ANSI_STRING VolumeName
;
473 ANSI_STRING FileSystemName
;
476 RtlInitAnsiString (&RootPathName
,
477 (LPSTR
)lpRootPathName
);
479 /* convert ansi (or oem) string to unicode */
481 RtlAnsiStringToUnicodeString (&RootPathNameU
,
485 RtlOemStringToUnicodeString (&RootPathNameU
,
489 if (lpVolumeNameBuffer
)
491 VolumeNameU
.Length
= 0;
492 VolumeNameU
.MaximumLength
= nVolumeNameSize
* sizeof(WCHAR
);
493 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
495 VolumeNameU
.MaximumLength
);
498 if (lpFileSystemNameBuffer
)
500 FileSystemNameU
.Length
= 0;
501 FileSystemNameU
.MaximumLength
= nFileSystemNameSize
* sizeof(WCHAR
);
502 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
504 FileSystemNameU
.MaximumLength
);
507 Result
= GetVolumeInformationW (RootPathNameU
.Buffer
,
508 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
510 lpVolumeSerialNumber
,
511 lpMaximumComponentLength
,
513 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
514 nFileSystemNameSize
);
518 if (lpVolumeNameBuffer
)
520 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
521 VolumeName
.Length
= 0;
522 VolumeName
.MaximumLength
= nVolumeNameSize
;
523 VolumeName
.Buffer
= lpVolumeNameBuffer
;
526 if (lpFileSystemNameBuffer
)
528 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
529 FileSystemName
.Length
= 0;
530 FileSystemName
.MaximumLength
= nFileSystemNameSize
;
531 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
534 /* convert unicode strings to ansi (or oem) */
537 if (lpVolumeNameBuffer
)
539 RtlUnicodeStringToAnsiString (&VolumeName
,
543 if (lpFileSystemNameBuffer
)
545 RtlUnicodeStringToAnsiString (&FileSystemName
,
552 if (lpVolumeNameBuffer
)
554 RtlUnicodeStringToOemString (&VolumeName
,
558 if (lpFileSystemNameBuffer
)
560 RtlUnicodeStringToOemString (&FileSystemName
,
567 RtlFreeHeap (RtlGetProcessHeap (),
569 RootPathNameU
.Buffer
);
570 if (lpVolumeNameBuffer
)
572 RtlFreeHeap (RtlGetProcessHeap (),
576 if (lpFileSystemNameBuffer
)
578 RtlFreeHeap (RtlGetProcessHeap (),
580 FileSystemNameU
.Buffer
);
586 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
588 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
594 GetVolumeInformationW(
595 LPCWSTR lpRootPathName
,
596 LPWSTR lpVolumeNameBuffer
,
597 DWORD nVolumeNameSize
,
598 LPDWORD lpVolumeSerialNumber
,
599 LPDWORD lpMaximumComponentLength
,
600 LPDWORD lpFileSystemFlags
,
601 LPWSTR lpFileSystemNameBuffer
,
602 DWORD nFileSystemNameSize
605 PFILE_FS_VOLUME_INFORMATION FileFsVolume
;
606 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
607 IO_STATUS_BLOCK IoStatusBlock
;
608 WCHAR RootPathName
[MAX_PATH
];
609 UCHAR Buffer
[max(FS_VOLUME_BUFFER_SIZE
, FS_ATTRIBUTE_BUFFER_SIZE
)];
614 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
615 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
617 DPRINT("FileFsVolume %p\n", FileFsVolume
);
618 DPRINT("FileFsAttribute %p\n", FileFsAttribute
);
620 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
622 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
627 wcsncpy (RootPathName
, lpRootPathName
, min(MAX_PATH
, wcslen(lpRootPathName
) + 1));
630 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
631 if (hFile
== INVALID_HANDLE_VALUE
)
636 DPRINT("hFile: %x\n", hFile
);
637 errCode
= NtQueryVolumeInformationFile(hFile
,
640 FS_VOLUME_BUFFER_SIZE
,
641 FileFsVolumeInformation
);
642 if ( !NT_SUCCESS(errCode
) )
644 DPRINT("Status: %x\n", errCode
);
646 SetLastErrorByStatus (errCode
);
650 if (lpVolumeSerialNumber
)
651 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
653 if (lpVolumeNameBuffer
)
655 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
657 memcpy(lpVolumeNameBuffer
,
658 FileFsVolume
->VolumeLabel
,
659 FileFsVolume
->VolumeLabelLength
);
660 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
665 SetLastError(ERROR_MORE_DATA
);
670 errCode
= NtQueryVolumeInformationFile (hFile
,
673 FS_ATTRIBUTE_BUFFER_SIZE
,
674 FileFsAttributeInformation
);
676 if (!NT_SUCCESS(errCode
))
678 DPRINT("Status: %x\n", errCode
);
679 SetLastErrorByStatus (errCode
);
683 if (lpFileSystemFlags
)
684 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
685 if (lpMaximumComponentLength
)
686 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
687 if (lpFileSystemNameBuffer
)
689 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
691 memcpy(lpFileSystemNameBuffer
,
692 FileFsAttribute
->FileSystemName
,
693 FileFsAttribute
->FileSystemNameLength
);
694 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
698 SetLastError(ERROR_MORE_DATA
);
712 LPCSTR lpRootPathName
,
716 UNICODE_STRING RootPathNameU
;
717 ANSI_STRING RootPathName
;
718 UNICODE_STRING VolumeNameU
;
719 ANSI_STRING VolumeName
;
722 RtlInitAnsiString (&RootPathName
,
723 (LPSTR
)lpRootPathName
);
724 RtlInitAnsiString (&VolumeName
,
725 (LPSTR
)lpVolumeName
);
727 /* convert ansi (or oem) strings to unicode */
730 RtlAnsiStringToUnicodeString (&RootPathNameU
,
733 RtlAnsiStringToUnicodeString (&VolumeNameU
,
739 RtlOemStringToUnicodeString (&RootPathNameU
,
742 RtlOemStringToUnicodeString (&VolumeNameU
,
747 Result
= SetVolumeLabelW (RootPathNameU
.Buffer
,
750 RtlFreeHeap (RtlGetProcessHeap (),
752 RootPathNameU
.Buffer
);
753 RtlFreeHeap (RtlGetProcessHeap (),
765 SetVolumeLabelW(LPCWSTR lpRootPathName
,
766 LPCWSTR lpVolumeName
)
768 PFILE_FS_LABEL_INFORMATION LabelInfo
;
769 IO_STATUS_BLOCK IoStatusBlock
;
774 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
775 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
777 sizeof(FILE_FS_LABEL_INFORMATION
) +
779 LabelInfo
->VolumeLabelLength
= LabelLength
;
780 memcpy(LabelInfo
->VolumeLabel
,
784 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
785 if (INVALID_HANDLE_VALUE
== hFile
)
787 RtlFreeHeap(RtlGetProcessHeap(),
793 Status
= NtSetVolumeInformationFile(hFile
,
796 sizeof(FILE_FS_LABEL_INFORMATION
) +
798 FileFsLabelInformation
);
800 RtlFreeHeap(RtlGetProcessHeap(),
804 if (!NT_SUCCESS(Status
))
806 DPRINT("Status: %x\n", Status
);
808 SetLastErrorByStatus(Status
);