server: Support for opening devices.
Added support for opening devices directly with the server when they
don't correspond to a Unix file.
diff --git a/server/fd.c b/server/fd.c
index 4ab7cbc..07ae40e 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -145,7 +145,8 @@
     unsigned int         access;      /* file access (GENERIC_READ/WRITE) */
     unsigned int         sharing;     /* file sharing mode */
     int                  unix_fd;     /* unix file descriptor */
-    int                  fs_locks;    /* can we use filesystem locks for this fd? */
+    int                  fs_locks :1; /* can we use filesystem locks for this fd? */
+    int                  unmounted :1;/* has the device been unmounted? */
     int                  poll_index;  /* index of fd in poll array */
     struct list          read_q;      /* async readers of this fd */
     struct list          write_q;     /* async writers of this fd */
@@ -1210,6 +1211,7 @@
     if (fd->unix_fd != -1) close( fd->unix_fd );
 
     fd->unix_fd = -1;
+    fd->unmounted = 1;
     fd->closed->unix_fd = -1;
     fd->closed->unlink[0] = 0;
 
@@ -1232,6 +1234,7 @@
     fd->sharing    = 0;
     fd->unix_fd    = -1;
     fd->fs_locks   = 1;
+    fd->unmounted  = 0;
     fd->poll_index = -1;
     list_init( &fd->inode_entry );
     list_init( &fd->locks );
@@ -1246,6 +1249,30 @@
     return fd;
 }
 
+/* allocate a pseudo fd object, for objects that need to behave like files but don't have a unix fd */
+struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *user )
+{
+    struct fd *fd = alloc_object( &fd_ops );
+
+    if (!fd) return NULL;
+
+    fd->fd_ops     = fd_user_ops;
+    fd->user       = user;
+    fd->inode      = NULL;
+    fd->closed     = NULL;
+    fd->access     = 0;
+    fd->sharing    = 0;
+    fd->unix_fd    = -1;
+    fd->fs_locks   = 0;
+    fd->unmounted  = 0;
+    fd->poll_index = -1;
+    list_init( &fd->inode_entry );
+    list_init( &fd->locks );
+    list_init( &fd->read_q );
+    list_init( &fd->write_q );
+    return fd;
+}
+
 /* check if the desired access is possible without violating */
 /* the sharing mode of other opens of the same file */
 static int check_sharing( struct fd *fd, unsigned int access, unsigned int sharing )
@@ -1409,7 +1436,11 @@
 /* retrieve the unix fd for an object */
 int get_unix_fd( struct fd *fd )
 {
-    if (fd->unix_fd == -1) set_error( STATUS_VOLUME_DISMOUNTED );
+    if (fd->unix_fd == -1)
+    {
+        if (fd->unmounted) set_error( STATUS_VOLUME_DISMOUNTED );
+        else set_error( STATUS_BAD_DEVICE_TYPE );
+    }
     return fd->unix_fd;
 }
 
@@ -1595,8 +1626,11 @@
     struct device *device;
     struct inode *inode;
     struct fd *fd;
+    int unix_fd = get_unix_fd( device_fd );
 
-    if (device_fd->unix_fd == -1 || fstat( device_fd->unix_fd, &st ) == -1 || !S_ISBLK( st.st_mode ))
+    if (unix_fd == -1) return;
+
+    if (fstat( unix_fd, &st ) == -1 || !S_ISBLK( st.st_mode ))
     {
         set_error( STATUS_INVALID_PARAMETER );
         return;
@@ -1653,6 +1687,32 @@
     }
 }
 
