Reimplemented GetDiskFreeSpaceW and GetDiskFreeSpaceExW on top of the
corresponding ntdll functions.
This commit is contained in:
parent
a9832be1a7
commit
d1051870db
|
@ -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;
|
||||
}
|
||||
|
|
262
files/drive.c
262
files/drive.c
|
@ -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
|
||||
|
@ -643,35 +640,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\\".
|
||||
|
@ -728,236 +696,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.@)
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue