Commit d1051870 authored by Alexandre Julliard's avatar Alexandre Julliard

Reimplemented GetDiskFreeSpaceW and GetDiskFreeSpaceExW on top of the

corresponding ntdll functions.
parent a9832be1
......@@ -148,6 +148,40 @@ static char *get_dos_device_path( LPCWSTR name )
}
/* open a handle to a device root */
static BOOL open_device_root( LPCWSTR root, HANDLE *handle )
{
static const WCHAR default_rootW[] = {'\\',0};
UNICODE_STRING nt_name;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
NTSTATUS status;
if (!root) root = default_rootW;
if (!RtlDosPathNameToNtPathName_U( root, &nt_name, NULL, NULL ))
{
SetLastError( ERROR_PATH_NOT_FOUND );
return FALSE;
}
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.Attributes = OBJ_CASE_INSENSITIVE;
attr.ObjectName = &nt_name;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
status = NtOpenFile( handle, 0, &attr, &io, 0,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
RtlFreeUnicodeString( &nt_name );
if (status != STATUS_SUCCESS)
{
SetLastError( RtlNtStatusToDosError(status) );
return FALSE;
}
return TRUE;
}
/* create symlinks for the DOS drives; helper for VOLUME_CreateDevices */
static int create_drives(void)
{
......@@ -1206,3 +1240,134 @@ DWORD WINAPI QueryDosDeviceA( LPCSTR devname, LPSTR target, DWORD bufsize )
HeapFree(GetProcessHeap(), 0, targetW);
return ret;
}
/***********************************************************************
* GetDiskFreeSpaceExW (KERNEL32.@)
*
* This function is used to acquire the size of the available and
* total space on a logical volume.
*
* RETURNS
*
* Zero on failure, nonzero upon success. Use GetLastError to obtain
* detailed error information.
*
*/
BOOL WINAPI GetDiskFreeSpaceExW( LPCWSTR root, PULARGE_INTEGER avail,
PULARGE_INTEGER total, PULARGE_INTEGER totalfree )
{
FILE_FS_SIZE_INFORMATION info;
IO_STATUS_BLOCK io;
NTSTATUS status;
HANDLE handle;
UINT units;
TRACE( "%s,%p,%p,%p\n", debugstr_w(root), avail, total, totalfree );
if (!open_device_root( root, &handle )) return FALSE;
status = NtQueryVolumeInformationFile( handle, &io, &info, sizeof(info), FileFsSizeInformation );
NtClose( handle );
if (status != STATUS_SUCCESS)
{
SetLastError( RtlNtStatusToDosError(status) );
return FALSE;
}
units = info.SectorsPerAllocationUnit * info.BytesPerSector;
if (total) total->QuadPart = info.TotalAllocationUnits.QuadPart * units;
if (totalfree) totalfree->QuadPart = info.AvailableAllocationUnits.QuadPart * units;
/* FIXME: this one should take quotas into account */
if (avail) avail->QuadPart = info.AvailableAllocationUnits.QuadPart * units;
return TRUE;
}
/***********************************************************************
* GetDiskFreeSpaceExA (KERNEL32.@)
*/
BOOL WINAPI GetDiskFreeSpaceExA( LPCSTR root, PULARGE_INTEGER avail,
PULARGE_INTEGER total, PULARGE_INTEGER totalfree )
{
UNICODE_STRING rootW;
BOOL ret;
if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
else rootW.Buffer = NULL;
ret = GetDiskFreeSpaceExW( rootW.Buffer, avail, total, totalfree);
RtlFreeUnicodeString(&rootW);
return ret;
}
/***********************************************************************
* GetDiskFreeSpaceW (KERNEL32.@)
*/
BOOL WINAPI GetDiskFreeSpaceW( LPCWSTR root, LPDWORD cluster_sectors,
LPDWORD sector_bytes, LPDWORD free_clusters,
LPDWORD total_clusters )
{
FILE_FS_SIZE_INFORMATION info;
IO_STATUS_BLOCK io;
NTSTATUS status;
HANDLE handle;
UINT units;
TRACE( "%s,%p,%p,%p,%p\n", debugstr_w(root),
cluster_sectors, sector_bytes, free_clusters, total_clusters );
if (!open_device_root( root, &handle )) return FALSE;
status = NtQueryVolumeInformationFile( handle, &io, &info, sizeof(info), FileFsSizeInformation );
NtClose( handle );
if (status != STATUS_SUCCESS)
{
SetLastError( RtlNtStatusToDosError(status) );
return FALSE;
}
units = info.SectorsPerAllocationUnit * info.BytesPerSector;
/* cap the size and available at 2GB as per specs */
if (info.AvailableAllocationUnits.QuadPart * units > 0x7fffffff)
info.AvailableAllocationUnits.QuadPart = 0x7fffffff / units;
if (info.TotalAllocationUnits.QuadPart * units > 0x7fffffff)
info.TotalAllocationUnits.QuadPart = 0x7fffffff / units;
if (cluster_sectors) *cluster_sectors = info.SectorsPerAllocationUnit;
if (sector_bytes) *sector_bytes = info.BytesPerSector;
if (free_clusters) *free_clusters = info.AvailableAllocationUnits.u.LowPart;
if (total_clusters) *total_clusters = info.TotalAllocationUnits.u.LowPart;
return TRUE;
}
/***********************************************************************
* GetDiskFreeSpaceA (KERNEL32.@)
*/
BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors,
LPDWORD sector_bytes, LPDWORD free_clusters,
LPDWORD total_clusters )
{
UNICODE_STRING rootW;
BOOL ret = FALSE;
if (root)
{
if(!RtlCreateUnicodeStringFromAsciiz(&rootW, root))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
}
else rootW.Buffer = NULL;
ret = GetDiskFreeSpaceW(rootW.Buffer, cluster_sectors, sector_bytes,
free_clusters, total_clusters );
RtlFreeUnicodeString(&rootW);
return ret;
}
......@@ -39,9 +39,6 @@
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
#endif
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
......@@ -644,35 +641,6 @@ int DRIVE_Chdir( int drive, LPCWSTR path )
/***********************************************************************
* DRIVE_GetFreeSpace
*/
static int DRIVE_GetFreeSpace( int drive, PULARGE_INTEGER size,
PULARGE_INTEGER available )
{
struct statvfs info;
if (!DRIVE_IsValid(drive))
{
SetLastError( ERROR_PATH_NOT_FOUND );
return 0;
}
if (statvfs( DOSDrives[drive].root, &info ) < 0)
{
FILE_SetDosError();
WARN("cannot do statvfs(%s)\n", DOSDrives[drive].root);
return 0;
}
size->QuadPart = RtlEnlargedUnsignedMultiply( info.f_frsize, info.f_blocks );
if (DOSDrives[drive].type == DRIVE_CDROM)
available->QuadPart = 0; /* ALWAYS 0, even if no real CD-ROM mounted there !! */
else
available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_frsize, info.f_bavail );
return 1;
}
/***********************************************************************
* DRIVE_GetCurrentDirectory
* Returns "X:\\path\\etc\\".
*
......@@ -729,236 +697,6 @@ WCHAR *DRIVE_BuildEnv(void)
/***********************************************************************
* GetDiskFreeSpaceW (KERNEL32.@)
*
* Fails if expression resulting from current drive's dir and "root"
* is not a root dir of the target drive.
*
* UNDOC: setting some LPDWORDs to NULL is perfectly possible
* if the corresponding info is unneeded.
*
* FIXME: needs to support UNC names from Win95 OSR2 on.
*
* Behaviour under Win95a:
* CurrDir root result
* "E:\\TEST" "E:" FALSE
* "E:\\" "E:" TRUE
* "E:\\" "E" FALSE
* "E:\\" "\\" TRUE
* "E:\\TEST" "\\" TRUE
* "E:\\TEST" ":\\" FALSE
* "E:\\TEST" "E:\\" TRUE
* "E:\\TEST" "" FALSE
* "E:\\" "" FALSE (!)
* "E:\\" 0x0 TRUE
* "E:\\TEST" 0x0 TRUE (!)
* "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
* "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
*/
BOOL WINAPI GetDiskFreeSpaceW( LPCWSTR root, LPDWORD cluster_sectors,
LPDWORD sector_bytes, LPDWORD free_clusters,
LPDWORD total_clusters )
{
int drive, sec_size;
ULARGE_INTEGER size,available;
LPCWSTR path;
DWORD cluster_sec;
TRACE("%s,%p,%p,%p,%p\n", debugstr_w(root), cluster_sectors, sector_bytes,
free_clusters, total_clusters);
if (!root || root[0] == '\\' || root[0] == '/')
drive = DRIVE_GetCurrentDrive();
else
if (root[0] && root[1] == ':') /* root contains drive tag */
{
drive = toupperW(root[0]) - 'A';
path = &root[2];
if (path[0] == '\0')
{
path = DRIVE_GetDosCwd(drive);
if (!path)
{
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
}
else
if (path[0] == '\\')
path++;
if (path[0]) /* oops, we are in a subdir */
{
SetLastError(ERROR_INVALID_NAME);
return FALSE;
}
}
else
{
if (!root[0])
SetLastError(ERROR_PATH_NOT_FOUND);
else
SetLastError(ERROR_INVALID_NAME);
return FALSE;
}
if (!DRIVE_GetFreeSpace(drive, &size, &available)) return FALSE;
/* Cap the size and available at 2GB as per specs. */
if ((size.u.HighPart) ||(size.u.LowPart > 0x7fffffff))
{
size.u.HighPart = 0;
size.u.LowPart = 0x7fffffff;
}
if ((available.u.HighPart) ||(available.u.LowPart > 0x7fffffff))
{
available.u.HighPart =0;
available.u.LowPart = 0x7fffffff;
}
sec_size = (DRIVE_GetType(drive)==DRIVE_CDROM) ? 2048 : 512;
size.u.LowPart /= sec_size;
available.u.LowPart /= sec_size;
/* FIXME: probably have to adjust those variables too for CDFS */
cluster_sec = 1;
while (cluster_sec * 65536 < size.u.LowPart) cluster_sec *= 2;
if (cluster_sectors)
*cluster_sectors = cluster_sec;
if (sector_bytes)
*sector_bytes = sec_size;
if (free_clusters)
*free_clusters = available.u.LowPart / cluster_sec;
if (total_clusters)
*total_clusters = size.u.LowPart / cluster_sec;
return TRUE;
}
/***********************************************************************
* GetDiskFreeSpaceA (KERNEL32.@)
*/
BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors,
LPDWORD sector_bytes, LPDWORD free_clusters,
LPDWORD total_clusters )
{
UNICODE_STRING rootW;
BOOL ret = FALSE;
if (root)
{
if(!RtlCreateUnicodeStringFromAsciiz(&rootW, root))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
}
else
rootW.Buffer = NULL;
ret = GetDiskFreeSpaceW(rootW.Buffer, cluster_sectors, sector_bytes,
free_clusters, total_clusters );
RtlFreeUnicodeString(&rootW);
return ret;
}
/***********************************************************************
* GetDiskFreeSpaceExW (KERNEL32.@)
*
* This function is used to acquire the size of the available and
* total space on a logical volume.
*
* RETURNS
*
* Zero on failure, nonzero upon success. Use GetLastError to obtain
* detailed error information.
*
*/
BOOL WINAPI GetDiskFreeSpaceExW( LPCWSTR root,
PULARGE_INTEGER avail,
PULARGE_INTEGER total,
PULARGE_INTEGER totalfree)
{
int drive;
ULARGE_INTEGER size,available;
if (!root) drive = DRIVE_GetCurrentDrive();
else
{ /* C: always works for GetDiskFreeSpaceEx */
if ((root[1]) && ((root[1] != ':') || (root[2] && root[2] != '\\')))
{
FIXME("there are valid root names which are not supported yet\n");
/* ..like UNC names, for instance. */
WARN("invalid root '%s'\n", debugstr_w(root));
return FALSE;
}
drive = toupperW(root[0]) - 'A';
}
if (!DRIVE_GetFreeSpace(drive, &size, &available)) return FALSE;
if (total)
{
total->u.HighPart = size.u.HighPart;
total->u.LowPart = size.u.LowPart;
}
if (totalfree)
{
totalfree->u.HighPart = available.u.HighPart;
totalfree->u.LowPart = available.u.LowPart;
}
if (avail)
{
if (FIXME_ON(dosfs))
{
/* On Windows2000, we need to check the disk quota
allocated for the user owning the calling process. We
don't want to be more obtrusive than necessary with the
FIXME messages, so don't print the FIXME unless Wine is
actually masquerading as Windows2000. */
RTL_OSVERSIONINFOEXW ovi;
ovi.dwOSVersionInfoSize = sizeof(ovi);
if (RtlGetVersion(&ovi))
{
if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4)
FIXME("no per-user quota support yet\n");
}
}
/* Quick hack, should eventually be fixed to work 100% with
Windows2000 (see comment above). */
avail->u.HighPart = available.u.HighPart;
avail->u.LowPart = available.u.LowPart;
}
return TRUE;
}
/***********************************************************************
* GetDiskFreeSpaceExA (KERNEL32.@)
*/
BOOL WINAPI GetDiskFreeSpaceExA( LPCSTR root, PULARGE_INTEGER avail,
PULARGE_INTEGER total,
PULARGE_INTEGER totalfree)
{
UNICODE_STRING rootW;
BOOL ret;
if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
else rootW.Buffer = NULL;
ret = GetDiskFreeSpaceExW( rootW.Buffer, avail, total, totalfree);
RtlFreeUnicodeString(&rootW);
return ret;
}
/***********************************************************************
* GetDriveTypeW (KERNEL32.@)
*
* Returns the type of the disk drive specified. If root is NULL the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment