diff --git a/server/device.c b/server/device.c index 843ba3423ca..5e936b05f0f 100644 --- a/server/device.c +++ b/server/device.c @@ -446,6 +446,7 @@ static struct object *device_open_file( struct object *obj, unsigned int access, { struct device *device = (struct device *)obj; struct device_file *file; + struct unicode_str nt_name; if (!(file = alloc_object( &device_file_ops ))) return NULL; @@ -458,7 +459,8 @@ static struct object *device_open_file( struct object *obj, unsigned int access, { mode_t mode = 0666; access = file->obj.ops->map_access( &file->obj, access ); - file->fd = open_fd( NULL, device->unix_path, O_NONBLOCK | O_LARGEFILE, + nt_name.str = device->obj.ops->get_full_name( &device->obj, &nt_name.len ); + file->fd = open_fd( NULL, device->unix_path, nt_name, O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options ); if (file->fd) set_fd_user( file->fd, &device_file_fd_ops, &file->obj ); } diff --git a/server/fd.c b/server/fd.c index 079508c2d95..2dcdd04a892 100644 --- a/server/fd.c +++ b/server/fd.c @@ -185,6 +185,8 @@ struct fd unsigned int options; /* file options (FILE_DELETE_ON_CLOSE, FILE_SYNCHRONOUS...) */ unsigned int sharing; /* file sharing mode */ char *unix_name; /* unix file name */ + WCHAR *nt_name; /* NT file name */ + data_size_t nt_namelen; /* length of NT file name */ int unix_fd; /* unix file descriptor */ unsigned int no_fd_status;/* status to return when unix_fd is -1 */ unsigned int cacheable :1;/* can the fd be cached on the client side? */ @@ -1570,6 +1572,7 @@ static void fd_destroy( struct object *obj ) remove_fd_locks( fd ); list_remove( &fd->inode_entry ); if (fd->poll_index != -1) remove_poll_user( fd, fd->poll_index ); + free( fd->nt_name ); if (fd->inode) { inode_add_closed_fd( fd->inode, fd->closed ); @@ -1688,6 +1691,8 @@ static struct fd *alloc_fd_object(void) fd->sharing = 0; fd->unix_fd = -1; fd->unix_name = NULL; + fd->nt_name = NULL; + fd->nt_namelen = 0; fd->cacheable = 0; fd->signaled = 1; fd->fs_locks = 1; @@ -1723,6 +1728,8 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use fd->options = options; fd->sharing = 0; fd->unix_name = NULL; + fd->nt_name = NULL; + fd->nt_namelen = 0; fd->unix_fd = -1; fd->cacheable = 0; fd->signaled = 0; @@ -1755,6 +1762,11 @@ struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sha if (!(fd->unix_name = mem_alloc( strlen(orig->unix_name) + 1 ))) goto failed; strcpy( fd->unix_name, orig->unix_name ); } + if (orig->nt_namelen) + { + if (!(fd->nt_name = memdup( orig->nt_name, orig->nt_namelen ))) goto failed; + fd->nt_namelen = orig->nt_namelen; + } if (orig->inode) { @@ -1831,8 +1843,50 @@ char *dup_fd_name( struct fd *root, const char *name ) return ret; } +static WCHAR *dup_nt_name( struct fd *root, struct unicode_str name, data_size_t *len ) +{ + WCHAR *ret; + data_size_t retlen; + + if (!root) + { + *len = name.len; + if (!name.len) return NULL; + return memdup( name.str, name.len ); + } + if (!root->nt_namelen) return NULL; + retlen = root->nt_namelen; + + /* skip . prefix */ + if (name.len && name.str[0] == '.' && (name.len == sizeof(WCHAR) || name.str[1] == '\\')) + { + name.str++; + name.len -= sizeof(WCHAR); + } + if ((ret = malloc( retlen + name.len + 1 ))) + { + memcpy( ret, root->nt_name, root->nt_namelen ); + if (name.len && name.str[0] != '\\' && + root->nt_namelen && root->nt_name[root->nt_namelen / sizeof(WCHAR) - 1] != '\\') + { + ret[retlen / sizeof(WCHAR)] = '\\'; + retlen += sizeof(WCHAR); + } + memcpy( ret + retlen / sizeof(WCHAR), name.str, name.len ); + *len = retlen + name.len; + } + return ret; +} + +void get_nt_name( struct fd *fd, struct unicode_str *name ) +{ + name->str = fd->nt_name; + name->len = fd->nt_namelen; +} + /* open() wrapper that returns a struct fd with no fd user set */ -struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, unsigned int access, +struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_name, + int flags, mode_t *mode, unsigned int access, unsigned int sharing, unsigned int options ) { struct stat st; @@ -1906,6 +1960,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, } } + fd->nt_name = dup_nt_name( root, nt_name, &fd->nt_namelen ); fd->unix_name = NULL; if ((path = dup_fd_name( root, name ))) { @@ -2437,8 +2492,8 @@ static void set_fd_disposition( struct fd *fd, int unlink ) } /* set new name for the fd */ -static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, - data_size_t len, int create_link, int replace ) +static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, data_size_t len, + struct unicode_str nt_name, int create_link, int replace ) { struct inode *inode; struct stat st, st2; @@ -2553,6 +2608,8 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, fchmod( fd->unix_fd, st.st_mode ); } + free( fd->nt_name ); + fd->nt_name = dup_nt_name( root, nt_name, &fd->nt_namelen ); free( fd->unix_name ); fd->closed->unix_name = fd->unix_name = realpath( name, NULL ); free( name ); @@ -2824,12 +2881,15 @@ DECL_HANDLER(set_fd_disp_info) DECL_HANDLER(set_fd_name_info) { struct fd *fd, *root_fd = NULL; + struct unicode_str nt_name; if (req->namelen > get_req_data_size()) { set_error( STATUS_INVALID_PARAMETER ); return; } + nt_name.str = get_req_data(); + nt_name.len = (req->namelen / sizeof(WCHAR)) * sizeof(WCHAR); if (req->rootdir) { @@ -2844,7 +2904,7 @@ DECL_HANDLER(set_fd_name_info) if ((fd = get_handle_fd_obj( current->process, req->handle, 0 ))) { set_fd_name( fd, root_fd, (const char *)get_req_data() + req->namelen, - get_req_data_size() - req->namelen, req->link, req->replace ); + get_req_data_size() - req->namelen, nt_name, req->link, req->replace ); release_object( fd ); } if (root_fd) release_object( root_fd ); diff --git a/server/file.c b/server/file.c index eaf73115155..f9ce0106c3b 100644 --- a/server/file.c +++ b/server/file.c @@ -210,6 +210,7 @@ int is_file_executable( const char *name ) } static struct object *create_file( struct fd *root, const char *nameptr, data_size_t len, + struct unicode_str nt_name, unsigned int access, unsigned int sharing, int create, unsigned int options, unsigned int attrs, const struct security_descriptor *sd ) @@ -220,7 +221,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si char *name; mode_t mode; - if (!len || ((nameptr[0] == '/') ^ !root)) + if (!len || ((nameptr[0] == '/') ^ !root) || (nt_name.len && ((nt_name.str[0] == '\\') ^ !root))) { set_error( STATUS_OBJECT_PATH_SYNTAX_BAD ); return NULL; @@ -267,7 +268,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si access = map_access( access, &file_type.mapping ); /* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */ - fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options ); + fd = open_fd( root, name, nt_name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options ); if (!fd) goto done; if (S_ISDIR(mode)) @@ -603,13 +604,15 @@ static struct object *file_open_file( struct object *obj, unsigned int access, { struct file *file = (struct file *)obj; struct object *new_file = NULL; + struct unicode_str nt_name; char *unix_name; assert( obj->ops == &file_ops ); if ((unix_name = dup_fd_name( file->fd, "" ))) { - new_file = create_file( NULL, unix_name, strlen(unix_name), access, + get_nt_name( file->fd, &nt_name ); + new_file = create_file( NULL, unix_name, strlen(unix_name), nt_name, access, sharing, FILE_OPEN, options, 0, NULL ); free( unix_name ); } @@ -706,7 +709,7 @@ DECL_HANDLER(create_file) name = get_req_data_after_objattr( objattr, &name_len ); reply->handle = 0; - if ((file = create_file( root_fd, name, name_len, req->access, req->sharing, + if ((file = create_file( root_fd, name, name_len, nt_name, req->access, req->sharing, req->create, req->options, req->attrs, sd ))) { reply->handle = alloc_handle( current->process, file, req->access, objattr->attributes ); diff --git a/server/file.h b/server/file.h index 686bae084c5..b36cca7c5d2 100644 --- a/server/file.h +++ b/server/file.h @@ -78,8 +78,9 @@ struct fd_ops extern struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *user, unsigned int options ); -extern struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, - unsigned int access, unsigned int sharing, unsigned int options ); +extern struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_name, + int flags, mode_t *mode, unsigned int access, + unsigned int sharing, unsigned int options ); extern struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, int unix_fd, struct object *user, unsigned int options ); extern struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing, @@ -100,6 +101,7 @@ extern void unlock_fd( struct fd *fd, file_pos_t offset, file_pos_t count ); extern void allow_fd_caching( struct fd *fd ); extern void set_fd_signaled( struct fd *fd, int signaled ); extern char *dup_fd_name( struct fd *root, const char *name ); +extern void get_nt_name( struct fd *fd, struct unicode_str *name ); extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ); extern int default_fd_get_poll_events( struct fd *fd ); diff --git a/server/unicode.c b/server/unicode.c index 56f3c024103..55f9954f4f4 100644 --- a/server/unicode.c +++ b/server/unicode.c @@ -264,6 +264,9 @@ static char *get_nls_dir(void) struct fd *load_intl_file(void) { static const char *nls_dirs[] = { NULL, NLSDIR, "/usr/local/share/wine/nls", "/usr/share/wine/nls" }; + static const WCHAR nt_pathW[] = {'C',':','\\','w','i','n','d','o','w','s','\\', + 's','y','s','t','e','m','3','2','\\','l','_','i','n','t','l','.','n','l','s',0}; + static const struct unicode_str nt_name = { nt_pathW, sizeof(nt_pathW) }; unsigned int i, offset, size; unsigned short data; char *path; @@ -278,7 +281,7 @@ struct fd *load_intl_file(void) if (!(path = malloc( strlen(nls_dirs[i]) + sizeof("/l_intl.nls" )))) continue; strcpy( path, nls_dirs[i] ); strcat( path, "/l_intl.nls" ); - if ((fd = open_fd( NULL, path, O_RDONLY, &mode, FILE_READ_DATA, + if ((fd = open_fd( NULL, path, nt_name, O_RDONLY, &mode, FILE_READ_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) break; free( path );