+/* open a file object */
+DECL_HANDLER(open_file_object)
+{
+    struct unicode_str name;
+    struct directory *root = NULL;
+    struct object *obj;
+
+    get_req_unicode_str( &name );
+    if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
+        return;
+
+    if ((obj = open_object_dir( root, &name, req->attributes, NULL )))
+    {
+        /* make sure this is a valid file object */
+        struct fd *fd = get_obj_fd( obj );
+        if (fd)
+        {
+            reply->handle = alloc_handle( current->process, obj, req->access, req->attributes );
+            release_object( fd );
+        }
+        release_object( obj );
+    }
+
+    if (root) release_object( root );
+}
+
 /* get a Unix fd to access a file */
 DECL_HANDLER(get_handle_fd)
 {
diff --git a/server/file.h b/server/file.h
index f89940b..4419998 100644
--- a/server/file.h
+++ b/server/file.h
@@ -47,6 +47,7 @@
 /* file descriptor functions */
 
 extern struct fd *alloc_fd( const struct fd_ops *fd_user_ops, struct object *user );
+extern struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *user );
 extern struct fd *open_fd( struct fd *fd, const char *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,
diff --git a/server/protocol.def b/server/protocol.def
index 3d055cb..2aa4f0e 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -604,6 +604,18 @@
 @END
 
 
+/* Open a file object */
+@REQ(open_file_object)
+    unsigned int access;        /* wanted access rights */
+    unsigned int attributes;    /* open attributes */
+    obj_handle_t rootdir;       /* root directory */
+    unsigned int sharing;       /* sharing flags */
+    VARARG(filename,unicode_str); /* file name */
+@REPLY
+    obj_handle_t handle;        /* handle to the file */
+@END
+
+
 /* Allocate a file handle for a Unix fd */
 @REQ(alloc_file_handle)
     unsigned int access;        /* wanted access rights */
diff --git a/server/request.h b/server/request.h
index 016e390..1fecb0f 100644
--- a/server/request.h
+++ b/server/request.h
@@ -145,6 +145,7 @@
 DECL_HANDLER(release_semaphore);
 DECL_HANDLER(open_semaphore);
 DECL_HANDLER(create_file);
+DECL_HANDLER(open_file_object);
 DECL_HANDLER(alloc_file_handle);
 DECL_HANDLER(get_handle_fd);
 DECL_HANDLER(set_handle_fd);
@@ -361,6 +362,7 @@
     (req_handler)req_release_semaphore,
     (req_handler)req_open_semaphore,
     (req_handler)req_create_file,
+    (req_handler)req_open_file_object,
     (req_handler)req_alloc_file_handle,
     (req_handler)req_get_handle_fd,
     (req_handler)req_set_handle_fd,
diff --git a/server/trace.c b/server/trace.c
index fb1be68..016b007 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1025,6 +1025,21 @@
     fprintf( stderr, " handle=%p", req->handle );
 }
 
+static void dump_open_file_object_request( const struct open_file_object_request *req )
+{
+    fprintf( stderr, " access=%08x,", req->access );
+    fprintf( stderr, " attributes=%08x,", req->attributes );
+    fprintf( stderr, " rootdir=%p,", req->rootdir );
+    fprintf( stderr, " sharing=%08x,", req->sharing );
+    fprintf( stderr, " filename=" );
+    dump_varargs_unicode_str( cur_size );
+}
+
+static void dump_open_file_object_reply( const struct open_file_object_reply *req )
+{
+    fprintf( stderr, " handle=%p", req->handle );
+}
+
 static void dump_alloc_file_handle_request( const struct alloc_file_handle_request *req )
 {
     fprintf( stderr, " access=%08x,", req->access );
@@ -3223,6 +3238,7 @@
     (dump_func)dump_release_semaphore_request,
     (dump_func)dump_open_semaphore_request,
     (dump_func)dump_create_file_request,
+    (dump_func)dump_open_file_object_request,
     (dump_func)dump_alloc_file_handle_request,
     (dump_func)dump_get_handle_fd_request,
     (dump_func)dump_set_handle_fd_request,
@@ -3436,6 +3452,7 @@
     (dump_func)dump_release_semaphore_reply,
     (dump_func)dump_open_semaphore_reply,
     (dump_func)dump_create_file_reply,
+    (dump_func)dump_open_file_object_reply,
     (dump_func)dump_alloc_file_handle_reply,
     (dump_func)dump_get_handle_fd_reply,
     (dump_func)dump_set_handle_fd_reply,
@@ -3649,6 +3666,7 @@
     "release_semaphore",
     "open_semaphore",
     "create_file",
+    "open_file_object",
     "alloc_file_handle",
     "get_handle_fd",
     "set_handle_fd",
@@ -3835,6 +3853,7 @@
     { "ACCESS_DENIED",               STATUS_ACCESS_DENIED },
     { "ACCESS_VIOLATION",            STATUS_ACCESS_VIOLATION },
     { "ALIAS_EXISTS",                STATUS_ALIAS_EXISTS },
+    { "BAD_DEVICE_TYPE",             STATUS_BAD_DEVICE_TYPE },
     { "BUFFER_OVERFLOW",             STATUS_BUFFER_OVERFLOW },
     { "BUFFER_TOO_SMALL",            STATUS_BUFFER_TOO_SMALL },
     { "CHILD_MUST_BE_VOLATILE",      STATUS_CHILD_MUST_BE_VOLATILE },