Commit a2963dac authored by Alexandre Julliard's avatar Alexandre Julliard

Reimplemented GetLogicalDrives, GetLogicalDriveStrings and

GetDriveType using the new symlink mechanism. Made GetDriveType attempt to autodetect the type if not specified in the registry.
parent 438369af
......@@ -65,6 +65,16 @@ enum fs_type
FS_ISO9660
};
static const WCHAR drive_types[][8] =
{
{ 0 }, /* DRIVE_UNKNOWN */
{ 0 }, /* DRIVE_NO_ROOT_DIR */
{'f','l','o','p','p','y',0}, /* DRIVE_REMOVABLE */
{'h','d',0}, /* DRIVE_FIXED */
{'n','e','t','w','o','r','k',0}, /* DRIVE_REMOTE */
{'c','d','r','o','m',0}, /* DRIVE_CDROM */
{'r','a','m','d','i','s','k',0} /* DRIVE_RAMDISK */
};
/* read a Unix symlink; returned buffer must be freed by caller */
static char *read_symlink( const char *path )
......@@ -154,6 +164,50 @@ static BOOL open_device_root( LPCWSTR root, HANDLE *handle )
}
/* fetch the type of a drive from the registry */
static UINT get_registry_drive_type( int drive )
{
OBJECT_ATTRIBUTES attr;
UNICODE_STRING nameW;
HKEY hkey;
DWORD dummy;
UINT ret = DRIVE_UNKNOWN;
char tmp[32 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
WCHAR driveW[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
'W','i','n','e','\\','W','i','n','e','\\',
'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0};
static const WCHAR TypeW[] = {'T','y','p','e',0};
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.ObjectName = &nameW;
attr.Attributes = 0;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
RtlInitUnicodeString( &nameW, driveW );
nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + drive;
if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) return DRIVE_UNKNOWN;
RtlInitUnicodeString( &nameW, TypeW );
if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
{
int i;
WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
for (i = 0; i < sizeof(drive_types)/sizeof(drive_types[0]); i++)
{
if (!strcmpiW( data, drive_types[i] ))
{
ret = i;
break;
}
}
}
NtClose( hkey );
return ret;
}
/* create symlinks for the DOS drives; helper for VOLUME_CreateDevices */
static int create_drives(void)
{
......@@ -1167,6 +1221,170 @@ DWORD WINAPI QueryDosDeviceA( LPCSTR devname, LPSTR target, DWORD bufsize )
/***********************************************************************
* GetLogicalDrives (KERNEL32.@)
*/
DWORD WINAPI GetLogicalDrives(void)
{
const char *config_dir = wine_get_config_dir();
struct stat st;
char *buffer, *dev;
DWORD ret = 0;
int i;
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, strlen(config_dir) + sizeof("/dosdevices/a:") )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return 0;
}
strcpy( buffer, config_dir );
strcat( buffer, "/dosdevices/a:" );
dev = buffer + strlen(buffer) - 2;
for (i = 0; i < 26; i++)
{
*dev = 'a' + i;
if (!stat( buffer, &st )) ret |= (1 << i);
}
HeapFree( GetProcessHeap(), 0, buffer );
return ret;
}
/***********************************************************************
* GetLogicalDriveStringsA (KERNEL32.@)
*/
UINT WINAPI GetLogicalDriveStringsA( UINT len, LPSTR buffer )
{
DWORD drives = GetLogicalDrives();
UINT drive, count;
for (drive = count = 0; drive < 26; drive++) if (drives & (1 << drive)) count++;
if ((count * 4) + 1 > len) return count * 4 + 1;
for (drive = 0; drive < 26; drive++)
{
if (drives & (1 << drive))
{
*buffer++ = 'a' + drive;
*buffer++ = ':';
*buffer++ = '\\';
*buffer++ = 0;
}
}
*buffer = 0;
return count * 4;
}
/***********************************************************************
* GetLogicalDriveStringsW (KERNEL32.@)
*/
UINT WINAPI GetLogicalDriveStringsW( UINT len, LPWSTR buffer )
{
DWORD drives = GetLogicalDrives();
UINT drive, count;
for (drive = count = 0; drive < 26; drive++) if (drives & (1 << drive)) count++;
if ((count * 4) + 1 > len) return count * 4 + 1;
for (drive = 0; drive < 26; drive++)
{
if (drives & (1 << drive))
{
*buffer++ = 'a' + drive;
*buffer++ = ':';
*buffer++ = '\\';
*buffer++ = 0;
}
}
*buffer = 0;
return count * 4;
}
/***********************************************************************
* GetDriveTypeW (KERNEL32.@)
*
* Returns the type of the disk drive specified. If root is NULL the
* root of the current directory is used.
*
* RETURNS
*
* Type of drive (from Win32 SDK):
*
* DRIVE_UNKNOWN unable to find out anything about the drive
* DRIVE_NO_ROOT_DIR nonexistent root dir
* DRIVE_REMOVABLE the disk can be removed from the machine
* DRIVE_FIXED the disk can not be removed from the machine
* DRIVE_REMOTE network disk
* DRIVE_CDROM CDROM drive
* DRIVE_RAMDISK virtual disk in RAM
*/
UINT WINAPI GetDriveTypeW(LPCWSTR root) /* [in] String describing drive */
{
FILE_FS_DEVICE_INFORMATION info;
IO_STATUS_BLOCK io;
NTSTATUS status;
HANDLE handle;
UINT ret;
if (!open_device_root( root, &handle )) return DRIVE_NO_ROOT_DIR;
status = NtQueryVolumeInformationFile( handle, &io, &info, sizeof(info), FileFsDeviceInformation );
NtClose( handle );
if (status != STATUS_SUCCESS)
{
SetLastError( RtlNtStatusToDosError(status) );
ret = DRIVE_UNKNOWN;
}
else if ((ret = get_registry_drive_type( toupperW(root[0]) - 'A' )) == DRIVE_UNKNOWN)
{
switch (info.DeviceType)
{
case FILE_DEVICE_CD_ROM_FILE_SYSTEM: ret = DRIVE_CDROM; break;
case FILE_DEVICE_VIRTUAL_DISK: ret = DRIVE_RAMDISK; break;
case FILE_DEVICE_NETWORK_FILE_SYSTEM: ret = DRIVE_REMOTE; break;
case FILE_DEVICE_DISK_FILE_SYSTEM:
if (info.Characteristics & FILE_REMOTE_DEVICE) ret = DRIVE_REMOTE;
else if (info.Characteristics & FILE_REMOVABLE_MEDIA) ret = DRIVE_REMOVABLE;
else ret = DRIVE_FIXED;
break;
default:
ret = DRIVE_UNKNOWN;
break;
}
}
TRACE( "%s -> %d\n", debugstr_w(root), ret );
return ret;
}
/***********************************************************************
* GetDriveTypeA (KERNEL32.@)
*/
UINT WINAPI GetDriveTypeA( LPCSTR root )
{
UNICODE_STRING rootW;
UINT ret;
if (root)
{
if( !RtlCreateUnicodeStringFromAsciiz(&rootW, root))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return DRIVE_NO_ROOT_DIR;
}
}
else rootW.Buffer = NULL;
ret = GetDriveTypeW(rootW.Buffer);
RtlFreeUnicodeString(&rootW);
return ret;
}
/***********************************************************************
* GetDiskFreeSpaceExW (KERNEL32.@)
*
* This function is used to acquire the size of the available and
......
......@@ -67,23 +67,11 @@ typedef struct
LPWSTR dos_cwd; /* cwd in DOS format without leading or trailing \ */
char *unix_cwd; /* cwd in Unix format without leading or trailing / */
char *device; /* raw device path */
UINT type; /* drive type */
dev_t dev; /* unix device number */
ino_t ino; /* unix inode number */
} DOSDRIVE;
static const WCHAR DRIVE_Types[][8] =
{
{ 0 }, /* DRIVE_UNKNOWN */
{ 0 }, /* DRIVE_NO_ROOT_DIR */
{'f','l','o','p','p','y',0}, /* DRIVE_REMOVABLE */
{'h','d',0}, /* DRIVE_FIXED */
{'n','e','t','w','o','r','k',0}, /* DRIVE_REMOTE */
{'c','d','r','o','m',0}, /* DRIVE_CDROM */
{'r','a','m','d','i','s','k',0} /* DRIVE_RAMDISK */
};
#define MAX_DOS_DRIVES 26
static DOSDRIVE DOSDrives[MAX_DOS_DRIVES];
......@@ -101,23 +89,6 @@ inline static char *heap_strdup( const char *str )
}
/***********************************************************************
* DRIVE_GetDriveType
*/
static inline UINT DRIVE_GetDriveType( INT drive, LPCWSTR value )
{
int i;
for (i = 0; i < sizeof(DRIVE_Types)/sizeof(DRIVE_Types[0]); i++)
{
if (!strcmpiW( value, DRIVE_Types[i] )) return i;
}
MESSAGE("Drive %c: unknown drive type %s, defaulting to 'hd'.\n",
'A' + drive, debugstr_w(value) );
return DRIVE_FIXED;
}
/***********************************************************************
* DRIVE_Init
*/
int DRIVE_Init(void)
......@@ -140,7 +111,6 @@ int DRIVE_Init(void)
const char *config_dir = wine_get_config_dir();
static const WCHAR PathW[] = {'P','a','t','h',0};
static const WCHAR TypeW[] = {'T','y','p','e',0};
static const WCHAR DeviceW[] = {'D','e','v','i','c','e',0};
attr.Length = sizeof(attr);
......@@ -180,7 +150,6 @@ int DRIVE_Init(void)
drive->device = NULL;
drive->dev = drive_stat_buffer.st_dev;
drive->ino = drive_stat_buffer.st_ino;
drive->type = DRIVE_FIXED;
root = NULL;
symlink_count++;
}
......@@ -246,20 +215,11 @@ int DRIVE_Init(void)
drive->device = NULL;
drive->dev = drive_stat_buffer.st_dev;
drive->ino = drive_stat_buffer.st_ino;
drive->type = DRIVE_FIXED;
}
}
if (drive->root)
{
/* Get the drive type */
RtlInitUnicodeString( &nameW, TypeW );
if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
{
WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
drive->type = DRIVE_GetDriveType( i, data );
}
/* Get the device */
RtlInitUnicodeString( &nameW, DeviceW );
if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
......@@ -270,14 +230,9 @@ int DRIVE_Init(void)
WideCharToMultiByte(CP_UNIXCP, 0, data, -1, drive->device, len, NULL, NULL);
}
/* Make the first hard disk the current drive */
if ((DRIVE_CurDrive == -1) && (drive->type == DRIVE_FIXED))
DRIVE_CurDrive = i;
count++;
TRACE("Drive %c: path=%s type=%s dev=%x ino=%x\n",
'A' + i, drive->root, debugstr_w(DRIVE_Types[drive->type]),
(int)drive->dev, (int)drive->ino );
TRACE("Drive %c: path=%s dev=%x ino=%x\n",
'A' + i, drive->root, (int)drive->dev, (int)drive->ino );
}
next:
......@@ -291,7 +246,6 @@ int DRIVE_Init(void)
DOSDrives[2].root = heap_strdup( "/" );
DOSDrives[2].dos_cwd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DOSDrives[2].dos_cwd[0]));
DOSDrives[2].unix_cwd = heap_strdup( "" );
DOSDrives[2].type = DRIVE_FIXED;
DOSDrives[2].device = NULL;
DRIVE_CurDrive = 2;
}
......@@ -299,7 +253,7 @@ int DRIVE_Init(void)
/* Make sure the current drive is valid */
if (DRIVE_CurDrive == -1)
{
for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, drive++)
for (i = 2, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, drive++)
{
if (drive->root)
{
......@@ -563,16 +517,6 @@ const char * DRIVE_GetDevice( int drive )
}
/***********************************************************************
* DRIVE_GetType
*/
static UINT DRIVE_GetType( int drive )
{
if (!DRIVE_IsValid( drive )) return DRIVE_NO_ROOT_DIR;
return DOSDrives[drive].type;
}
/***********************************************************************
* DRIVE_Chdir
*/
int DRIVE_Chdir( int drive, LPCWSTR path )
......@@ -685,70 +629,6 @@ WCHAR *DRIVE_BuildEnv(void)
/***********************************************************************
* GetDriveTypeW (KERNEL32.@)
*
* Returns the type of the disk drive specified. If root is NULL the
* root of the current directory is used.
*
* RETURNS
*
* Type of drive (from Win32 SDK):
*
* DRIVE_UNKNOWN unable to find out anything about the drive
* DRIVE_NO_ROOT_DIR nonexistent root dir
* DRIVE_REMOVABLE the disk can be removed from the machine
* DRIVE_FIXED the disk can not be removed from the machine
* DRIVE_REMOTE network disk
* DRIVE_CDROM CDROM drive
* DRIVE_RAMDISK virtual disk in RAM
*/
UINT WINAPI GetDriveTypeW(LPCWSTR root) /* [in] String describing drive */
{
int drive;
TRACE("(%s)\n", debugstr_w(root));
if (NULL == root) drive = DRIVE_GetCurrentDrive();
else
{
if ((root[1]) && (root[1] != ':'))
{
WARN("invalid root %s\n", debugstr_w(root));
return DRIVE_NO_ROOT_DIR;
}
drive = toupperW(root[0]) - 'A';
}
return DRIVE_GetType(drive);
}
/***********************************************************************
* GetDriveTypeA (KERNEL32.@)
*/
UINT WINAPI GetDriveTypeA( LPCSTR root )
{
UNICODE_STRING rootW;
UINT ret = 0;
if (root)
{
if( !RtlCreateUnicodeStringFromAsciiz(&rootW, root))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
}
else
rootW.Buffer = NULL;
ret = GetDriveTypeW(rootW.Buffer);
RtlFreeUnicodeString(&rootW);
return ret;
}
/***********************************************************************
* GetCurrentDirectory (KERNEL.411)
*/
UINT16 WINAPI GetCurrentDirectory16( UINT16 buflen, LPSTR buf )
......@@ -868,76 +748,3 @@ BOOL WINAPI SetCurrentDirectoryA( LPCSTR dir )
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return ret;
}
/***********************************************************************
* GetLogicalDriveStringsA (KERNEL32.@)
*/
UINT WINAPI GetLogicalDriveStringsA( UINT len, LPSTR buffer )
{
int drive, count;
for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
if (DRIVE_IsValid(drive)) count++;
if ((count * 4) + 1 <= len)
{
LPSTR p = buffer;
for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
if (DRIVE_IsValid(drive))
{
*p++ = 'a' + drive;
*p++ = ':';
*p++ = '\\';
*p++ = '\0';
}
*p = '\0';
return count * 4;
}
else
return (count * 4) + 1; /* account for terminating null */
/* The API tells about these different return values */
}
/***********************************************************************
* GetLogicalDriveStringsW (KERNEL32.@)
*/
UINT WINAPI GetLogicalDriveStringsW( UINT len, LPWSTR buffer )
{
int drive, count;
for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
if (DRIVE_IsValid(drive)) count++;
if (count * 4 * sizeof(WCHAR) <= len)
{
LPWSTR p = buffer;
for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
if (DRIVE_IsValid(drive))
{
*p++ = (WCHAR)('a' + drive);
*p++ = (WCHAR)':';
*p++ = (WCHAR)'\\';
*p++ = (WCHAR)'\0';
}
*p = (WCHAR)'\0';
}
return count * 4 * sizeof(WCHAR);
}
/***********************************************************************
* GetLogicalDrives (KERNEL32.@)
*/
DWORD WINAPI GetLogicalDrives(void)
{
DWORD ret = 0;
int drive;
for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
{
if ( (DRIVE_IsValid(drive)) ||
(DOSDrives[drive].type == DRIVE_CDROM)) /* audio CD is also valid */
ret |= (1 << drive);
}
return ret;
}
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