server: Store a duplicate of the file descriptor for file mappings.
diff --git a/server/fd.c b/server/fd.c
index f57ed97..a4018ee 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1488,6 +1488,59 @@
return fd;
}
+/* duplicate an fd object for a different user */
+struct fd *dup_fd_object( struct fd *orig )
+{
+ struct fd *fd = alloc_object( &fd_ops );
+
+ if (!fd) return NULL;
+
+ fd->fd_ops = NULL;
+ fd->user = NULL;
+ fd->inode = NULL;
+ fd->closed = NULL;
+ fd->access = orig->access;
+ fd->options = orig->options;
+ fd->sharing = orig->sharing;
+ fd->unix_fd = -1;
+ fd->signaled = 0;
+ fd->fs_locks = 0;
+ fd->poll_index = -1;
+ fd->read_q = NULL;
+ fd->write_q = NULL;
+ fd->wait_q = NULL;
+ fd->completion = NULL;
+ list_init( &fd->inode_entry );
+ list_init( &fd->locks );
+
+ if (!(fd->unix_name = mem_alloc( strlen(orig->unix_name) + 1 ))) goto failed;
+ strcpy( fd->unix_name, orig->unix_name );
+ if ((fd->poll_index = add_poll_user( fd )) == -1) goto failed;
+
+ if (orig->inode)
+ {
+ struct closed_fd *closed = mem_alloc( sizeof(*closed) );
+ if (!closed) goto failed;
+ if ((fd->unix_fd = dup( orig->unix_fd )) == -1)
+ {
+ free( closed );
+ goto failed;
+ }
+ closed->unix_fd = fd->unix_fd;
+ closed->unlink[0] = 0;
+ fd->closed = closed;
+ fd->inode = (struct inode *)grab_object( orig->inode );
+ list_add_head( &fd->inode->open, &fd->inode_entry );
+ }
+ else if ((fd->unix_fd = dup( orig->unix_fd )) == -1) goto failed;
+
+ return fd;
+
+failed:
+ release_object( fd );
+ return NULL;
+}
+
/* set the status to return when the fd has no associated unix fd */
void set_no_fd_status( struct fd *fd, unsigned int status )
{
@@ -1839,6 +1892,11 @@
fd->fd_ops->reselect_async( fd, queue );
}
+void no_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
+{
+ set_error( STATUS_OBJECT_TYPE_MISMATCH );
+}
+
void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
{
struct async *async;
@@ -1927,6 +1985,13 @@
release_object( device );
}
+obj_handle_t no_fd_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
+ int blocking, const void *data, data_size_t size )
+{
+ set_error( STATUS_OBJECT_TYPE_MISMATCH );
+ return 0;
+}
+
/* default ioctl() routine */
obj_handle_t default_fd_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
int blocking, const void *data, data_size_t size )
diff --git a/server/file.h b/server/file.h
index 21b3879..27aed39 100644
--- a/server/file.h
+++ b/server/file.h
@@ -58,6 +58,7 @@
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 );
extern void *get_fd_user( struct fd *fd );
extern void set_fd_user( struct fd *fd, const struct fd_ops *ops, struct object *user );
extern unsigned int get_fd_options( struct fd *fd );
@@ -79,8 +80,11 @@
extern struct async *fd_queue_async( struct fd *fd, const async_data_t *data, int type );
extern void fd_async_wake_up( struct fd *fd, int type, unsigned int status );
extern void fd_reselect_async( struct fd *fd, struct async_queue *queue );
+extern obj_handle_t no_fd_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
+ int blocking, const void *data, data_size_t size );
extern obj_handle_t default_fd_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
int blocking, const void *data, data_size_t size );
+extern void no_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count );
extern void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count );
extern void default_fd_reselect_async( struct fd *fd, struct async_queue *queue );
extern void default_fd_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb );
diff --git a/server/mapping.c b/server/mapping.c
index 67760c9..e3f69a8 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -70,6 +70,7 @@
static struct fd *mapping_get_fd( struct object *obj );
static unsigned int mapping_map_access( struct object *obj, unsigned int access );
static void mapping_destroy( struct object *obj );
+static enum server_fd_type mapping_get_fd_type( struct fd *fd );
static const struct object_ops mapping_ops =
{
@@ -91,6 +92,18 @@
mapping_destroy /* destroy */
};
+static const struct fd_ops mapping_fd_ops =
+{
+ default_fd_get_poll_events, /* get_poll_events */
+ default_poll_event, /* poll_event */
+ no_flush, /* flush */
+ mapping_get_fd_type, /* get_fd_type */
+ no_fd_ioctl, /* ioctl */
+ no_fd_queue_async, /* queue_async */
+ default_fd_reselect_async, /* reselect_async */
+ default_fd_cancel_async /* cancel_async */
+};
+
static struct list shared_list = LIST_INIT(shared_list);
#ifdef __i386__
@@ -396,6 +409,8 @@
obj_handle_t handle, const struct security_descriptor *sd )
{
struct mapping *mapping;
+ struct file *file;
+ struct fd *fd;
int access = 0;
int unix_fd;
struct stat st;
@@ -428,8 +443,14 @@
set_error( STATUS_INVALID_PARAMETER );
goto error;
}
- if (!(mapping->file = get_file_obj( current->process, handle, access ))) goto error;
- mapping->fd = get_obj_fd( (struct object *)mapping->file );
+ if (!(file = get_file_obj( current->process, handle, access ))) goto error;
+ fd = get_obj_fd( (struct object *)file );
+ mapping->fd = dup_fd_object( fd );
+ release_object( file );
+ release_object( fd );
+ if (!mapping->fd) goto error;
+
+ set_fd_user( mapping->fd, &mapping_fd_ops, &mapping->obj );
if ((unix_fd = get_unix_fd( mapping->fd )) == -1) goto error;
if (protect & VPROT_IMAGE)
{
@@ -527,6 +548,11 @@
free( mapping->committed );
}
+static enum server_fd_type mapping_get_fd_type( struct fd *fd )
+{
+ return FD_TYPE_FILE;
+}
+
int get_page_size(void)
{
if (!page_mask) init_page_size();