| /* |
| * Server-side pipe management |
| * |
| * Copyright (C) 1998 Alexandre Julliard |
| */ |
| |
| #include "config.h" |
| |
| #include <assert.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #ifdef HAVE_SYS_ERRNO_H |
| #include <sys/errno.h> |
| #endif |
| #include <sys/stat.h> |
| #include <sys/time.h> |
| #include <sys/types.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #include "winerror.h" |
| #include "winbase.h" |
| |
| #include "handle.h" |
| #include "thread.h" |
| #include "request.h" |
| |
| enum side { READ_SIDE, WRITE_SIDE }; |
| |
| struct pipe |
| { |
| struct object obj; /* object header */ |
| struct pipe *other; /* the pipe other end */ |
| enum side side; /* which side of the pipe is this */ |
| }; |
| |
| static void pipe_dump( struct object *obj, int verbose ); |
| static int pipe_get_poll_events( struct object *obj ); |
| static int pipe_get_read_fd( struct object *obj ); |
| static int pipe_get_write_fd( struct object *obj ); |
| static int pipe_get_info( struct object *obj, struct get_file_info_request *req ); |
| static void pipe_destroy( struct object *obj ); |
| |
| static const struct object_ops pipe_ops = |
| { |
| sizeof(struct pipe), /* size */ |
| pipe_dump, /* dump */ |
| default_poll_add_queue, /* add_queue */ |
| default_poll_remove_queue, /* remove_queue */ |
| default_poll_signaled, /* signaled */ |
| no_satisfied, /* satisfied */ |
| pipe_get_poll_events, /* get_poll_events */ |
| default_poll_event, /* poll_event */ |
| pipe_get_read_fd, /* get_read_fd */ |
| pipe_get_write_fd, /* get_write_fd */ |
| no_flush, /* flush */ |
| pipe_get_info, /* get_file_info */ |
| pipe_destroy /* destroy */ |
| }; |
| |
| |
| static struct pipe *create_pipe_side( int fd, int side ) |
| { |
| struct pipe *pipe; |
| |
| if ((pipe = alloc_object( &pipe_ops, fd ))) |
| { |
| pipe->other = NULL; |
| pipe->side = side; |
| } |
| return pipe; |
| } |
| |
| static int create_pipe( struct object *obj[2] ) |
| { |
| struct pipe *read_pipe; |
| struct pipe *write_pipe; |
| int fd[2]; |
| |
| if (pipe( fd ) == -1) |
| { |
| file_set_error(); |
| return 0; |
| } |
| if ((read_pipe = create_pipe_side( fd[0], READ_SIDE ))) |
| { |
| if ((write_pipe = create_pipe_side( fd[1], WRITE_SIDE ))) |
| { |
| write_pipe->other = read_pipe; |
| read_pipe->other = write_pipe; |
| obj[0] = &read_pipe->obj; |
| obj[1] = &write_pipe->obj; |
| return 1; |
| } |
| release_object( read_pipe ); |
| } |
| else close( fd[1] ); |
| return 0; |
| } |
| |
| static void pipe_dump( struct object *obj, int verbose ) |
| { |
| struct pipe *pipe = (struct pipe *)obj; |
| assert( obj->ops == &pipe_ops ); |
| fprintf( stderr, "Pipe %s-side fd=%d\n", |
| (pipe->side == READ_SIDE) ? "read" : "write", pipe->obj.fd ); |
| } |
| |
| static int pipe_get_poll_events( struct object *obj ) |
| { |
| struct pipe *pipe = (struct pipe *)obj; |
| assert( obj->ops == &pipe_ops ); |
| return (pipe->side == READ_SIDE) ? POLLIN : POLLOUT; |
| } |
| |
| 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->obj.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->obj.fd ); |
| } |
| |
| static int pipe_get_info( struct object *obj, struct get_file_info_request *req ) |
| { |
| req->type = FILE_TYPE_PIPE; |
| req->attr = 0; |
| req->access_time = 0; |
| req->write_time = 0; |
| req->size_high = 0; |
| req->size_low = 0; |
| req->links = 0; |
| req->index_high = 0; |
| req->index_low = 0; |
| req->serial = 0; |
| return 1; |
| } |
| |
| 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; |
| } |
| |
| /* create an anonymous pipe */ |
| DECL_HANDLER(create_pipe) |
| { |
| struct object *obj[2]; |
| int hread = -1, hwrite = -1; |
| |
| if (create_pipe( obj )) |
| { |
| hread = alloc_handle( current->process, obj[0], |
| STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_READ, |
| req->inherit ); |
| if (hread != -1) |
| { |
| hwrite = alloc_handle( current->process, obj[1], |
| STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_WRITE, |
| req->inherit ); |
| if (hwrite == -1) |
| close_handle( current->process, hread ); |
| } |
| release_object( obj[0] ); |
| release_object( obj[1] ); |
| } |
| req->handle_read = hread; |
| req->handle_write = hwrite; |
| } |