Reimplemented GetLogicalDrives, GetLogicalDriveStrings and

GetDriveType using the new symlink mechanism.
Made GetDriveType attempt to autodetect the type if not specified in
the registry.
This commit is contained in:
Alexandre Julliard 2004-04-23 23:31:58 +00:00
parent 438369af9a
commit a2963dacc3
2 changed files with 221 additions and 196 deletions

View file

@ -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)
{
@ -1166,6 +1220,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.@)
*

View file

@ -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];
@ -100,23 +88,6 @@ inline static char *heap_strdup( const char *str )
return p;
}
/***********************************************************************
* 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
*/
@ -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)
{
@ -562,16 +516,6 @@ const char * DRIVE_GetDevice( int drive )
return (DRIVE_IsValid( drive )) ? DOSDrives[drive].device : NULL;
}
/***********************************************************************
* DRIVE_GetType
*/
static UINT DRIVE_GetType( int drive )
{
if (!DRIVE_IsValid( drive )) return DRIVE_NO_ROOT_DIR;
return DOSDrives[drive].type;
}
/***********************************************************************
* DRIVE_Chdir
*/
@ -684,70 +628,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)
*/
@ -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;
}