This patch makes the server interface for opening files unicode. It also intentionally breaks NtOpenFile, since the implemenation was a bad hack. Mike License: LGPL ChangeLog: * unicodify the create_file server call * use unicode for filenames inside the server
Index: dlls/ntdll/file.c =================================================================== RCS file: /home/wine/wine/dlls/ntdll/file.c,v retrieving revision 1.14 diff -u -r1.14 file.c --- dlls/ntdll/file.c 14 Jun 2002 00:36:20 -0000 1.14 +++ dlls/ntdll/file.c 19 Jun 2002 17:23:09 -0000 @@ -30,7 +30,6 @@ #include "wine/debug.h" #include "wine/server.h" #include "ntdll_misc.h" -#include "file.h" /* FIXME */ #include "ntddk.h" #include "winioctl.h" @@ -58,12 +57,8 @@ ULONG ShareAccess, ULONG OpenOptions) { - ULONG len = 0; - PSTR filename; - CHAR szDosDevices[] = "\\DosDevices\\"; - DOS_FULL_NAME full_name; NTSTATUS r; - + FIXME("(%p,0x%08lx,%p,%p,0x%08lx,0x%08lx) partial stub\n", FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); @@ -77,24 +72,7 @@ return STATUS_OBJECT_NAME_NOT_FOUND; } - /* create an ascii string from the unicode filename */ - RtlUnicodeToMultiByteSize( &len, ObjectAttributes->ObjectName->Buffer, - ObjectAttributes->ObjectName->Length ); - filename = RtlAllocateHeap( GetProcessHeap(), 0, len + 1); - RtlUnicodeToMultiByteN(filename, len, NULL, ObjectAttributes->ObjectName->Buffer, - ObjectAttributes->ObjectName->Length ); - filename[len]=0; - - /* FIXME: DOSFS stuff should call here, not vice-versa */ - if(strncmp(filename, szDosDevices, strlen(szDosDevices))) - return STATUS_OBJECT_NAME_NOT_FOUND; - - /* FIXME: this calls SetLastError() -> bad */ - if(!DOSFS_GetFullName(&filename[strlen(szDosDevices)], TRUE, - &full_name)) - return STATUS_OBJECT_NAME_NOT_FOUND; - - /* FIXME: modify server protocol so + /* FIXME: modify server protocol so create file takes an OBJECT_ATTRIBUTES structure */ SERVER_START_REQ( create_file ) { @@ -103,9 +81,8 @@ req->sharing = ShareAccess; req->create = OPEN_EXISTING; req->attrs = 0; - req->drive_type = GetDriveTypeA( full_name.short_name ); - wine_server_add_data( req, full_name.long_name, strlen(full_name.long_name) ); - SetLastError(0); + req->drive_type = -1; + wine_server_add_data( req, ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length ); r = wine_server_call( req ); *FileHandle = reply->handle; } Index: files/file.c =================================================================== RCS file: /home/wine/wine/files/file.c,v retrieving revision 1.149 diff -u -r1.149 file.c --- files/file.c 5 Jun 2002 00:47:38 -0000 1.149 +++ files/file.c 19 Jun 2002 17:23:11 -0000 @@ -378,6 +378,8 @@ { unsigned int err; HANDLE ret; + WCHAR name[MAX_PATH]; + int len = MultiByteToWideChar(CP_ACP,0,filename,-1,name,MAX_PATH); for (;;) { @@ -389,7 +391,7 @@ req->create = creation; req->attrs = attributes; req->drive_type = drive_type; - wine_server_add_data( req, filename, strlen(filename) ); + wine_server_add_data( req, name, len*sizeof(WCHAR) ); SetLastError(0); err = wine_server_call( req ); ret = reply->handle; @@ -403,7 +405,7 @@ if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED)) { TRACE("Write access failed for file '%s', trying without " - "write access\n", filename); + "write access\n", debugstr_w(name)); access &= ~GENERIC_WRITE; continue; } @@ -411,7 +413,7 @@ if (err) SetLastError( RtlNtStatusToDosError(err) ); - if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError()); + if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", debugstr_wn(name,len), GetLastError()); return ret; } } Index: server/file.c =================================================================== RCS file: /home/wine/wine/server/file.c,v retrieving revision 1.58 diff -u -r1.58 file.c --- server/file.c 30 May 2002 20:12:58 -0000 1.58 +++ server/file.c 19 Jun 2002 17:23:11 -0000 @@ -44,12 +44,13 @@ #include "thread.h" #include "request.h" #include "async.h" +#include "unicode.h" struct file { struct object obj; /* object header */ struct file *next; /* next file in hashing list */ - char *name; /* file name */ + WCHAR *name; /* file name */ unsigned int access; /* file access (GENERIC_READ/WRITE) */ unsigned int flags; /* flags (FILE_FLAG_*) */ unsigned int sharing; /* file sharing mode */ @@ -89,16 +90,16 @@ }; -static int get_name_hash( const char *name ) +static int get_name_hash( const WCHAR *name ) { int hash = 0; - while (*name) hash ^= (unsigned char)*name++; + while (*name) hash ^= (unsigned short)*name++; return hash % NAME_HASH_SIZE; } /* check if the desired access is possible without violating */ /* the sharing mode of other opens of the same file */ -static int check_sharing( const char *name, int hash, unsigned int access, +static int check_sharing( const WCHAR *name, int hash, unsigned int access, unsigned int sharing ) { struct file *file; @@ -107,7 +108,7 @@ for (file = file_hash[hash]; file; file = file->next) { - if (strcmp( file->name, name )) continue; + if (strcmpW( file->name, name )) continue; existing_sharing &= file->sharing; existing_access |= file->access; } @@ -144,20 +145,19 @@ return file; } - -static struct file *create_file( const char *nameptr, size_t len, unsigned int access, +struct object *create_file( const WCHAR *nameptr, size_t len, unsigned int access, unsigned int sharing, int create, unsigned int attrs, int drive_type ) { struct file *file; int hash, flags; struct stat st; - char *name; + WCHAR *name, szwCom[] = {'.','c','o','m',0 }, szwExe[] = {'.','e','x','e',0 }; int fd = -1; mode_t mode; - if (!(name = mem_alloc( len + 1 ))) return NULL; - memcpy( name, nameptr, len ); + if (!(name = mem_alloc( (len+1)*sizeof (WCHAR) ))) return NULL; + memcpy( name, nameptr, len*sizeof (WCHAR) ); name[len] = 0; /* check sharing mode */ @@ -183,11 +183,11 @@ mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666; if (len >= 4 && - (!strcasecmp( name + len - 4, ".exe" ) || !strcasecmp( name + len - 4, ".com" ))) + (!strcmpiW( name + len - 4, szwExe ) || !strcmpiW( name + len - 4, szwCom ))) mode |= 0111; /* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */ - if ((fd = open( name, flags | O_NONBLOCK | O_LARGEFILE, mode )) == -1 ) + if ((fd = openw( name, flags | O_NONBLOCK | O_LARGEFILE, mode )) == -1 ) goto file_error; /* refuse to open a directory */ if (fstat( fd, &st ) == -1) goto file_error; @@ -205,7 +205,7 @@ file->name = name; file->next = file_hash[hash]; file_hash[hash] = file; - return file; + return &file->obj; file_error: file_set_error(); @@ -218,7 +218,7 @@ /* check if two file objects point to the same file */ int is_same_file( struct file *file1, struct file *file2 ) { - return !strcmp( file1->name, file2->name ); + return !strcmpW( file1->name, file2->name ); } /* get the type of drive the file is on */ @@ -264,7 +264,9 @@ { struct file *file = (struct file *)obj; assert( obj->ops == &file_ops ); - fprintf( stderr, "File fd=%d flags=%08x name='%s'\n", file->obj.fd, file->flags, file->name ); + fprintf( stderr, "File fd=%d flags=%08x name=", file->obj.fd, file->flags ); + dump_strW(file->name,strlenW(file->name),stderr,"[]"); + fprintf( stderr, "\n" ); } static int file_get_poll_events( struct object *obj ) @@ -427,7 +429,7 @@ while (*pptr && *pptr != file) pptr = &(*pptr)->next; assert( *pptr ); *pptr = (*pptr)->next; - if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlink( file->name ); + if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlinkw( file->name ); free( file->name ); } if (file->flags & FILE_FLAG_OVERLAPPED) @@ -564,13 +566,13 @@ if (!access_time || !write_time) { struct stat st; - if (stat( file->name, &st ) == -1) goto error; + if (statw( file->name, &st ) == -1) goto error; if (!access_time) access_time = st.st_atime; if (!write_time) write_time = st.st_mtime; } utimbuf.actime = access_time; utimbuf.modtime = write_time; - if (utime( file->name, &utimbuf ) == -1) goto error; + if (utimew( file->name, &utimbuf ) == -1) goto error; release_object( file ); return 1; error: @@ -596,11 +598,24 @@ /* create a file */ DECL_HANDLER(create_file) { - struct file *file; + struct object *file = NULL; + const WCHAR *name = get_req_data(); + int len = get_req_data_size()/sizeof (WCHAR); reply->handle = 0; - if ((file = create_file( get_req_data(), get_req_data_size(), req->access, - req->sharing, req->create, req->attrs, req->drive_type ))) + + if(len && (name[0]!='/')) /* nt path name */ + { + /* FIXME: open an NT path here */ + set_error(STATUS_ACCESS_DENIED); + } + else + { + file = create_file( name, len, req->access, + req->sharing, req->create, req->attrs, req->drive_type ); + } + + if (file) { reply->handle = alloc_handle( current->process, file, req->access, req->inherit ); release_object( file ); Index: server/protocol.def =================================================================== RCS file: /home/wine/wine/server/protocol.def,v retrieving revision 1.39 diff -u -r1.39 protocol.def --- server/protocol.def 2 Jun 2002 21:22:22 -0000 1.39 +++ server/protocol.def 19 Jun 2002 17:23:12 -0000 @@ -572,7 +572,7 @@ int create; /* file create action */ unsigned int attrs; /* file attributes for creation */ int drive_type; /* type of drive the file is on */ - VARARG(filename,string); /* file name */ + VARARG(filename,unicode_str); /* file name */ @REPLY obj_handle_t handle; /* handle to the file */ @END Index: server/unicode.c =================================================================== RCS file: /home/wine/wine/server/unicode.c,v retrieving revision 1.4 diff -u -r1.4 unicode.c --- server/unicode.c 26 Apr 2002 19:05:18 -0000 1.4 +++ server/unicode.c 19 Jun 2002 17:23:12 -0000 @@ -24,8 +24,18 @@ #include <ctype.h> #include <stdio.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <errno.h> + +#include "thread.h" #include "unicode.h" +static const union cptable *ansi_cptable; + + /* dump a Unicode string with proper escaping */ int dump_strW( const WCHAR *str, size_t len, FILE *f, char escape[2] ) { @@ -68,3 +78,85 @@ count += pos - buffer; return count; } + +int strcasecmpnW(const WCHAR *x, const WCHAR *y, int n) +{ + int i; + for(i=0; i<n; i++) + { + if((x[i]&~0x20)>(y[i]&~0x20)) + return 1; + if((x[i]&~0x20)<(y[i]&~0x20)) + return -1; + } + return 0; +} + +/* FIXME: hardcoded to ANSI for the time being */ + +int file_unicode_to_apath(const WCHAR *path_w, char *path_a, int len) +{ + if(!ansi_cptable) + ansi_cptable = cp_get_table( 1252 ); + return cp_wcstombs( ansi_cptable, 0, path_w, -1, path_a, len, NULL, NULL); +} + +int file_apath_to_unicode(const char *path_a, WCHAR *path_w, int len) +{ + if(!ansi_cptable) + ansi_cptable = cp_get_table( 1252 ); + return cp_mbstowcs( ansi_cptable, 0, path_a, -1, path_w, len); +} + +int openw(const WCHAR *name, int access, int mode) +{ + char name_a[MAX_PATH]; + name_a[0]=0; + file_unicode_to_apath(name,name_a,MAX_PATH); + return open(name_a,access,mode); +} + +int unlinkw(const WCHAR *name) +{ + char name_a[MAX_PATH]; + name_a[0]=0; + file_unicode_to_apath(name,name_a,MAX_PATH); + return unlink(name_a); +} + +int statw(const WCHAR *name, struct stat *st) +{ + char name_a[MAX_PATH]; + name_a[0]=0; + file_unicode_to_apath(name,name_a,MAX_PATH); + return stat(name_a,st); +} + +int utimew(const WCHAR *name, struct utimbuf *utimbuf) +{ + char name_a[MAX_PATH]; + name_a[0]=0; + file_unicode_to_apath(name,name_a,MAX_PATH); + return utime(name_a,utimbuf); +} + +DIR *opendirw(const WCHAR *name) +{ + char name_a[MAX_PATH]; + name_a[0]=0; + file_unicode_to_apath(name,name_a,MAX_PATH); + return opendir(name_a); +} + +static struct direntw g_de; + +struct direntw *readdirw(DIR *dir) +{ + struct dirent *de = readdir(dir); + if(!de) + return NULL; + g_de.d_name[0]=0; + file_apath_to_unicode(de->d_name, g_de.d_name, sizeof(g_de.d_name)/sizeof(WCHAR)); + return &g_de; +} + Index: server/unicode.h =================================================================== RCS file: /home/wine/wine/server/unicode.h,v retrieving revision 1.8 diff -u -r1.8 unicode.h --- server/unicode.h 10 Mar 2002 00:18:36 -0000 1.8 +++ server/unicode.h 19 Jun 2002 17:23:12 -0000 @@ -22,6 +22,9 @@ #define __WINE_SERVER_UNICODE_H #include <stdio.h> +#include <dirent.h> +#include <sys/time.h> +#include <utime.h> #include "windef.h" #include "wine/unicode.h" @@ -35,4 +38,20 @@ extern int dump_strW( const WCHAR *str, size_t len, FILE *f, char escape[2] ); +extern int strcasecmpnW(const WCHAR *x, const WCHAR *y, int n); + +extern int openw(const WCHAR *name, int access, int mode); +extern int unlinkw(const WCHAR *name); +extern int statw(const WCHAR *name, struct stat *st); +extern int utimew(const WCHAR *name, struct utimbuf *utimbuf); + +struct direntw +{ + WCHAR d_name[NAME_MAX+1]; +}; + +extern DIR *opendirw(const WCHAR *name); +extern struct direntw *readdirw(DIR *dir); + #endif /* __WINE_SERVER_UNICODE_H */ +