Hallo, appended patch opens the devicefile connected to a drive as connected by the user in ~/.wine/config [Drive X] "Device" = "/dev/yyy". The appropriate action on that file ( read, write, set_file_pointer, ...) succeed according the the righte the user has on that device. That way, I am able to open a unencrypted DVD with "DVD Shrink", inspect the structure and watch the movie, without mounting the DVD. ( For encryted DVD, I have on my disk the needed translation of the DeviceIOControls). On the server side, my implementation needs to add "set_file_pointer" to "struct fd_ops", that's the reason why so many files get touched. Changelog: wine/include/wine/server_protocol.h,wine/include/file.h,wine/files/file.c, wine/files/dos_fs.c,wine/dlls/kernel/device.c, wine/server/device.c, wine/server/fd.c, wine/server/file.c, wine/server/file.h, wine/server/named_pipe.c, wine/server/process.c, wine/server/request.c,wine/server/serial.c, wine/server/signal.c, wine/server/smb.c, wine/server/sock.c , wine/server/trace.c, wine/server/thread.c Handle the device file connected to a device Bye -- Uwe Bonnes bon@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Institut fuer Kernphysik Schlossgartenstrasse 9 64289 Darmstadt --------- Tel. 06151 162516 -------- Fax. 06151 164321 ---------- Index: wine/include/wine/server_protocol.h =================================================================== RCS file: /home/wine/wine/include/wine/server_protocol.h,v retrieving revision 1.92 diff -u -w -r1.92 server_protocol.h --- wine/include/wine/server_protocol.h 11 Dec 2003 05:34:53 -0000 1.92 +++ wine/include/wine/server_protocol.h 13 Dec 2003 21:18:32 -0000 @@ -1509,8 +1509,10 @@ { struct request_header __header; unsigned int access; + unsigned int attributes; int inherit; int id; + /* VARARG(device,string); */ }; struct create_device_reply { Index: wine/include/file.h =================================================================== RCS file: /home/wine/wine/include/file.h,v retrieving revision 1.62 diff -u -w -r1.62 file.h --- wine/include/file.h 2 Dec 2003 04:19:56 -0000 1.62 +++ wine/include/file.h 13 Dec 2003 21:18:33 -0000 @@ -76,7 +76,7 @@ LPSECURITY_ATTRIBUTES sa, DWORD creation, DWORD attributes, HANDLE template, BOOL fail_read_only, UINT drive_type ); -extern HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa ); +extern HANDLE FILE_CreateDevice( int client_id, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa ); extern LONG WINAPI WIN16_hread(HFILE16,SEGPTR,LONG); @@ -98,6 +98,6 @@ DOS_FULL_NAME *full ); /* win32/device.c */ -extern HANDLE DEVICE_Open( LPCWSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa ); +extern HANDLE DEVICE_Open( LPCWSTR filename, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa ); #endif /* __WINE_FILE_H */ Index: wine/files/file.c =================================================================== RCS file: /home/wine/wine/files/file.c,v retrieving revision 1.196 diff -u -w -r1.196 file.c --- wine/files/file.c 12 Dec 2003 04:10:52 -0000 1.196 +++ wine/files/file.c 13 Dec 2003 21:18:37 -0000 @@ -271,14 +271,17 @@ * Same as FILE_CreateFile but for a device * Returns 0 on failure. */ -HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa ) +HANDLE FILE_CreateDevice( int client_id, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa ) { + const char * devicename = DRIVE_GetDevice( client_id&0xff); HANDLE ret; SERVER_START_REQ( create_device ) { req->access = access; req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); + req->attributes = attributes; req->id = client_id; + wine_server_add_data( req, devicename, (devicename)?strlen(devicename):0 ); SetLastError(0); wine_server_call_err( req ); ret = reply->handle; @@ -393,12 +396,12 @@ } else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0') { - ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa ); + ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, attributes, sa ); goto done; } else if (!DOSFS_GetDevice( filename )) { - ret = DEVICE_Open( filename+4, access, sa ); + ret = DEVICE_Open( filename+4, access, attributes, sa ); goto done; } else Index: wine/files/dos_fs.c =================================================================== RCS file: /home/wine/wine/files/dos_fs.c,v retrieving revision 1.143 diff -u -w -r1.143 dos_fs.c --- wine/files/dos_fs.c 27 Nov 2003 00:59:36 -0000 1.143 +++ wine/files/dos_fs.c 13 Dec 2003 21:18:45 -0000 @@ -973,7 +973,7 @@ !strcmpiW(DOSFS_Devices[i].name, hpscanW) || !strcmpiW(DOSFS_Devices[i].name, emmxxxx0W)) { - return FILE_CreateDevice( i, access, sa ); + return FILE_CreateDevice( i, access, attributes, sa ); } if( (handle=DOSFS_CreateCommPort(DOSFS_Devices[i].name,access,attributes,sa)) ) Index: wine/dlls/kernel/device.c =================================================================== RCS file: /home/wine/wine/dlls/kernel/device.c,v retrieving revision 1.5 diff -u -w -r1.5 device.c --- wine/dlls/kernel/device.c 4 Dec 2003 21:05:13 -0000 1.5 +++ wine/dlls/kernel/device.c 13 Dec 2003 21:18:47 -0000 @@ -270,7 +270,7 @@ { NULL, 0, NULL } }; -HANDLE DEVICE_Open( LPCWSTR filenameW, DWORD access, LPSECURITY_ATTRIBUTES sa ) +HANDLE DEVICE_Open( LPCWSTR filenameW, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa ) { const struct VxDInfo *info; char filename[MAX_PATH]; @@ -283,7 +283,7 @@ for (info = VxDList; info->name; info++) if (!strncasecmp( info->name, filename, strlen(info->name) )) - return FILE_CreateDevice( info->id | 0x10000, access, sa ); + return FILE_CreateDevice( info->id | 0x10000, access, access, sa ); FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n", filename); Index: wine/server/device.c =================================================================== RCS file: /home/wine/wine/server/device.c,v retrieving revision 1.18 diff -u -w -r1.18 device.c --- wine/server/device.c 5 Sep 2003 23:15:41 -0000 1.18 +++ wine/server/device.c 13 Dec 2003 21:18:48 -0000 @@ -24,16 +24,23 @@ * client-side device support. */ +#include "config.h" + #include <assert.h> #include <fcntl.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/ioctl.h> #include "windef.h" #include "winbase.h" +#include "file.h" #include "handle.h" #include "thread.h" #include "request.h" @@ -42,37 +49,150 @@ { struct object obj; /* object header */ int id; /* client identifier */ + struct fd *fd; /* accociated device file */ }; static void device_dump( struct object *obj, int verbose ); +static struct fd *device_get_fd( struct object *obj ); +static void device_destroy(struct object *obj); +static int device_get_file_info( struct fd *fd, struct get_file_info_reply *reply, int *flags ); +static int device_set_file_pointer( struct fd *fd, unsigned int *low, int *high, int whence ); static const struct object_ops device_ops = { sizeof(struct device), /* size */ device_dump, /* dump */ - no_add_queue, /* add_queue */ - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* satisfied */ - no_get_fd, /* get_fd */ - no_destroy /* destroy */ + default_fd_add_queue, /* add_queue */ + default_fd_remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + no_satisfied, /* satisfied */ + device_get_fd, /* get_fd */ + device_destroy /* destroy */ }; -static struct device *create_device( int id ) +static const struct fd_ops device_fd_ops = +{ + NULL, /* get_poll_events */ + default_poll_event, /* poll_event */ + no_flush, /* flush */ + device_get_file_info, /* get_file_info */ + device_set_file_pointer, /* device_set_file_pointer*/ + no_queue_async /* queue_async */ +}; + +static struct device *create_device( int id, unsigned int access, unsigned int attributes, + const char *nameptr, size_t len ) { struct device *dev; + int fd=-1, flags = 0, myerr; + char *name; + + if ((len) && (name = mem_alloc( len + 1 )) && (access/*!=QUERY_ACCESS*/)) + { + memcpy( name, nameptr, len ); + name[len] = 0; + + switch(access & (GENERIC_READ | GENERIC_WRITE)) + { + case GENERIC_READ: flags |= O_RDONLY; break; + case GENERIC_WRITE: flags |= O_WRONLY; break; + case GENERIC_READ|GENERIC_WRITE: flags |= O_RDWR; break; + default: break; + } + + flags |= O_NONBLOCK; + + fd = open( name, flags ); + myerr = errno; + if ((fd == -1) && ((myerr == EROFS) ||(myerr == EACCES))) + { + flags &= ~O_RDWR; + flags &= ~O_WRONLY; + fd = open( name, flags ); + } + free( name ); + } + if ((dev = alloc_object( &device_ops ))) { dev->id = id; + if (fd != -1) + { + dev->fd = create_anonymous_fd( &device_fd_ops, fd, &dev->obj ); + } + else + dev->fd = 0; } return dev; } +static struct fd *device_get_fd( struct object *obj ) +{ + struct device *dev = (struct device *)obj; + assert( obj->ops == &device_ops ); + return ( dev->fd )?(struct fd *)grab_object( dev->fd ):0; +} + +static void device_destroy( struct object *obj) +{ + struct device *dev = (struct device *)obj; + if (dev->fd) + release_object( dev->fd ); +} + static void device_dump( struct object *obj, int verbose ) { struct device *dev = (struct device *)obj; assert( obj->ops == &device_ops ); - fprintf( stderr, "Device id=%08x\n", dev->id ); + fprintf( stderr, "Device id=%08x fd=%p\n", dev->id , dev->fd); +} + +static int device_get_file_info( struct fd *fd, struct get_file_info_reply *reply, int *flags ) +{ + struct file *file = get_fd_user( fd ); + if (reply) + { + if (file) + reply->type = FILE_TYPE_DISK; + else + reply->type = FD_TYPE_INVALID; + reply->attr = 0; + reply->access_time = 0; + reply->write_time = 0; + reply->size_high = 0; + reply->size_low = 0; + reply->links = 0; + reply->index_high = 0; + reply->index_low = 0; + reply->serial = 0; + } + *flags = 0; + return FD_TYPE_DEFAULT; +} + +static int device_set_file_pointer( struct fd *fd, unsigned int *low, int *high, int whence ) +{ + struct file *file = get_fd_user( fd ); + off_t result,xto; + int unix_fd = get_unix_fd( fd ); + + xto = *low+((off_t)*high<<32); + if (!(file)) return 0; + if ((result = lseek( unix_fd, xto, whence))==-1) + { + /* Check for seek before start of file */ + + /* also check EPERM due to SuSE7 2.2.16 lseek() EPERM kernel bug */ + if (((errno == EINVAL) || (errno == EPERM)) + && (whence != SEEK_SET) && (*high < 0)) + set_error( 0xc0010000 | ERROR_NEGATIVE_SEEK /* FIXME */ ); + else + file_set_error(); + return 0; + } + *low = result & 0xffffffff; + *high = result >> 32; + return 1; } /* create a device */ @@ -81,7 +201,7 @@ struct device *dev; reply->handle = 0; - if ((dev = create_device( req->id ))) + if ((dev = create_device( req->id , req->access, req->attributes, get_req_data(), get_req_data_size()))) { reply->handle = alloc_handle( current->process, dev, req->access, req->inherit ); release_object( dev ); Index: wine/server/fd.c =================================================================== RCS file: /home/wine/wine/server/fd.c,v retrieving revision 1.14 diff -u -w -r1.14 fd.c --- wine/server/fd.c 1 Dec 2003 23:01:12 -0000 1.14 +++ wine/server/fd.c 13 Dec 2003 21:18:51 -0000 @@ -988,6 +988,15 @@ return FD_TYPE_INVALID; } +/* default get_file_info() routine */ +int no_set_file_pointer( struct fd *fd, unsigned int *low, int *high, int whence ) +{ + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + *low = 0xffffffff; + *high = 0xffffffff; + return 0; +} + /* default queue_async() routine */ void no_queue_async( struct fd *fd, void* ptr, unsigned int status, int type, int count ) { @@ -1048,7 +1057,7 @@ } } -/* get a file information */ +/* set a file information */ DECL_HANDLER(get_file_info) { struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 ); @@ -1058,6 +1067,28 @@ int flags; fd->fd_ops->get_file_info( fd, reply, &flags ); release_object( fd ); + } +} + +/* get a file information */ +DECL_HANDLER(set_file_pointer) +{ + struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 ); + int high = req->high; + int low = req->low; + + + if (fd) + { + fd->fd_ops->set_file_pointer( fd, &low, &high, req->whence); + release_object( fd ); + reply->new_low = low; + reply->new_high = high; + } + else + { + reply->new_low = 0xffffffff; + reply->new_high = 0xffffffff; } } Index: wine/server/file.c =================================================================== RCS file: /home/wine/wine/server/file.c,v retrieving revision 1.73 diff -u -w -r1.73 file.c --- wine/server/file.c 10 Dec 2003 02:14:23 -0000 1.73 +++ wine/server/file.c 13 Dec 2003 21:18:52 -0000 @@ -76,6 +76,7 @@ static void file_poll_event( struct fd *fd, int event ); static int file_flush( struct fd *fd, struct event **event ); static int file_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags ); +static int file_set_file_pointer( struct fd *fd, unsigned int *low, int *high, int whence ); static void file_queue_async( struct fd *fd, void *ptr, unsigned int status, int type, int count ); static const struct object_ops file_ops = @@ -96,6 +97,7 @@ file_poll_event, /* poll_event */ file_flush, /* flush */ file_get_info, /* get_file_info */ + file_set_file_pointer, /* set_file_pointer */ file_queue_async /* queue_async */ }; @@ -358,6 +360,32 @@ return FD_TYPE_DEFAULT; } +static int file_set_file_pointer( struct fd *fd, unsigned int *low, int *high, int whence ) +{ + struct file *file; + off_t result,xto; + int unix_fd = get_unix_fd( fd ); + + file= get_fd_user( fd ); + xto = *low+((off_t)*high<<32); + if (!(file)) return 0; + if ((result = lseek( unix_fd, xto, whence))==-1) + { + /* Check for seek before start of file */ + + /* also check EPERM due to SuSE7 2.2.16 lseek() EPERM kernel bug */ + if (((errno == EINVAL) || (errno == EPERM)) + && (whence != SEEK_SET) && (*high < 0)) + set_error( 0xc0010000 | ERROR_NEGATIVE_SEEK /* FIXME */ ); + else + file_set_error(); + return 0; + } + *low = result & 0xffffffff; + *high = result >> 32; + return 1; +} + static void file_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count) { struct file *file = get_fd_user( fd ); @@ -477,33 +505,6 @@ return get_unix_fd( file->fd ); } -static int set_file_pointer( obj_handle_t handle, unsigned int *low, int *high, int whence ) -{ - struct file *file; - off_t result,xto; - - xto = *low+((off_t)*high<<32); - if (!(file = get_file_obj( current->process, handle, 0 ))) - return 0; - if ((result = lseek( get_file_unix_fd(file), xto, whence))==-1) - { - /* Check for seek before start of file */ - - /* also check EPERM due to SuSE7 2.2.16 lseek() EPERM kernel bug */ - if (((errno == EINVAL) || (errno == EPERM)) - && (whence != SEEK_SET) && (*high < 0)) - set_win32_error( ERROR_NEGATIVE_SEEK ); - else - file_set_error(); - release_object( file ); - return 0; - } - *low = result & 0xffffffff; - *high = result >> 32; - release_object( file ); - return 1; -} - /* extend a file beyond the current end of file */ static int extend_file( struct file *file, off_t size ) { @@ -623,16 +624,6 @@ reply->handle = alloc_handle( current->process, file, req->access, req->inherit ); release_object( file ); } -} - -/* set a file current position */ -DECL_HANDLER(set_file_pointer) -{ - int high = req->high; - int low = req->low; - set_file_pointer( req->handle, &low, &high, req->whence ); - reply->new_low = low; - reply->new_high = high; } /* truncate (or extend) a file */ Index: wine/server/file.h =================================================================== RCS file: /home/wine/wine/server/file.h,v retrieving revision 1.10 diff -u -w -r1.10 file.h --- wine/server/file.h 8 Oct 2003 00:25:33 -0000 1.10 +++ wine/server/file.h 13 Dec 2003 21:18:53 -0000 @@ -38,6 +38,8 @@ int (*flush)(struct fd *, struct event **); /* get file information */ int (*get_file_info)(struct fd *,struct get_file_info_reply *, int *flags); + /* set file pointer (if appropriate)*/ + int (*set_file_pointer)(struct fd *, unsigned int *low, int *high, int whence ); /* queue an async operation - see register_async handler in async.c*/ void (*queue_async)(struct fd *, void* ptr, unsigned int status, int type, int count); }; @@ -63,6 +65,7 @@ extern void default_poll_event( struct fd *fd, int event ); extern int no_flush( struct fd *fd, struct event **event ); extern int no_get_file_info( struct fd *fd, struct get_file_info_reply *info, int *flags ); +extern int no_set_file_pointer( struct fd *fd, unsigned int *low, int *high, int whence ); extern void no_queue_async( struct fd *fd, void* ptr, unsigned int status, int type, int count ); extern void main_loop(void); Index: wine/server/named_pipe.c =================================================================== RCS file: /home/wine/wine/server/named_pipe.c,v retrieving revision 1.27 diff -u -w -r1.27 named_pipe.c --- wine/server/named_pipe.c 5 Sep 2003 23:15:41 -0000 1.27 +++ wine/server/named_pipe.c 13 Dec 2003 21:18:55 -0000 @@ -152,6 +152,7 @@ default_poll_event, /* poll_event */ pipe_server_flush, /* flush */ pipe_end_get_info, /* get_file_info */ + no_set_file_pointer, /* set_file_pointer*/ no_queue_async /* queue_async */ }; @@ -179,6 +180,7 @@ default_poll_event, /* poll_event */ pipe_client_flush, /* flush */ pipe_end_get_info, /* get_file_info */ + no_set_file_pointer, /* set_file_pointer*/ no_queue_async /* queue_async */ }; Index: wine/server/process.c =================================================================== RCS file: /home/wine/wine/server/process.c,v retrieving revision 1.115 diff -u -w -r1.115 process.c --- wine/server/process.c 10 Dec 2003 04:08:06 -0000 1.115 +++ wine/server/process.c 13 Dec 2003 21:18:58 -0000 @@ -76,6 +76,7 @@ process_poll_event, /* poll_event */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + no_set_file_pointer, /* set_file_pointer*/ no_queue_async /* queue_async */ }; Index: wine/server/request.c =================================================================== RCS file: /home/wine/wine/server/request.c,v retrieving revision 1.80 diff -u -w -r1.80 request.c --- wine/server/request.c 18 Jun 2003 19:45:22 -0000 1.80 +++ wine/server/request.c 13 Dec 2003 21:19:00 -0000 @@ -100,6 +100,7 @@ master_socket_poll_event, /* poll_event */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + no_set_file_pointer, /* set_file_pointer*/ no_queue_async /* queue_async */ }; Index: wine/server/serial.c =================================================================== RCS file: /home/wine/wine/server/serial.c,v retrieving revision 1.31 diff -u -w -r1.31 serial.c --- wine/server/serial.c 5 Sep 2003 23:15:41 -0000 1.31 +++ wine/server/serial.c 13 Dec 2003 21:19:01 -0000 @@ -107,6 +107,7 @@ serial_poll_event, /* poll_event */ serial_flush, /* flush */ serial_get_info, /* get_file_info */ + no_set_file_pointer, /* set_file_pointer*/ serial_queue_async /* queue_async */ }; Index: wine/server/signal.c =================================================================== RCS file: /home/wine/wine/server/signal.c,v retrieving revision 1.6 diff -u -w -r1.6 signal.c --- wine/server/signal.c 24 Oct 2003 04:29:01 -0000 1.6 +++ wine/server/signal.c 13 Dec 2003 21:19:02 -0000 @@ -71,6 +71,7 @@ handler_poll_event, /* poll_event */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + no_set_file_pointer, /* set_file_pointer*/ no_queue_async /* queue_async */ }; Index: wine/server/smb.c =================================================================== RCS file: /home/wine/wine/server/smb.c,v retrieving revision 1.10 diff -u -w -r1.10 smb.c --- wine/server/smb.c 5 Sep 2003 23:15:41 -0000 1.10 +++ wine/server/smb.c 13 Dec 2003 21:19:03 -0000 @@ -89,6 +89,7 @@ default_poll_event, /* poll_event */ no_flush, /* flush */ smb_get_info, /* get_file_info */ + no_set_file_pointer, /* set_file_pointer*/ no_queue_async /* queue_async */ }; Index: wine/server/sock.c =================================================================== RCS file: /home/wine/wine/server/sock.c,v retrieving revision 1.46 diff -u -w -r1.46 sock.c --- wine/server/sock.c 5 Sep 2003 23:15:41 -0000 1.46 +++ wine/server/sock.c 13 Dec 2003 21:19:05 -0000 @@ -117,6 +117,7 @@ sock_poll_event, /* poll_event */ no_flush, /* flush */ sock_get_info, /* get_file_info */ + no_set_file_pointer, /* set_file_pointer*/ sock_queue_async /* queue_async */ }; Index: wine/server/trace.c =================================================================== RCS file: /home/wine/wine/server/trace.c,v retrieving revision 1.190 diff -u -w -r1.190 trace.c --- wine/server/trace.c 11 Dec 2003 05:34:53 -0000 1.190 +++ wine/server/trace.c 13 Dec 2003 21:19:13 -0000 @@ -1349,8 +1349,11 @@ static void dump_create_device_request( const struct create_device_request *req ) { fprintf( stderr, " access=%08x,", req->access ); + fprintf( stderr, " attributes=%08x,", req->attributes ); fprintf( stderr, " inherit=%d,", req->inherit ); - fprintf( stderr, " id=%d", req->id ); + fprintf( stderr, " id=%d,", req->id ); + fprintf( stderr, " device=" ); + dump_varargs_string( cur_size ); } static void dump_create_device_reply( const struct create_device_reply *req ) Index: wine/server/thread.c =================================================================== RCS file: /home/wine/wine/server/thread.c,v retrieving revision 1.103 diff -u -w -r1.103 thread.c --- wine/server/thread.c 27 Oct 2003 22:10:22 -0000 1.103 +++ wine/server/thread.c 13 Dec 2003 21:19:15 -0000 @@ -100,6 +100,7 @@ thread_poll_event, /* poll_event */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + no_set_file_pointer, /* set_file_pointer*/ no_queue_async /* queue_async */ };