Added several file server requests
Added server-side pipes and consoles
This commit is contained in:
parent
338e757d08
commit
aa0ebd0f1c
|
@ -268,6 +268,50 @@ struct get_unix_handle_request
|
|||
};
|
||||
|
||||
|
||||
/* Get a Unix fd to read from a file */
|
||||
struct get_read_fd_request
|
||||
{
|
||||
int handle; /* handle to the file */
|
||||
};
|
||||
|
||||
|
||||
/* Get a Unix fd to write to a file */
|
||||
struct get_write_fd_request
|
||||
{
|
||||
int handle; /* handle to the file */
|
||||
};
|
||||
|
||||
|
||||
/* Set a file current position */
|
||||
struct set_file_pointer_request
|
||||
{
|
||||
int handle; /* handle to the file */
|
||||
int low; /* position low word */
|
||||
int high; /* position high word */
|
||||
int whence; /* whence to seek */
|
||||
};
|
||||
struct set_file_pointer_reply
|
||||
{
|
||||
int low; /* new position low word */
|
||||
int high; /* new position high word */
|
||||
};
|
||||
|
||||
|
||||
/* Truncate (or extend) a file */
|
||||
struct truncate_file_request
|
||||
{
|
||||
int handle; /* handle to the file */
|
||||
};
|
||||
|
||||
|
||||
/* Flush a file buffers */
|
||||
struct flush_file_request
|
||||
{
|
||||
int handle; /* handle to the file */
|
||||
};
|
||||
|
||||
|
||||
/* Get information about a file */
|
||||
struct get_file_info_request
|
||||
{
|
||||
int handle; /* handle to the file */
|
||||
|
@ -285,6 +329,38 @@ struct get_file_info_reply
|
|||
unsigned int serial; /* volume serial number */
|
||||
};
|
||||
|
||||
|
||||
/* Create an anonymous pipe */
|
||||
struct create_pipe_request
|
||||
{
|
||||
int inherit; /* inherit flag */
|
||||
};
|
||||
struct create_pipe_reply
|
||||
{
|
||||
int handle_read; /* handle to the read-side of the pipe */
|
||||
int handle_write; /* handle to the write-side of the pipe */
|
||||
};
|
||||
|
||||
|
||||
/* Create a console */
|
||||
struct create_console_request
|
||||
{
|
||||
int inherit; /* inherit flag */
|
||||
};
|
||||
struct create_console_reply
|
||||
{
|
||||
int handle_read; /* handle to read from the console */
|
||||
int handle_write; /* handle to write to the console */
|
||||
};
|
||||
|
||||
|
||||
/* Set a console file descriptor */
|
||||
struct set_console_fd_request
|
||||
{
|
||||
int handle; /* handle to the console */
|
||||
};
|
||||
|
||||
|
||||
/* client-side functions */
|
||||
|
||||
#ifndef __WINE_SERVER__
|
||||
|
|
|
@ -34,6 +34,12 @@ struct object_ops
|
|||
int (*signaled)(struct object *,struct thread *);
|
||||
/* wait satisfied; return 1 if abandoned */
|
||||
int (*satisfied)(struct object *,struct thread *);
|
||||
/* return a Unix fd that can be used to read from the object */
|
||||
int (*get_read_fd)(struct object *);
|
||||
/* return a Unix fd that can be used to write to the object */
|
||||
int (*get_write_fd)(struct object *);
|
||||
/* flush the object buffers */
|
||||
int (*flush)(struct object *);
|
||||
/* destroy on refcount == 0 */
|
||||
void (*destroy)(struct object *);
|
||||
};
|
||||
|
@ -57,6 +63,11 @@ extern int init_object( struct object *obj, const struct object_ops *ops,
|
|||
extern struct object *grab_object( void *obj );
|
||||
extern void release_object( void *obj );
|
||||
extern struct object *find_object( const char *name );
|
||||
extern int no_satisfied( struct object *obj, struct thread *thread );
|
||||
extern int no_read_fd( struct object *obj );
|
||||
extern int no_write_fd( struct object *obj );
|
||||
extern int no_flush( struct object *obj );
|
||||
extern void default_select_event( int fd, int event, void *private );
|
||||
|
||||
/* request handlers */
|
||||
|
||||
|
@ -161,7 +172,22 @@ extern int release_semaphore( int handle, unsigned int count, unsigned int *prev
|
|||
|
||||
extern struct object *create_file( int fd );
|
||||
extern int file_get_unix_handle( int handle, unsigned int access );
|
||||
extern int set_file_pointer( int handle, int *low, int *high, int whence );
|
||||
extern int truncate_file( int handle );
|
||||
extern int get_file_info( int handle, struct get_file_info_reply *reply );
|
||||
extern void file_set_error(void);
|
||||
|
||||
|
||||
/* pipe functions */
|
||||
|
||||
extern int create_pipe( struct object *obj[2] );
|
||||
|
||||
|
||||
/* console functions */
|
||||
|
||||
extern int create_console( int fd, struct object *obj[2] );
|
||||
extern int set_console_fd( int handle, int fd );
|
||||
|
||||
|
||||
extern int debug_level;
|
||||
|
||||
|
|
|
@ -25,7 +25,15 @@ enum request
|
|||
REQ_OPEN_NAMED_OBJ,
|
||||
REQ_CREATE_FILE,
|
||||
REQ_GET_UNIX_HANDLE,
|
||||
REQ_GET_READ_FD,
|
||||
REQ_GET_WRITE_FD,
|
||||
REQ_SET_FILE_POINTER,
|
||||
REQ_TRUNCATE_FILE,
|
||||
REQ_FLUSH_FILE,
|
||||
REQ_GET_FILE_INFO,
|
||||
REQ_CREATE_PIPE,
|
||||
REQ_CREATE_CONSOLE,
|
||||
REQ_SET_CONSOLE_FD,
|
||||
REQ_NB_REQUESTS
|
||||
};
|
||||
|
||||
|
@ -54,7 +62,15 @@ DECL_HANDLER(release_semaphore);
|
|||
DECL_HANDLER(open_named_obj);
|
||||
DECL_HANDLER(create_file);
|
||||
DECL_HANDLER(get_unix_handle);
|
||||
DECL_HANDLER(get_read_fd);
|
||||
DECL_HANDLER(get_write_fd);
|
||||
DECL_HANDLER(set_file_pointer);
|
||||
DECL_HANDLER(truncate_file);
|
||||
DECL_HANDLER(flush_file);
|
||||
DECL_HANDLER(get_file_info);
|
||||
DECL_HANDLER(create_pipe);
|
||||
DECL_HANDLER(create_console);
|
||||
DECL_HANDLER(set_console_fd);
|
||||
|
||||
static const struct handler {
|
||||
void (*handler)();
|
||||
|
@ -80,7 +96,15 @@ static const struct handler {
|
|||
{ (void(*)())req_open_named_obj, sizeof(struct open_named_obj_request) },
|
||||
{ (void(*)())req_create_file, sizeof(struct create_file_request) },
|
||||
{ (void(*)())req_get_unix_handle, sizeof(struct get_unix_handle_request) },
|
||||
{ (void(*)())req_get_read_fd, sizeof(struct get_read_fd_request) },
|
||||
{ (void(*)())req_get_write_fd, sizeof(struct get_write_fd_request) },
|
||||
{ (void(*)())req_set_file_pointer, sizeof(struct set_file_pointer_request) },
|
||||
{ (void(*)())req_truncate_file, sizeof(struct truncate_file_request) },
|
||||
{ (void(*)())req_flush_file, sizeof(struct flush_file_request) },
|
||||
{ (void(*)())req_get_file_info, sizeof(struct get_file_info_request) },
|
||||
{ (void(*)())req_create_pipe, sizeof(struct create_pipe_request) },
|
||||
{ (void(*)())req_create_console, sizeof(struct create_console_request) },
|
||||
{ (void(*)())req_set_console_fd, sizeof(struct set_console_fd_request) },
|
||||
};
|
||||
#endif /* WANT_REQUEST_HANDLERS */
|
||||
|
||||
|
|
|
@ -6,10 +6,12 @@ VPATH = @srcdir@
|
|||
MODULE = server
|
||||
|
||||
C_SRCS = \
|
||||
console.c \
|
||||
event.c \
|
||||
file.c \
|
||||
mutex.c \
|
||||
object.c \
|
||||
pipe.c \
|
||||
process.c \
|
||||
request.c \
|
||||
select.c \
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Server-side console management
|
||||
*
|
||||
* Copyright (C) 1998 Alexandre Julliard
|
||||
*
|
||||
* FIXME: all this stuff is a hack to avoid breaking
|
||||
* the client-side console support.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
struct console
|
||||
{
|
||||
struct object obj; /* object header */
|
||||
int fd; /* Unix file descriptor */
|
||||
int is_read; /* is this the read or write part? */
|
||||
};
|
||||
|
||||
static void console_dump( struct object *obj, int verbose );
|
||||
static void console_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||
static void console_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||
static int console_signaled( struct object *obj, struct thread *thread );
|
||||
static int console_get_read_fd( struct object *obj );
|
||||
static int console_get_write_fd( struct object *obj );
|
||||
static void console_destroy( struct object *obj );
|
||||
|
||||
static const struct object_ops console_ops =
|
||||
{
|
||||
console_dump,
|
||||
console_add_queue,
|
||||
console_remove_queue,
|
||||
console_signaled,
|
||||
no_satisfied,
|
||||
console_get_read_fd,
|
||||
console_get_write_fd,
|
||||
no_flush,
|
||||
console_destroy
|
||||
};
|
||||
|
||||
static const struct select_ops select_ops =
|
||||
{
|
||||
default_select_event,
|
||||
NULL /* we never set a timeout on a console */
|
||||
};
|
||||
|
||||
int create_console( int fd, struct object *obj[2] )
|
||||
{
|
||||
struct console *console_read, *console_write;
|
||||
int read_fd, write_fd;
|
||||
|
||||
if ((read_fd = (fd != -1) ? dup(fd) : dup(0)) == -1)
|
||||
{
|
||||
file_set_error();
|
||||
return 0;
|
||||
}
|
||||
if ((write_fd = (fd != -1) ? dup(fd) : dup(0)) == -1)
|
||||
{
|
||||
file_set_error();
|
||||
close( read_fd );
|
||||
return 0;
|
||||
}
|
||||
if (!(console_read = mem_alloc( sizeof(struct console) )))
|
||||
{
|
||||
close( read_fd );
|
||||
close( write_fd );
|
||||
return 0;
|
||||
}
|
||||
if (!(console_write = mem_alloc( sizeof(struct console) )))
|
||||
{
|
||||
close( read_fd );
|
||||
close( write_fd );
|
||||
free( console_read );
|
||||
return 0;
|
||||
}
|
||||
init_object( &console_read->obj, &console_ops, NULL );
|
||||
init_object( &console_write->obj, &console_ops, NULL );
|
||||
console_read->fd = read_fd;
|
||||
console_read->is_read = 1;
|
||||
console_write->fd = write_fd;
|
||||
console_write->is_read = 0;
|
||||
CLEAR_ERROR();
|
||||
obj[0] = &console_read->obj;
|
||||
obj[1] = &console_write->obj;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int set_console_fd( int handle, int fd )
|
||||
{
|
||||
struct console *console;
|
||||
|
||||
if (!(console = (struct console *)get_handle_obj( current->process, handle,
|
||||
0, &console_ops )))
|
||||
return 0;
|
||||
if ((fd = dup(fd)) == -1)
|
||||
{
|
||||
file_set_error();
|
||||
release_object( console );
|
||||
return 0;
|
||||
}
|
||||
close( console->fd );
|
||||
console->fd = fd;
|
||||
release_object( console );
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void console_dump( struct object *obj, int verbose )
|
||||
{
|
||||
struct console *console = (struct console *)obj;
|
||||
assert( obj->ops == &console_ops );
|
||||
printf( "Console %s fd=%d\n",
|
||||
console->is_read ? "input" : "output", console->fd );
|
||||
}
|
||||
|
||||
static void console_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
||||
{
|
||||
struct console *console = (struct console *)obj;
|
||||
assert( obj->ops == &console_ops );
|
||||
if (!obj->head) /* first on the queue */
|
||||
add_select_user( console->fd,
|
||||
console->is_read ? READ_EVENT : WRITE_EVENT,
|
||||
&select_ops, console );
|
||||
add_queue( obj, entry );
|
||||
}
|
||||
|
||||
static void console_remove_queue( struct object *obj, struct wait_queue_entry *entry )
|
||||
{
|
||||
struct console *console = (struct console *)grab_object(obj);
|
||||
assert( obj->ops == &console_ops );
|
||||
|
||||
remove_queue( obj, entry );
|
||||
if (!obj->head) /* last on the queue is gone */
|
||||
remove_select_user( console->fd );
|
||||
release_object( obj );
|
||||
}
|
||||
|
||||
static int console_signaled( struct object *obj, struct thread *thread )
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval tv = { 0, 0 };
|
||||
struct console *console = (struct console *)obj;
|
||||
assert( obj->ops == &console_ops );
|
||||
|
||||
FD_ZERO( &fds );
|
||||
FD_SET( console->fd, &fds );
|
||||
if (console->is_read)
|
||||
return select( console->fd + 1, &fds, NULL, NULL, &tv ) > 0;
|
||||
else
|
||||
return select( console->fd + 1, NULL, &fds, NULL, &tv ) > 0;
|
||||
}
|
||||
|
||||
static int console_get_read_fd( struct object *obj )
|
||||
{
|
||||
struct console *console = (struct console *)obj;
|
||||
assert( obj->ops == &console_ops );
|
||||
|
||||
if (!console->is_read)
|
||||
{
|
||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
||||
return -1;
|
||||
}
|
||||
return dup( console->fd );
|
||||
}
|
||||
|
||||
static int console_get_write_fd( struct object *obj )
|
||||
{
|
||||
struct console *console = (struct console *)obj;
|
||||
assert( obj->ops == &console_ops );
|
||||
|
||||
if (console->is_read)
|
||||
{
|
||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
||||
return -1;
|
||||
}
|
||||
return dup( console->fd );
|
||||
}
|
||||
|
||||
static void console_destroy( struct object *obj )
|
||||
{
|
||||
struct console *console = (struct console *)obj;
|
||||
assert( obj->ops == &console_ops );
|
||||
close( console->fd );
|
||||
free( console );
|
||||
}
|
|
@ -31,6 +31,9 @@ static const struct object_ops event_ops =
|
|||
remove_queue,
|
||||
event_signaled,
|
||||
event_satisfied,
|
||||
no_read_fd,
|
||||
no_write_fd,
|
||||
no_flush,
|
||||
event_destroy
|
||||
};
|
||||
|
||||
|
|
138
server/file.c
138
server/file.c
|
@ -30,7 +30,9 @@ static void file_dump( struct object *obj, int verbose );
|
|||
static void file_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||
static void file_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||
static int file_signaled( struct object *obj, struct thread *thread );
|
||||
static int file_satisfied( struct object *obj, struct thread *thread );
|
||||
static int file_get_read_fd( struct object *obj );
|
||||
static int file_get_write_fd( struct object *obj );
|
||||
static int file_flush( struct object *obj );
|
||||
static void file_destroy( struct object *obj );
|
||||
|
||||
static const struct object_ops file_ops =
|
||||
|
@ -39,17 +41,17 @@ static const struct object_ops file_ops =
|
|||
file_add_queue,
|
||||
file_remove_queue,
|
||||
file_signaled,
|
||||
file_satisfied,
|
||||
no_satisfied,
|
||||
file_get_read_fd,
|
||||
file_get_write_fd,
|
||||
file_flush,
|
||||
file_destroy
|
||||
};
|
||||
|
||||
static void file_event( int fd, int event, void *private );
|
||||
static void file_timeout( int fd, void *private );
|
||||
|
||||
static const struct select_ops select_ops =
|
||||
{
|
||||
file_event,
|
||||
file_timeout
|
||||
default_select_event,
|
||||
NULL /* we never set a timeout on a file */
|
||||
};
|
||||
|
||||
struct object *create_file( int fd )
|
||||
|
@ -123,10 +125,42 @@ static int file_signaled( struct object *obj, struct thread *thread )
|
|||
return select( file->fd + 1, &read_fds, &write_fds, NULL, &tv ) > 0;
|
||||
}
|
||||
|
||||
static int file_satisfied( struct object *obj, struct thread *thread )
|
||||
static int file_get_read_fd( struct object *obj )
|
||||
{
|
||||
/* Nothing to do */
|
||||
return 0; /* Not abandoned */
|
||||
struct file *file = (struct file *)obj;
|
||||
assert( obj->ops == &file_ops );
|
||||
|
||||
if (!(file->event & READ_EVENT)) /* FIXME: should not be necessary */
|
||||
{
|
||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
||||
return -1;
|
||||
}
|
||||
return dup( file->fd );
|
||||
}
|
||||
|
||||
static int file_get_write_fd( struct object *obj )
|
||||
{
|
||||
struct file *file = (struct file *)obj;
|
||||
assert( obj->ops == &file_ops );
|
||||
|
||||
if (!(file->event & WRITE_EVENT)) /* FIXME: should not be necessary */
|
||||
{
|
||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
||||
return -1;
|
||||
}
|
||||
return dup( file->fd );
|
||||
}
|
||||
|
||||
static int file_flush( struct object *obj )
|
||||
{
|
||||
int ret;
|
||||
struct file *file = (struct file *)grab_object(obj);
|
||||
assert( obj->ops == &file_ops );
|
||||
|
||||
ret = (fsync( file->fd ) != -1);
|
||||
if (!ret) file_set_error();
|
||||
release_object( file );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void file_destroy( struct object *obj )
|
||||
|
@ -137,18 +171,28 @@ static void file_destroy( struct object *obj )
|
|||
free( file );
|
||||
}
|
||||
|
||||
static void file_event( int fd, int event, void *private )
|
||||
/* set the last error depending on errno */
|
||||
void file_set_error(void)
|
||||
{
|
||||
struct file *file = (struct file *)private;
|
||||
assert( file );
|
||||
|
||||
wake_up( &file->obj, 0 );
|
||||
}
|
||||
|
||||
static void file_timeout( int fd, void *private )
|
||||
{
|
||||
/* we never set a timeout on a file */
|
||||
assert( 0 );
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN: SET_ERROR( ERROR_SHARING_VIOLATION ); break;
|
||||
case EBADF: SET_ERROR( ERROR_INVALID_HANDLE ); break;
|
||||
case ENOSPC: SET_ERROR( ERROR_HANDLE_DISK_FULL ); break;
|
||||
case EACCES:
|
||||
case EPERM: SET_ERROR( ERROR_ACCESS_DENIED ); break;
|
||||
case EROFS: SET_ERROR( ERROR_WRITE_PROTECT ); break;
|
||||
case EBUSY: SET_ERROR( ERROR_LOCK_VIOLATION ); break;
|
||||
case ENOENT: SET_ERROR( ERROR_FILE_NOT_FOUND ); break;
|
||||
case EISDIR: SET_ERROR( ERROR_CANNOT_MAKE ); break;
|
||||
case ENFILE:
|
||||
case EMFILE: SET_ERROR( ERROR_NO_MORE_FILES ); break;
|
||||
case EEXIST: SET_ERROR( ERROR_FILE_EXISTS ); break;
|
||||
case EINVAL: SET_ERROR( ERROR_INVALID_PARAMETER ); break;
|
||||
case ESPIPE: SET_ERROR( ERROR_SEEK ); break;
|
||||
case ENOTEMPTY: SET_ERROR( ERROR_DIR_NOT_EMPTY ); break;
|
||||
default: perror("file_set_error"); SET_ERROR( ERROR_UNKNOWN ); break;
|
||||
}
|
||||
}
|
||||
|
||||
int file_get_unix_handle( int handle, unsigned int access )
|
||||
|
@ -164,6 +208,56 @@ int file_get_unix_handle( int handle, unsigned int access )
|
|||
return unix_handle;
|
||||
}
|
||||
|
||||
int set_file_pointer( int handle, int *low, int *high, int whence )
|
||||
{
|
||||
struct file *file;
|
||||
int result;
|
||||
|
||||
if (*high)
|
||||
{
|
||||
fprintf( stderr, "set_file_pointer: offset > 4Gb not supported yet\n" );
|
||||
SET_ERROR( ERROR_INVALID_PARAMETER );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(file = (struct file *)get_handle_obj( current->process, handle,
|
||||
0, &file_ops )))
|
||||
return 0;
|
||||
if ((result = lseek( file->fd, *low, whence )) == -1)
|
||||
{
|
||||
/* Check for seek before start of file */
|
||||
if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
|
||||
SET_ERROR( ERROR_NEGATIVE_SEEK );
|
||||
else
|
||||
file_set_error();
|
||||
release_object( file );
|
||||
return 0;
|
||||
}
|
||||
*low = result;
|
||||
release_object( file );
|
||||
return 1;
|
||||
}
|
||||
|
||||
int truncate_file( int handle )
|
||||
{
|
||||
struct file *file;
|
||||
int result;
|
||||
|
||||
if (!(file = (struct file *)get_handle_obj( current->process, handle,
|
||||
GENERIC_WRITE, &file_ops )))
|
||||
return 0;
|
||||
if (((result = lseek( file->fd, 0, SEEK_CUR )) == -1) ||
|
||||
(ftruncate( file->fd, result ) == -1))
|
||||
{
|
||||
file_set_error();
|
||||
release_object( file );
|
||||
return 0;
|
||||
}
|
||||
release_object( file );
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int get_file_info( int handle, struct get_file_info_reply *reply )
|
||||
{
|
||||
struct file *file;
|
||||
|
@ -174,7 +268,7 @@ int get_file_info( int handle, struct get_file_info_reply *reply )
|
|||
return 0;
|
||||
if (fstat( file->fd, &st ) == -1)
|
||||
{
|
||||
/* file_set_error(); */
|
||||
file_set_error();
|
||||
release_object( file );
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ static const struct object_ops mutex_ops =
|
|||
remove_queue,
|
||||
mutex_signaled,
|
||||
mutex_satisfied,
|
||||
no_read_fd,
|
||||
no_write_fd,
|
||||
no_flush,
|
||||
mutex_destroy
|
||||
};
|
||||
|
||||
|
|
|
@ -144,3 +144,35 @@ struct object *find_object( const char *name )
|
|||
if (!ptr) return NULL;
|
||||
return grab_object( ptr->obj );
|
||||
}
|
||||
|
||||
/* functions for unimplemented object operations */
|
||||
|
||||
int no_satisfied( struct object *obj, struct thread *thread )
|
||||
{
|
||||
return 0; /* not abandoned */
|
||||
}
|
||||
|
||||
int no_read_fd( struct object *obj )
|
||||
{
|
||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
||||
return -1;
|
||||
}
|
||||
|
||||
int no_write_fd( struct object *obj )
|
||||
{
|
||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
||||
return -1;
|
||||
}
|
||||
|
||||
int no_flush( struct object *obj )
|
||||
{
|
||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
||||
return 0;
|
||||
}
|
||||
|
||||
void default_select_event( int fd, int event, void *private )
|
||||
{
|
||||
struct object *obj = (struct object *)private;
|
||||
assert( obj );
|
||||
wake_up( obj, 0 );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Server-side pipe management
|
||||
*
|
||||
* Copyright (C) 1998 Alexandre Julliard
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
enum side { READ_SIDE, WRITE_SIDE };
|
||||
|
||||
struct pipe
|
||||
{
|
||||
struct object obj; /* object header */
|
||||
struct pipe *other; /* the pipe other end */
|
||||
int fd; /* Unix file descriptor */
|
||||
enum side side; /* which side of the pipe is this */
|
||||
};
|
||||
|
||||
static void pipe_dump( struct object *obj, int verbose );
|
||||
static void pipe_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||
static void pipe_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||
static int pipe_signaled( struct object *obj, struct thread *thread );
|
||||
static int pipe_get_read_fd( struct object *obj );
|
||||
static int pipe_get_write_fd( struct object *obj );
|
||||
static void pipe_destroy( struct object *obj );
|
||||
|
||||
static const struct object_ops pipe_ops =
|
||||
{
|
||||
pipe_dump,
|
||||
pipe_add_queue,
|
||||
pipe_remove_queue,
|
||||
pipe_signaled,
|
||||
no_satisfied,
|
||||
pipe_get_read_fd,
|
||||
pipe_get_write_fd,
|
||||
no_flush,
|
||||
pipe_destroy
|
||||
};
|
||||
|
||||
static const struct select_ops select_ops =
|
||||
{
|
||||
default_select_event,
|
||||
NULL /* we never set a timeout on a pipe */
|
||||
};
|
||||
|
||||
int create_pipe( struct object *obj[2] )
|
||||
{
|
||||
struct pipe *newpipe[2];
|
||||
int fd[2];
|
||||
|
||||
if (pipe( fd ) == -1)
|
||||
{
|
||||
file_set_error();
|
||||
return 0;
|
||||
}
|
||||
if (!(newpipe[0] = mem_alloc( sizeof(struct pipe) )))
|
||||
{
|
||||
close( fd[0] );
|
||||
close( fd[1] );
|
||||
return 0;
|
||||
}
|
||||
if (!(newpipe[1] = mem_alloc( sizeof(struct pipe) )))
|
||||
{
|
||||
close( fd[0] );
|
||||
close( fd[1] );
|
||||
free( newpipe[0] );
|
||||
return 0;
|
||||
}
|
||||
init_object( &newpipe[0]->obj, &pipe_ops, NULL );
|
||||
init_object( &newpipe[1]->obj, &pipe_ops, NULL );
|
||||
newpipe[0]->fd = fd[0];
|
||||
newpipe[0]->other = newpipe[1];
|
||||
newpipe[0]->side = READ_SIDE;
|
||||
newpipe[1]->fd = fd[1];
|
||||
newpipe[1]->other = newpipe[0];
|
||||
newpipe[1]->side = WRITE_SIDE;
|
||||
obj[0] = &newpipe[0]->obj;
|
||||
obj[1] = &newpipe[1]->obj;
|
||||
CLEAR_ERROR();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void pipe_dump( struct object *obj, int verbose )
|
||||
{
|
||||
struct pipe *pipe = (struct pipe *)obj;
|
||||
assert( obj->ops == &pipe_ops );
|
||||
printf( "Pipe %s-side fd=%d\n",
|
||||
(pipe->side == READ_SIDE) ? "read" : "write", pipe->fd );
|
||||
}
|
||||
|
||||
static void pipe_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
||||
{
|
||||
struct pipe *pipe = (struct pipe *)obj;
|
||||
assert( obj->ops == &pipe_ops );
|
||||
if (!obj->head) /* first on the queue */
|
||||
add_select_user( pipe->fd,
|
||||
(pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT,
|
||||
&select_ops, pipe );
|
||||
add_queue( obj, entry );
|
||||
}
|
||||
|
||||
static void pipe_remove_queue( struct object *obj, struct wait_queue_entry *entry )
|
||||
{
|
||||
struct pipe *pipe = (struct pipe *)grab_object(obj);
|
||||
assert( obj->ops == &pipe_ops );
|
||||
|
||||
remove_queue( obj, entry );
|
||||
if (!obj->head) /* last on the queue is gone */
|
||||
remove_select_user( pipe->fd );
|
||||
release_object( obj );
|
||||
}
|
||||
|
||||
static int pipe_signaled( struct object *obj, struct thread *thread )
|
||||
{
|
||||
struct pipe *pipe = (struct pipe *)obj;
|
||||
struct timeval tv = { 0, 0 };
|
||||
fd_set fds;
|
||||
|
||||
assert( obj->ops == &pipe_ops );
|
||||
FD_ZERO( &fds );
|
||||
FD_SET( pipe->fd, &fds );
|
||||
if (pipe->side == READ_SIDE)
|
||||
return select( pipe->fd + 1, &fds, NULL, NULL, &tv ) > 0;
|
||||
else
|
||||
return select( pipe->fd + 1, NULL, &fds, NULL, &tv ) > 0;
|
||||
}
|
||||
|
||||
static int pipe_get_read_fd( struct object *obj )
|
||||
{
|
||||
struct pipe *pipe = (struct pipe *)obj;
|
||||
assert( obj->ops == &pipe_ops );
|
||||
|
||||
if (!pipe->other)
|
||||
{
|
||||
SET_ERROR( ERROR_BROKEN_PIPE );
|
||||
return -1;
|
||||
}
|
||||
if (pipe->side != READ_SIDE) /* FIXME: should not be necessary */
|
||||
{
|
||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
||||
return -1;
|
||||
}
|
||||
return dup( pipe->fd );
|
||||
}
|
||||
|
||||
static int pipe_get_write_fd( struct object *obj )
|
||||
{
|
||||
struct pipe *pipe = (struct pipe *)obj;
|
||||
assert( obj->ops == &pipe_ops );
|
||||
|
||||
if (!pipe->other)
|
||||
{
|
||||
SET_ERROR( ERROR_BROKEN_PIPE );
|
||||
return -1;
|
||||
}
|
||||
if (pipe->side != WRITE_SIDE) /* FIXME: should not be necessary */
|
||||
{
|
||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
||||
return -1;
|
||||
}
|
||||
return dup( pipe->fd );
|
||||
}
|
||||
|
||||
static void pipe_destroy( struct object *obj )
|
||||
{
|
||||
struct pipe *pipe = (struct pipe *)obj;
|
||||
assert( obj->ops == &pipe_ops );
|
||||
|
||||
if (pipe->other) pipe->other->other = NULL;
|
||||
close( pipe->fd );
|
||||
free( pipe );
|
||||
}
|
|
@ -56,7 +56,6 @@ static struct process *first_process;
|
|||
|
||||
static void process_dump( struct object *obj, int verbose );
|
||||
static int process_signaled( struct object *obj, struct thread *thread );
|
||||
static int process_satisfied( struct object *obj, struct thread *thread );
|
||||
static void process_destroy( struct object *obj );
|
||||
static void free_handles( struct process *process );
|
||||
static int copy_handle_table( struct process *process, struct process *parent );
|
||||
|
@ -67,7 +66,10 @@ static const struct object_ops process_ops =
|
|||
add_queue,
|
||||
remove_queue,
|
||||
process_signaled,
|
||||
process_satisfied,
|
||||
no_satisfied,
|
||||
no_read_fd,
|
||||
no_write_fd,
|
||||
no_flush,
|
||||
process_destroy
|
||||
};
|
||||
|
||||
|
@ -130,11 +132,6 @@ static int process_signaled( struct object *obj, struct thread *thread )
|
|||
return (process->running_threads > 0);
|
||||
}
|
||||
|
||||
static int process_satisfied( struct object *obj, struct thread *thread )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get a process from an id (and increment the refcount) */
|
||||
struct process *get_process_from_id( void *id )
|
||||
{
|
||||
|
|
116
server/request.c
116
server/request.c
|
@ -4,6 +4,7 @@
|
|||
* Copyright (C) 1998 Alexandre Julliard
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -156,6 +157,8 @@ DECL_HANDLER(init_thread)
|
|||
DECL_HANDLER(set_debug)
|
||||
{
|
||||
debug_level = req->level;
|
||||
/* Make sure last_req is initialized */
|
||||
current->last_req = REQ_SET_DEBUG;
|
||||
CLEAR_ERROR();
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
@ -408,6 +411,64 @@ DECL_HANDLER(get_unix_handle)
|
|||
send_reply( current, handle, 0 );
|
||||
}
|
||||
|
||||
/* get a Unix fd to read from a file */
|
||||
DECL_HANDLER(get_read_fd)
|
||||
{
|
||||
struct object *obj;
|
||||
int read_fd;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, GENERIC_READ, NULL )))
|
||||
{
|
||||
read_fd = obj->ops->get_read_fd( obj );
|
||||
release_object( obj );
|
||||
}
|
||||
else read_fd = -1;
|
||||
send_reply( current, read_fd, 0 );
|
||||
}
|
||||
|
||||
/* get a Unix fd to write to a file */
|
||||
DECL_HANDLER(get_write_fd)
|
||||
{
|
||||
struct object *obj;
|
||||
int write_fd;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, GENERIC_WRITE, NULL )))
|
||||
{
|
||||
write_fd = obj->ops->get_write_fd( obj );
|
||||
release_object( obj );
|
||||
}
|
||||
else write_fd = -1;
|
||||
send_reply( current, write_fd, 0 );
|
||||
}
|
||||
|
||||
/* set a file current position */
|
||||
DECL_HANDLER(set_file_pointer)
|
||||
{
|
||||
struct set_file_pointer_reply reply = { req->low, req->high };
|
||||
set_file_pointer( req->handle, &reply.low, &reply.high, req->whence );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* truncate (or extend) a file */
|
||||
DECL_HANDLER(truncate_file)
|
||||
{
|
||||
truncate_file( req->handle );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* flush a file buffers */
|
||||
DECL_HANDLER(flush_file)
|
||||
{
|
||||
struct object *obj;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, GENERIC_WRITE, NULL )))
|
||||
{
|
||||
obj->ops->flush( obj );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* get a file information */
|
||||
DECL_HANDLER(get_file_info)
|
||||
{
|
||||
|
@ -415,3 +476,58 @@ DECL_HANDLER(get_file_info)
|
|||
get_file_info( req->handle, &reply );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* create an anonymous pipe */
|
||||
DECL_HANDLER(create_pipe)
|
||||
{
|
||||
struct create_pipe_reply reply = { -1, -1 };
|
||||
struct object *obj[2];
|
||||
if (create_pipe( obj ))
|
||||
{
|
||||
reply.handle_read = alloc_handle( current->process, obj[0],
|
||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_READ,
|
||||
req->inherit );
|
||||
if (reply.handle_read != -1)
|
||||
{
|
||||
reply.handle_write = alloc_handle( current->process, obj[1],
|
||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_WRITE,
|
||||
req->inherit );
|
||||
if (reply.handle_write == -1)
|
||||
close_handle( current->process, reply.handle_read );
|
||||
}
|
||||
release_object( obj[0] );
|
||||
release_object( obj[1] );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* create a console */
|
||||
DECL_HANDLER(create_console)
|
||||
{
|
||||
struct create_console_reply reply = { -1, -1 };
|
||||
struct object *obj[2];
|
||||
if (create_console( fd, obj ))
|
||||
{
|
||||
reply.handle_read = alloc_handle( current->process, obj[0],
|
||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_READ,
|
||||
req->inherit );
|
||||
if (reply.handle_read != -1)
|
||||
{
|
||||
reply.handle_write = alloc_handle( current->process, obj[1],
|
||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_WRITE,
|
||||
req->inherit );
|
||||
if (reply.handle_write == -1)
|
||||
close_handle( current->process, reply.handle_read );
|
||||
}
|
||||
release_object( obj[0] );
|
||||
release_object( obj[1] );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set a console fd */
|
||||
DECL_HANDLER(set_console_fd)
|
||||
{
|
||||
set_console_fd( req->handle, fd );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ static const struct object_ops semaphore_ops =
|
|||
remove_queue,
|
||||
semaphore_signaled,
|
||||
semaphore_satisfied,
|
||||
no_read_fd,
|
||||
no_write_fd,
|
||||
no_flush,
|
||||
semaphore_destroy
|
||||
};
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ struct thread_wait
|
|||
|
||||
static void dump_thread( struct object *obj, int verbose );
|
||||
static int thread_signaled( struct object *obj, struct thread *thread );
|
||||
static int thread_satisfied( struct object *obj, struct thread *thread );
|
||||
static void destroy_thread( struct object *obj );
|
||||
|
||||
static const struct object_ops thread_ops =
|
||||
|
@ -52,7 +51,10 @@ static const struct object_ops thread_ops =
|
|||
add_queue,
|
||||
remove_queue,
|
||||
thread_signaled,
|
||||
thread_satisfied,
|
||||
no_satisfied,
|
||||
no_read_fd,
|
||||
no_write_fd,
|
||||
no_flush,
|
||||
destroy_thread
|
||||
};
|
||||
|
||||
|
@ -153,11 +155,6 @@ static int thread_signaled( struct object *obj, struct thread *thread )
|
|||
return (mythread->state == TERMINATED);
|
||||
}
|
||||
|
||||
static int thread_satisfied( struct object *obj, struct thread *thread )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get a thread pointer from a thread id (and increment the refcount) */
|
||||
struct thread *get_thread_from_id( void *id )
|
||||
{
|
||||
|
|
|
@ -229,6 +229,46 @@ static int dump_get_unix_handle_request( struct get_unix_handle_request *req, in
|
|||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_get_read_fd_request( struct get_read_fd_request *req, int len )
|
||||
{
|
||||
printf( " handle=%d", req->handle );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_get_write_fd_request( struct get_write_fd_request *req, int len )
|
||||
{
|
||||
printf( " handle=%d", req->handle );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_set_file_pointer_request( struct set_file_pointer_request *req, int len )
|
||||
{
|
||||
printf( " handle=%d,", req->handle );
|
||||
printf( " low=%d,", req->low );
|
||||
printf( " high=%d,", req->high );
|
||||
printf( " whence=%d", req->whence );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_set_file_pointer_reply( struct set_file_pointer_reply *req, int len )
|
||||
{
|
||||
printf( " low=%d,", req->low );
|
||||
printf( " high=%d", req->high );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_truncate_file_request( struct truncate_file_request *req, int len )
|
||||
{
|
||||
printf( " handle=%d", req->handle );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_flush_file_request( struct flush_file_request *req, int len )
|
||||
{
|
||||
printf( " handle=%d", req->handle );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_get_file_info_request( struct get_file_info_request *req, int len )
|
||||
{
|
||||
printf( " handle=%d", req->handle );
|
||||
|
@ -249,6 +289,38 @@ static int dump_get_file_info_reply( struct get_file_info_reply *req, int len )
|
|||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_create_pipe_request( struct create_pipe_request *req, int len )
|
||||
{
|
||||
printf( " inherit=%d", req->inherit );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_create_pipe_reply( struct create_pipe_reply *req, int len )
|
||||
{
|
||||
printf( " handle_read=%d,", req->handle_read );
|
||||
printf( " handle_write=%d", req->handle_write );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_create_console_request( struct create_console_request *req, int len )
|
||||
{
|
||||
printf( " inherit=%d", req->inherit );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_create_console_reply( struct create_console_reply *req, int len )
|
||||
{
|
||||
printf( " handle_read=%d,", req->handle_read );
|
||||
printf( " handle_write=%d", req->handle_write );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_set_console_fd_request( struct set_console_fd_request *req, int len )
|
||||
{
|
||||
printf( " handle=%d", req->handle );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
struct dumper
|
||||
{
|
||||
int (*dump_req)( void *data, int len );
|
||||
|
@ -297,8 +369,24 @@ static const struct dumper dumpers[REQ_NB_REQUESTS] =
|
|||
(void(*)())dump_create_file_reply },
|
||||
{ (int(*)(void *,int))dump_get_unix_handle_request,
|
||||
(void(*)())0 },
|
||||
{ (int(*)(void *,int))dump_get_read_fd_request,
|
||||
(void(*)())0 },
|
||||
{ (int(*)(void *,int))dump_get_write_fd_request,
|
||||
(void(*)())0 },
|
||||
{ (int(*)(void *,int))dump_set_file_pointer_request,
|
||||
(void(*)())dump_set_file_pointer_reply },
|
||||
{ (int(*)(void *,int))dump_truncate_file_request,
|
||||
(void(*)())0 },
|
||||
{ (int(*)(void *,int))dump_flush_file_request,
|
||||
(void(*)())0 },
|
||||
{ (int(*)(void *,int))dump_get_file_info_request,
|
||||
(void(*)())dump_get_file_info_reply },
|
||||
{ (int(*)(void *,int))dump_create_pipe_request,
|
||||
(void(*)())dump_create_pipe_reply },
|
||||
{ (int(*)(void *,int))dump_create_console_request,
|
||||
(void(*)())dump_create_console_reply },
|
||||
{ (int(*)(void *,int))dump_set_console_fd_request,
|
||||
(void(*)())0 },
|
||||
};
|
||||
|
||||
static const char * const req_names[REQ_NB_REQUESTS] =
|
||||
|
@ -323,7 +411,15 @@ static const char * const req_names[REQ_NB_REQUESTS] =
|
|||
"open_named_obj",
|
||||
"create_file",
|
||||
"get_unix_handle",
|
||||
"get_read_fd",
|
||||
"get_write_fd",
|
||||
"set_file_pointer",
|
||||
"truncate_file",
|
||||
"flush_file",
|
||||
"get_file_info",
|
||||
"create_pipe",
|
||||
"create_console",
|
||||
"set_console_fd",
|
||||
};
|
||||
|
||||
void trace_request( enum request req, void *data, int len, int fd )
|
||||
|
|
Loading…
Reference in New Issue