diff --git a/dlls/kernel/kernel_main.c b/dlls/kernel/kernel_main.c index 49e39b0ac9b..e6dc0b72d6a 100644 --- a/dlls/kernel/kernel_main.c +++ b/dlls/kernel/kernel_main.c @@ -50,6 +50,7 @@ extern void LOCALE_InitRegistry(void); extern void COMPUTERNAME_Init(void); extern int __wine_set_signal_handler(unsigned, int (*)(unsigned)); +extern void VOLUME_CreateDevices(void); /* memory/environ.c */ extern void ENV_CopyStartupInformation(void); @@ -125,7 +126,10 @@ static BOOL process_attach(void) /* Setup computer name */ COMPUTERNAME_Init(); - + + /* Create device symlinks */ + VOLUME_CreateDevices(); + /* copy process information from ntdll */ ENV_CopyStartupInformation(); diff --git a/dlls/kernel/kernel_private.h b/dlls/kernel/kernel_private.h index a77c00314d8..ac460c9ec8a 100644 --- a/dlls/kernel/kernel_private.h +++ b/dlls/kernel/kernel_private.h @@ -51,6 +51,9 @@ extern HMODULE kernel32_handle; extern HANDLE dos_handles[DOS_TABLE_SIZE]; void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing ); +extern HANDLE VOLUME_OpenDevice( LPCWSTR name, DWORD access, DWORD sharing, + LPSECURITY_ATTRIBUTES sa, DWORD attributes ); + extern void PTHREAD_Init(void); extern BOOL WOWTHUNK_Init(void); diff --git a/dlls/kernel/volume.c b/dlls/kernel/volume.c index 295f54b5eea..11bcd231a32 100644 --- a/dlls/kernel/volume.c +++ b/dlls/kernel/volume.c @@ -27,6 +27,7 @@ #include #include +#include #include "windef.h" #include "winbase.h" @@ -37,6 +38,9 @@ #include "winioctl.h" #include "ntddstor.h" #include "ntddcdrm.h" +#include "kernel_private.h" +#include "file.h" +#include "wine/library.h" #include "wine/unicode.h" #include "wine/debug.h" @@ -62,6 +66,249 @@ enum fs_type }; +/* return default device to use for serial ports */ +/* result should not be more than 16 characters long */ +static BOOL get_default_com_device( char *buffer, int num ) +{ + if (!num || num > 9) return FALSE; +#ifdef linux + sprintf( buffer, "/dev/ttyS%d", num - 1 ); + return TRUE; +#else + FIXME( "no known default for device com%d\n", num ); + return FALSE; +#endif +} + +/* return default device to use for parallel ports */ +/* result should not be more than 16 characters long */ +static BOOL get_default_lpt_device( char *buffer, int num ) +{ + if (!num || num > 9) return FALSE; +#ifdef linux + sprintf( buffer, "/dev/lp%d", num - 1 ); + return TRUE; +#else + FIXME( "no known default for device lpt%d\n", num ); + return FALSE; +#endif +} + +/* read a Unix symlink; returned buffer must be freed by caller */ +static char *read_symlink( const char *path ) +{ + char *buffer; + int ret, size = 128; + + for (;;) + { + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return 0; + } + ret = readlink( path, buffer, size ); + if (ret == -1) + { + FILE_SetDosError(); + HeapFree( GetProcessHeap(), 0, buffer ); + return 0; + } + if (ret != sizeof(buffer)) + { + buffer[ret] = 0; + return buffer; + } + HeapFree( GetProcessHeap(), 0, buffer ); + size *= 2; + } +} + +/* get the path of a dos device symlink in the $WINEPREFIX/dosdevices directory */ +static char *get_dos_device_path( LPCWSTR name ) +{ + const char *config_dir = wine_get_config_dir(); + char *buffer, *dev; + int i; + + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, + strlen(config_dir) + sizeof("/dosdevices/") + 5 ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return NULL; + } + strcpy( buffer, config_dir ); + strcat( buffer, "/dosdevices/" ); + dev = buffer + strlen(buffer); + /* no codepage conversion, DOS device names are ASCII anyway */ + for (i = 0; i < 5; i++) + if (!(dev[i] = (char)tolowerW(name[i]))) break; + dev[5] = 0; + return buffer; +} + + +/*********************************************************************** + * VOLUME_CreateDevices + * + * Create the device files for the new device naming scheme. + * Should go away after a transition period. + */ +void VOLUME_CreateDevices(void) +{ + const char *config_dir = wine_get_config_dir(); + char *buffer; + int i, count = 0; + + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, + strlen(config_dir) + sizeof("/dosdevices") ))) + return; + + strcpy( buffer, config_dir ); + strcat( buffer, "/dosdevices" ); + + if (!mkdir( buffer, 0777 )) /* we created it, so now create the devices */ + { + HKEY hkey; + DWORD dummy; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + WCHAR *p, *devnameW; + char tmp[128]; + WCHAR com[5] = {'C','O','M','1',0}; + WCHAR lpt[5] = {'L','P','T','1',0}; + + static const WCHAR serialportsW[] = {'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','\\', + 'S','e','r','i','a','l','P','o','r','t','s',0}; + static const WCHAR parallelportsW[] = {'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','\\', + 'P','a','r','a','l','l','e','l','P','o','r','t','s',0}; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &nameW; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString( &nameW, serialportsW ); + + if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) + { + RtlInitUnicodeString( &nameW, com ); + for (i = 1; i <= 9; i++) + { + com[3] = '0' + i; + if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, + tmp, sizeof(tmp), &dummy )) + { + devnameW = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data; + if ((p = strchrW( devnameW, ',' ))) *p = 0; + if (DefineDosDeviceW( DDD_RAW_TARGET_PATH, com, devnameW )) + { + char devname[32]; + WideCharToMultiByte(CP_UNIXCP, 0, devnameW, -1, + devname, sizeof(devname), NULL, NULL); + MESSAGE( "Created symlink %s/dosdevices/com%d -> %s\n", config_dir, i, devname ); + count++; + } + } + } + NtClose( hkey ); + } + + RtlInitUnicodeString( &nameW, parallelportsW ); + if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) + { + RtlInitUnicodeString( &nameW, lpt ); + for (i = 1; i <= 9; i++) + { + lpt[3] = '0' + i; + if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, + tmp, sizeof(tmp), &dummy )) + { + devnameW = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data; + if ((p = strchrW( devnameW, ',' ))) *p = 0; + if (DefineDosDeviceW( DDD_RAW_TARGET_PATH, lpt, devnameW )) + { + char devname[32]; + WideCharToMultiByte(CP_UNIXCP, 0, devnameW, -1, + devname, sizeof(devname), NULL, NULL); + MESSAGE( "Created symlink %s/dosdevices/lpt%d -> %s\n", config_dir, i, devname ); + count++; + } + } + } + NtClose( hkey ); + } + if (count) + MESSAGE( "\nYou can now remove the [SerialPorts] and [ParallelPorts] sections\n" + "in your configuration file, they are replaced by the above symlinks.\n\n" ); + } + HeapFree( GetProcessHeap(), 0, buffer ); +} + + +/****************************************************************** + * VOLUME_OpenDevice + */ +HANDLE VOLUME_OpenDevice( LPCWSTR name, DWORD access, DWORD sharing, + LPSECURITY_ATTRIBUTES sa, DWORD attributes ) +{ + char *buffer, *dev; + HANDLE ret; + + if (!(buffer = get_dos_device_path( name ))) return 0; + dev = strrchr( buffer, '/' ) + 1; + + for (;;) + { + TRACE("trying %s\n", buffer ); + + ret = FILE_CreateFile( buffer, access, sharing, sa, OPEN_EXISTING, 0, 0, TRUE, DRIVE_FIXED ); + if (ret || GetLastError() != ERROR_FILE_NOT_FOUND) break; + if (!dev) break; + + /* now try some defaults for it */ + if (!strcmp( dev, "aux" )) + { + strcpy( dev, "com1" ); + continue; + } + if (!strcmp( dev, "prn" )) + { + strcpy( dev, "lpt1" ); + continue; + } + if (!strcmp( dev, "nul" )) + { + strcpy( buffer, "/dev/null" ); + dev = NULL; /* last try */ + continue; + } + if (!strncmp( dev, "com", 3 ) && get_default_com_device( buffer, dev[3] - '0' )) + { + dev = NULL; /* last try */ + continue; + } + if (!strncmp( dev, "lpt", 3 ) && get_default_lpt_device( buffer, dev[3] - '0' )) + { + dev = NULL; /* last try */ + continue; + } + break; + } + + if (!ret) ERR( "could not open device %s err %ld\n", debugstr_w(name), GetLastError() ); + HeapFree( GetProcessHeap(), 0, buffer ); + return ret; +} + + /****************************************************************** * VOLUME_FindCdRomDataBestVoldesc */ @@ -624,3 +871,267 @@ BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR str, LPWSTR dst, DWORD siz FIXME("(%s, %p, %lx): stub\n", debugstr_w(str), dst, size); return 0; } + + +/*********************************************************************** + * DefineDosDeviceW (KERNEL32.@) + */ +BOOL WINAPI DefineDosDeviceW( DWORD flags, LPCWSTR devname, LPCWSTR targetpath ) +{ + DWORD dosdev; + + if (!(flags & DDD_RAW_TARGET_PATH)) + { + FIXME( "(0x%08lx,%s,%s) DDD_RAW_TARGET_PATH flag not set, not supported yet\n", + flags, debugstr_w(devname), debugstr_w(targetpath) ); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } + + /* first check for a DOS device */ + + if ((dosdev = RtlIsDosDeviceName_U( devname ))) + { + WCHAR name[5]; + DWORD len; + char *path, *target, *p; + BOOL ret = FALSE; + + memcpy( name, devname + HIWORD(dosdev)/sizeof(WCHAR), LOWORD(dosdev) ); + name[LOWORD(dosdev)/sizeof(WCHAR)] = 0; + if (!(path = get_dos_device_path( name ))) return FALSE; + + len = WideCharToMultiByte( CP_UNIXCP, 0, targetpath, -1, NULL, 0, NULL, NULL ); + if ((target = HeapAlloc( GetProcessHeap(), 0, len ))) + { + WideCharToMultiByte( CP_UNIXCP, 0, targetpath, -1, target, len, NULL, NULL ); + for (p = target; *p; p++) if (*p == '\\') *p = '/'; + TRACE( "creating symlink %s -> %s\n", path, target ); + unlink( path ); + if (!symlink( target, path )) ret = TRUE; + else FILE_SetDosError(); + HeapFree( GetProcessHeap(), 0, target ); + } + else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + HeapFree( GetProcessHeap(), 0, path ); + return ret; + } + + /* now it must be a drive mapping */ + + FIXME("(0x%08lx,%s,%s) drive mappings not supported yet\n", + flags, debugstr_w(devname), debugstr_w(targetpath) ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + + +/*********************************************************************** + * DefineDosDeviceA (KERNEL32.@) + */ +BOOL WINAPI DefineDosDeviceA(DWORD flags, LPCSTR devname, LPCSTR targetpath) +{ + UNICODE_STRING d, t; + BOOL ret; + + if (!RtlCreateUnicodeStringFromAsciiz(&d, devname)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + if (!RtlCreateUnicodeStringFromAsciiz(&t, targetpath)) + { + RtlFreeUnicodeString(&d); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + ret = DefineDosDeviceW(flags, d.Buffer, t.Buffer); + RtlFreeUnicodeString(&d); + RtlFreeUnicodeString(&t); + return ret; +} + + +/*********************************************************************** + * QueryDosDeviceW (KERNEL32.@) + * + * returns array of strings terminated by \0, terminated by \0 + */ +DWORD WINAPI QueryDosDeviceW( LPCWSTR devname, LPWSTR target, DWORD bufsize ) +{ + static const WCHAR auxW[] = {'A','U','X',0}; + static const WCHAR nulW[] = {'N','U','L',0}; + static const WCHAR prnW[] = {'P','R','N',0}; + static const WCHAR comW[] = {'C','O','M',0}; + static const WCHAR lptW[] = {'L','P','T',0}; + static const WCHAR com0W[] = {'C','O','M','0',0}; + static const WCHAR com1W[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\','C','O','M','1',0,0}; + static const WCHAR lpt1W[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\','L','P','T','1',0,0}; + + char buffer[16]; + struct stat st; + + if (!bufsize) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return 0; + } + + if (devname) + { + WCHAR *p, name[5]; + char *path, *link; + DWORD dosdev, ret = 0; + + if (!(dosdev = RtlIsDosDeviceName_U( devname ))) + { + SetLastError( ERROR_BAD_PATHNAME ); + return 0; + } + memcpy( name, devname + HIWORD(dosdev)/sizeof(WCHAR), LOWORD(dosdev) ); + name[LOWORD(dosdev)/sizeof(WCHAR)] = 0; + if (!(path = get_dos_device_path( name ))) return 0; + link = read_symlink( path ); + HeapFree( GetProcessHeap(), 0, path ); + + if (link) + { + ret = MultiByteToWideChar( CP_UNIXCP, 0, link, -1, target, bufsize ); + HeapFree( GetProcessHeap(), 0, link ); + } + else /* look for defaults */ + { + if (!strcmpiW( name, auxW )) + { + if (bufsize >= sizeof(com1W)/sizeof(WCHAR)) + { + memcpy( target, com1W, sizeof(com1W) ); + ret = sizeof(com1W)/sizeof(WCHAR); + } + else SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return ret; + } + if (!strcmpiW( name, prnW )) + { + if (bufsize >= sizeof(lpt1W)/sizeof(WCHAR)) + { + memcpy( target, lpt1W, sizeof(lpt1W) ); + ret = sizeof(lpt1W)/sizeof(WCHAR); + } + else SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return ret; + } + + buffer[0] = 0; + + if (!strcmpiW( name, nulW )) + strcpy( buffer, "/dev/null" ); + else if (!strncmpiW( name, comW, 3 )) + get_default_com_device( buffer, name[3] - '0' ); + else if (!strncmpiW( name, lptW, 3 )) + get_default_lpt_device( buffer, name[3] - '0' ); + + if (buffer[0] && !stat( buffer, &st )) + ret = MultiByteToWideChar( CP_UNIXCP, 0, buffer, -1, target, bufsize ); + else + SetLastError( ERROR_FILE_NOT_FOUND ); + } + + if (ret) + { + if (ret < bufsize) target[ret++] = 0; /* add an extra null */ + for (p = target; *p; p++) if (*p == '/') *p = '\\'; + } + + return ret; + } + else /* return a list of all devices */ + { + WCHAR *p = target; + char *path, *dev, buffer[16]; + int i; + + if (bufsize <= (sizeof(auxW)+sizeof(nulW)+sizeof(prnW))/sizeof(WCHAR)) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return 0; + } + + memcpy( p, auxW, sizeof(auxW) ); + p += sizeof(auxW) / sizeof(WCHAR); + memcpy( p, nulW, sizeof(nulW) ); + p += sizeof(nulW) / sizeof(WCHAR); + memcpy( p, prnW, sizeof(prnW) ); + p += sizeof(prnW) / sizeof(WCHAR); + + if (!(path = get_dos_device_path( com0W ))) return 0; + dev = strrchr( path, '/' ) + 1; + + for (i = 1; i <= 9; i++) + { + sprintf( dev, "com%d", i ); + if (!stat( path, &st ) || + (get_default_com_device( buffer, i ) && !stat( buffer, &st ))) + { + if (p + 5 >= target + bufsize) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return 0; + } + strcpyW( p, comW ); + p[3] = '0' + i; + p[4] = 0; + p += 5; + } + } + for (i = 1; i <= 9; i++) + { + sprintf( dev, "lpt%d", i ); + if (!stat( path, &st ) || + (get_default_lpt_device( buffer, i ) && !stat( buffer, &st ))) + { + if (p + 5 >= target + bufsize) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return 0; + } + strcpyW( p, lptW ); + p[3] = '0' + i; + p[4] = 0; + p += 5; + } + } + *p++ = 0; /* terminating null */ + return p - target; + } +} + + +/*********************************************************************** + * QueryDosDeviceA (KERNEL32.@) + * + * returns array of strings terminated by \0, terminated by \0 + */ +DWORD WINAPI QueryDosDeviceA( LPCSTR devname, LPSTR target, DWORD bufsize ) +{ + DWORD ret = 0, retW; + UNICODE_STRING devnameW; + LPWSTR targetW = HeapAlloc( GetProcessHeap(),0, bufsize * sizeof(WCHAR) ); + + if (!targetW) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return 0; + } + + if (devname) RtlCreateUnicodeStringFromAsciiz(&devnameW, devname); + else devnameW.Buffer = NULL; + + retW = QueryDosDeviceW(devnameW.Buffer, targetW, bufsize); + + ret = WideCharToMultiByte(CP_ACP, 0, targetW, retW, target, bufsize, NULL, NULL); + + RtlFreeUnicodeString(&devnameW); + HeapFree(GetProcessHeap(), 0, targetW); + return ret; +} diff --git a/documentation/samples/config b/documentation/samples/config index ad980711eca..4c79407c9b3 100644 --- a/documentation/samples/config +++ b/documentation/samples/config @@ -152,15 +152,6 @@ WINE REGISTRY Version 2 ;"dir3" = "/usr/X11R6/lib/X11/fonts/TT" ;"dir4" = "/usr/share/fonts/TT" -[serialports] -"Com1" = "/dev/ttyS0" -"Com2" = "/dev/ttyS1" -"Com3" = "/dev/ttyS2" -"Com4" = "/dev/modem" - -[parallelports] -"Lpt1" = "/dev/lp0" - [ppdev] ;; key: io-base of the emulated port ;; value : parport-device{,timeout} diff --git a/documentation/wine.conf.man b/documentation/wine.conf.man index 60a961a2ffa..376d011341d 100644 --- a/documentation/wine.conf.man +++ b/documentation/wine.conf.man @@ -212,22 +212,6 @@ fiddling with the current defaults and needless to say that you must know what you are doing. --debugmsg +loaddll might come in handy for experimenting with that stuff. .PP -.B [serialports] -.br -.I format: """com[12345678]""=""""" -.br -default: none -.br -Used to specify the devices which are used as COM1 - COM8. -.PP -.B [parallelports] -.br -.I format: """lpt[12345678]""=""""" -.br -default: none -.br -Used to specify the devices which are used as LPT1 - LPT8. -.PP .B [Debug] .br .I format: """SpyExclude""=""""" @@ -350,16 +334,22 @@ Make sure to use double backslashes in the section name. A sample configuration file is distributed as .B documentation/samples/config in the Wine source distribution. -.SH FILES -.TP -.I ~/.wine/config -User-specific configuration file .SH ENVIRONMENT VARIABLES .TP .I WINEPREFIX Specifies the directory that contains the per-user .I config -file, the registry files, and the wineserver socket. The default is +file, the registry files, and the DOS device mappings. The default is .I $HOME/.wine. +.SH FILES +.TP +.I $WINEPREFIX/config +User-specific configuration file +.TP +.I $WINEPREFIX/dosdevices +Directory containing the DOS device mappings. Each file in that +directory is a symlink to the Unix device file implementing a given +device. For instance, if COM1 is mapped to /dev/ttyS0 you'd have a +symlink of the form $WINEPREFIX/dosdevices/com1 -> /dev/ttyS0. .SH "SEE ALSO" .BR wine (1) diff --git a/files/dos_fs.c b/files/dos_fs.c index 5b83fb0cfc3..af0e4047fa8 100644 --- a/files/dos_fs.c +++ b/files/dos_fs.c @@ -95,42 +95,6 @@ typedef struct /* Chars we don't want to see in DOS file names */ #define INVALID_DOS_CHARS "*?<>|\"+=,;[] \345" -/* DOS device descriptor */ -typedef struct -{ - const WCHAR name[5]; -} DOS_DEVICE; - -static const DOS_DEVICE DOSFS_Devices[] = -/* name, device flags (see Int 21/AX=0x4400) */ -{ - { {'C','O','N',0} }, - { {'P','R','N',0} }, - { {'N','U','L',0} }, - { {'A','U','X',0} }, - { {'L','P','T','1',0} }, - { {'L','P','T','2',0} }, - { {'L','P','T','3',0} }, - { {'L','P','T','4',0} }, - { {'C','O','M','1',0} }, - { {'C','O','M','2',0} }, - { {'C','O','M','3',0} }, - { {'C','O','M','4',0} } -}; - -static const WCHAR devW[] = {'\\','D','e','v','i','c','e','\\',0}; -static const WCHAR dosW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0}; - -static const WCHAR auxW[] = {'A','U','X',0}; -static const WCHAR comW[] = {'C','O','M',0}; -static const WCHAR lptW[] = {'L','P','T',0}; -static const WCHAR nulW[] = {'N','U','L',0}; - -static const WCHAR nullW[] = {'N','u','l','l',0}; -static const WCHAR parW[] = {'P','a','r','a','l','l','e','l',0}; -static const WCHAR serW[] = {'S','e','r','i','a','l',0}; -static const WCHAR oneW[] = {'1',0}; - /* at some point we may want to allow Winelib apps to set this */ static const BOOL is_case_sensitive = FALSE; @@ -702,122 +666,6 @@ BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *long_buf } -/************************************************************************** - * DOSFS_CreateCommPort - */ -static HANDLE DOSFS_CreateCommPort(LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa) -{ - HANDLE ret; - HKEY hkey; - DWORD dummy; - OBJECT_ATTRIBUTES attr; - UNICODE_STRING nameW; - WCHAR *devnameW; - char tmp[128]; - char devname[40]; - - static const WCHAR serialportsW[] = {'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','\\', - 'S','e','r','i','a','l','P','o','r','t','s',0}; - - TRACE_(file)("%s %lx %lx\n", debugstr_w(name), access, attributes); - - attr.Length = sizeof(attr); - attr.RootDirectory = 0; - attr.ObjectName = &nameW; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - RtlInitUnicodeString( &nameW, serialportsW ); - - if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return 0; - - RtlInitUnicodeString( &nameW, name ); - if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy )) - devnameW = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data; - else - devnameW = NULL; - - NtClose( hkey ); - - if (!devnameW) return 0; - WideCharToMultiByte(CP_ACP, 0, devnameW, -1, devname, sizeof(devname), NULL, NULL); - - TRACE("opening %s as %s\n", devname, debugstr_w(name)); - - ret = FILE_CreateFile( devname, access, FILE_SHARE_READ|FILE_SHARE_WRITE, - sa, OPEN_EXISTING, attributes, NULL, FALSE, DRIVE_FIXED ); - - if(!ret) - ERR("Couldn't open device '%s' ! (check permissions)\n",devname); - else - TRACE("return %p\n", ret ); - return ret; -} - -/*********************************************************************** - * DOSFS_OpenDevice - * - * Open a DOS device. This might not map 1:1 into the UNIX device concept. - * Returns 0 on failure. - */ -HANDLE DOSFS_OpenDevice( LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa ) -{ - unsigned int i; - const WCHAR *p; - HANDLE handle; - - if (name[0] && (name[1] == ':')) name += 2; - if ((p = strrchrW( name, '/' ))) name = p + 1; - if ((p = strrchrW( name, '\\' ))) name = p + 1; - for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++) - { - const WCHAR *dev = DOSFS_Devices[i].name; - if (!strncmpiW( dev, name, strlenW(dev) )) - { - p = name + strlenW( dev ); - if (!*p || (*p == '.') || (*p == ':')) { - static const WCHAR nulW[] = {'N','U','L',0}; - static const WCHAR conW[] = {'C','O','N',0}; - /* got it */ - if (!strcmpiW(DOSFS_Devices[i].name, nulW)) - return FILE_CreateFile( "/dev/null", access, - FILE_SHARE_READ|FILE_SHARE_WRITE, sa, - OPEN_EXISTING, 0, 0, TRUE, DRIVE_UNKNOWN ); - if (!strcmpiW(DOSFS_Devices[i].name, conW)) { - HANDLE to_dup; - switch (access & (GENERIC_READ|GENERIC_WRITE)) { - case GENERIC_READ: - to_dup = GetStdHandle( STD_INPUT_HANDLE ); - break; - case GENERIC_WRITE: - to_dup = GetStdHandle( STD_OUTPUT_HANDLE ); - break; - default: - FIXME("can't open CON read/write\n"); - return 0; - } - if (!DuplicateHandle( GetCurrentProcess(), to_dup, GetCurrentProcess(), - &handle, 0, - sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle, - DUPLICATE_SAME_ACCESS )) - handle = 0; - return handle; - } - - if( (handle=DOSFS_CreateCommPort(DOSFS_Devices[i].name,access,attributes,sa)) ) - return handle; - FIXME("device open %s not supported (yet)\n", debugstr_w(DOSFS_Devices[i].name)); - return 0; - } - } - } - return 0; -} - - /*********************************************************************** * DOSFS_GetPathDrive * @@ -1106,126 +954,3 @@ BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate, + tm->tm_mday; return TRUE; } - - -/*********************************************************************** - * QueryDosDeviceA (KERNEL32.@) - * - * returns array of strings terminated by \0, terminated by \0 - */ -DWORD WINAPI QueryDosDeviceA(LPCSTR devname,LPSTR target,DWORD bufsize) -{ - DWORD ret = 0, retW; - LPWSTR targetW = (LPWSTR)HeapAlloc(GetProcessHeap(),0, - bufsize * sizeof(WCHAR)); - UNICODE_STRING devnameW; - - if(devname) RtlCreateUnicodeStringFromAsciiz(&devnameW, devname); - else devnameW.Buffer = NULL; - - retW = QueryDosDeviceW(devnameW.Buffer, targetW, bufsize); - - ret = WideCharToMultiByte(CP_ACP, 0, targetW, retW, target, - bufsize, NULL, NULL); - - RtlFreeUnicodeString(&devnameW); - if (targetW) HeapFree(GetProcessHeap(),0,targetW); - return ret; -} - - -/*********************************************************************** - * QueryDosDeviceW (KERNEL32.@) - * - * returns array of strings terminated by \0, terminated by \0 - * - * FIXME - * - Win9x returns for all calls ERROR_INVALID_PARAMETER - * - the returned devices for devname == NULL is far from complete - * - its not checked that the returned device exist - */ -DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize) -{ - const WCHAR *pDev, *pName, *pNum = NULL; - int numsiz=0; - DWORD ret; - - TRACE("(%s,...)\n", debugstr_w(devname)); - if (!devname) { - /* return known MSDOS devices */ - DWORD ret = 0; - int i; - static const WCHAR devices[][5] = {{'A','U','X',0}, - {'C','O','M','1',0}, - {'C','O','M','2',0}, - {'L','P','T','1',0}, - {'N','U','L',0,}}; - for(i=0; (i< (sizeof(devices)/sizeof(devices[0]))); i++) { - DWORD len = strlenW(devices[i]); - if(target && (bufsize >= ret + len + 2)) { - strcpyW(target+ret, devices[i]); - ret += len + 1; - } else { - /* in this case WinXP returns 0 */ - FIXME("function return is wrong for WinXP!\n"); - SetLastError(ERROR_INSUFFICIENT_BUFFER); - break; - } - } - /* append drives here */ - if(target && bufsize > 0) target[ret++] = 0; - FIXME("Returned list is not complete\n"); - return ret; - } - /* In theory all that are possible and have been defined. - * Now just those below, since mirc uses it to check for special files. - * - * (It is more complex, and supports netmounted stuff, and \\.\ stuff, - * but currently we just ignore that.) - */ - if (!strcmpiW(devname, auxW)) { - pDev = dosW; - pName = comW; - numsiz = 1; - pNum = oneW; - } else if (!strcmpiW(devname, nulW)) { - pDev = devW; - pName = nullW; - } else if (!strncmpiW(devname, comW, strlenW(comW))) { - pDev = devW; - pName = serW; - pNum = devname + strlenW(comW); - for(numsiz=0; isdigitW(*(pNum+numsiz)); numsiz++); - if(*(pNum + numsiz)) { - SetLastError(ERROR_FILE_NOT_FOUND); - return 0; - } - } else if (!strncmpiW(devname, lptW, strlenW(lptW))) { - pDev = devW; - pName = parW; - pNum = devname + strlenW(lptW); - for(numsiz=0; isdigitW(*(pNum+numsiz)); numsiz++); - if(*(pNum + numsiz)) { - SetLastError(ERROR_FILE_NOT_FOUND); - return 0; - } - } else { - /* This might be a DOS device we do not handle yet ... */ - FIXME("(%s) not detected as DOS device!\n",debugstr_w(devname)); - - /* Win9x set the error ERROR_INVALID_PARAMETER */ - SetLastError(ERROR_FILE_NOT_FOUND); - return 0; -} - FIXME("device %s may not exist on this computer\n", debugstr_w(devname)); - - ret = strlenW(pDev) + strlenW(pName) + numsiz + 2; - if (ret > bufsize) ret = 0; - if (target && ret) { - strcpyW(target,pDev); - strcatW(target,pName); - if (pNum) strcatW(target,pNum); - target[ret-1] = 0; - } - return ret; -} diff --git a/files/drive.c b/files/drive.c index ce43e43b189..96a24f55ed3 100644 --- a/files/drive.c +++ b/files/drive.c @@ -620,87 +620,6 @@ int DRIVE_Chdir( int drive, LPCWSTR path ) } -/*********************************************************************** - * DefineDosDeviceA (KERNEL32.@) - */ -BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath) -{ - UNICODE_STRING d, t; - BOOL ret; - - if (!RtlCreateUnicodeStringFromAsciiz(&d, devname)) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - if (!RtlCreateUnicodeStringFromAsciiz(&t, targetpath)) - { - RtlFreeUnicodeString(&d); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - ret = DefineDosDeviceW(flags, d.Buffer, t.Buffer); - RtlFreeUnicodeString(&d); - RtlFreeUnicodeString(&t); - return ret; -} - - -/*********************************************************************** - * DefineDosDeviceA (KERNEL32.@) - */ -BOOL WINAPI DefineDosDeviceW(DWORD flags,LPCWSTR devname,LPCWSTR targetpath) -{ - DOSDRIVE *old, *new; - - /* this is a temporary hack for int21 support. better implementation has to be done */ - if (flags != DDD_RAW_TARGET_PATH || - !(toupperW(devname[0]) >= 'A' && toupperW(devname[0]) <= 'Z') || - devname[1] != ':' || devname[2] != 0 || - !(toupperW(targetpath[0]) >= 'A' && toupperW(targetpath[0]) <= 'Z') || - targetpath[1] != ':' || targetpath[2] != '\\' || targetpath[3] != 0) - { - FIXME("(0x%08lx,%s,%s),stub!\n", flags, debugstr_w(devname), debugstr_w(targetpath)); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; - } - - old = DOSDrives + devname[0] - 'A'; - new = DOSDrives + targetpath[0] - 'A'; - - if (!old->root) - { - SetLastError( ERROR_INVALID_DRIVE ); - return 0; - } - - if ( new->root ) - { - TRACE("Can't map drive %c: to already existing drive %c:\n", - devname[0], targetpath[0] ); - /* it is already mapped there, so return success */ - if (!strcmp(old->root,new->root)) - return 1; - return 0; - } - - new->root = heap_strdup( old->root ); - new->dos_cwd = HeapAlloc(GetProcessHeap(), 0, (strlenW(old->dos_cwd) + 1) * sizeof(WCHAR)); - strcpyW(new->dos_cwd, old->dos_cwd); - new->unix_cwd = heap_strdup( old->unix_cwd ); - new->device = heap_strdup( old->device ); - new->type = old->type; - new->flags = old->flags; - new->dev = old->dev; - new->ino = old->ino; - - TRACE("Drive %c: is now equal to drive %c:\n", - targetpath[0], devname[0] ); - - return 1; -} - - /*********************************************************************** * DRIVE_GetFreeSpace */ diff --git a/files/file.c b/files/file.c index 8ec467a58a7..a28e40514a5 100644 --- a/files/file.c +++ b/files/file.c @@ -318,6 +318,7 @@ HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, { DOS_FULL_NAME full_name; HANDLE ret; + DWORD dosdev; static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0}; static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0}; static const WCHAR bkslashesW[] = {'\\','\\',0}; @@ -342,6 +343,13 @@ HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ": (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes); + /* Open a console for CONIN$ or CONOUT$ */ + if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW)) + { + ret = OpenConsoleW(filename, access, (sa && sa->bInheritHandle), creation); + goto done; + } + /* If the name starts with '\\?\', ignore the first 4 chars. */ if (!strncmpW(filename, bkslashes_with_question_markW, 4)) { @@ -379,13 +387,47 @@ HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, } goto done; } - else if (!RtlIsDosDeviceName_U( filename + 4 )) + else if ((dosdev = RtlIsDosDeviceName_U( filename + 4 ))) + { + dosdev += MAKELONG( 0, 4*sizeof(WCHAR) ); /* adjust position to start of filename */ + } + else { ret = VXD_Open( filename+4, access, sa ); goto done; } - else - filename+=4; /* fall into DOSFS_Device case below */ + } + else dosdev = RtlIsDosDeviceName_U( filename ); + + if (dosdev) + { + static const WCHAR conW[] = {'C','O','N',0}; + WCHAR dev[5]; + + memcpy( dev, filename + HIWORD(dosdev)/sizeof(WCHAR), LOWORD(dosdev) ); + dev[LOWORD(dosdev)/sizeof(WCHAR)] = 0; + + TRACE("opening device %s\n", debugstr_w(dev) ); + + if (!strcmpiW( dev, conW )) + { + switch (access & (GENERIC_READ|GENERIC_WRITE)) + { + case GENERIC_READ: + ret = OpenConsoleW(coninW, access, (sa && sa->bInheritHandle), creation); + goto done; + case GENERIC_WRITE: + ret = OpenConsoleW(conoutW, access, (sa && sa->bInheritHandle), creation); + goto done; + default: + FIXME("can't open CON read/write\n"); + SetLastError( ERROR_FILE_NOT_FOUND ); + return INVALID_HANDLE_VALUE; + } + } + + ret = VOLUME_OpenDevice( dev, access, sharing, sa, attributes ); + goto done; } /* If the name still starts with '\\', it's a UNC name. */ @@ -402,26 +444,6 @@ HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, return INVALID_HANDLE_VALUE; } - /* Open a console for CONIN$ or CONOUT$ */ - if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW)) - { - ret = OpenConsoleW(filename, access, (sa && sa->bInheritHandle), creation); - goto done; - } - - if (RtlIsDosDeviceName_U( filename )) - { - TRACE("opening device %s\n", debugstr_w(filename) ); - - if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa ))) - { - /* Do not silence this please. It is a critical error. -MM */ - ERR("Couldn't open device %s!\n", debugstr_w(filename)); - SetLastError( ERROR_FILE_NOT_FOUND ); - } - goto done; - } - /* check for filename, don't check for last entry if creating */ if (!DOSFS_GetFullName( filename, (creation == OPEN_EXISTING) || diff --git a/include/file.h b/include/file.h index 32166b78f02..51c75ba9ee8 100644 --- a/include/file.h +++ b/include/file.h @@ -50,7 +50,6 @@ extern DWORD DIR_SearchPath( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DOS_FULL_NAME *full_name, BOOL win32 ); /* files/dos_fs.c */ -extern HANDLE DOSFS_OpenDevice( LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa); extern BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *long_buf, INT long_len, LPWSTR short_buf ); extern BOOL DOSFS_GetFullName( LPCWSTR name, BOOL check_last,