diff --git a/server/fd.c b/server/fd.c index 37e0ef214da..ba182f4ba0c 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1224,14 +1224,14 @@ static inline void unmount_fd( struct fd *fd ) } /* allocate an fd object, without setting the unix fd yet */ -struct fd *alloc_fd( const struct fd_ops *fd_user_ops, struct object *user ) +static struct fd *alloc_fd_object(void) { struct fd *fd = alloc_object( &fd_ops ); if (!fd) return NULL; - fd->fd_ops = fd_user_ops; - fd->user = user; + fd->fd_ops = NULL; + fd->user = NULL; fd->inode = NULL; fd->closed = NULL; fd->access = 0; @@ -1311,17 +1311,24 @@ static int check_sharing( struct fd *fd, unsigned int access, unsigned int shari return 1; } -/* open() wrapper using a struct fd */ -/* the fd must have been created with alloc_fd */ -/* on error the fd object is released */ -struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode, - unsigned int access, unsigned int sharing, unsigned int options ) +/* sets the user of an fd that previously had no user */ +void set_fd_user( struct fd *fd, const struct fd_ops *user_ops, struct object *user ) +{ + assert( fd->fd_ops == NULL ); + fd->fd_ops = user_ops; + fd->user = user; +} + +/* open() wrapper that returns a struct fd with no fd user set */ +struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int access, + unsigned int sharing, unsigned int options ) { struct stat st; struct closed_fd *closed_fd; + struct fd *fd; const char *unlink_name = ""; - assert( fd->unix_fd == -1 ); + if (!(fd = alloc_fd_object())) return NULL; if (options & FILE_DELETE_ON_CLOSE) unlink_name = name; if (!(closed_fd = mem_alloc( sizeof(*closed_fd) + strlen(unlink_name) ))) @@ -1337,9 +1344,7 @@ struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode, if (errno != EEXIST || (flags & O_EXCL)) { file_set_error(); - release_object( fd ); - free( closed_fd ); - return NULL; + goto error; } } flags &= ~(O_CREAT | O_EXCL | O_TRUNC); @@ -1347,9 +1352,7 @@ struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode, if ((fd->unix_fd = open( name, flags & ~O_TRUNC, *mode )) == -1) { file_set_error(); - release_object( fd ); - free( closed_fd ); - return NULL; + goto error; } closed_fd->unix_fd = fd->unix_fd; closed_fd->unlink[0] = 0; @@ -1420,10 +1423,11 @@ error: /* if the function fails the unix fd is closed */ struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, int unix_fd, struct object *user ) { - struct fd *fd = alloc_fd( fd_user_ops, user ); + struct fd *fd = alloc_fd_object(); if (fd) { + set_fd_user( fd, fd_user_ops, user ); fd->unix_fd = unix_fd; return fd; } diff --git a/server/file.c b/server/file.c index 84215c53ef3..bc8f63dd16a 100644 --- a/server/file.c +++ b/server/file.c @@ -61,6 +61,8 @@ struct file unsigned int options; /* file options (FILE_DELETE_ON_CLOSE, FILE_SYNCHRONOUS...) */ }; +static unsigned int generic_file_map_access( unsigned int access ); + static void file_dump( struct object *obj, int verbose ); static struct fd *file_get_fd( struct object *obj ); static unsigned int file_map_access( struct object *obj, unsigned int access ); @@ -120,12 +122,25 @@ static struct file *create_file_for_fd( int fd, unsigned int access, unsigned in return file; } +static struct object *create_file_obj( struct fd *fd, unsigned int access, unsigned int options ) +{ + struct file *file = alloc_object( &file_ops ); + + if (!file) return NULL; + file->access = access; + file->options = options; + file->fd = fd; + grab_object( fd ); + set_fd_user( fd, &file_fd_ops, &file->obj ); + return &file->obj; +} static struct object *create_file( const char *nameptr, size_t len, unsigned int access, unsigned int sharing, int create, unsigned int options, unsigned int attrs ) { - struct file *file; + struct object *obj = NULL; + struct fd *fd; int flags, rw_mode; char *name; mode_t mode; @@ -142,7 +157,7 @@ static struct object *create_file( const char *nameptr, size_t len, unsigned int case FILE_OPEN: flags = 0; break; case FILE_OPEN_IF: flags = O_CREAT; break; case FILE_OVERWRITE: flags = O_TRUNC; break; - default: set_error( STATUS_INVALID_PARAMETER ); goto error; + default: set_error( STATUS_INVALID_PARAMETER ); goto done; } mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666; @@ -151,14 +166,11 @@ static struct object *create_file( const char *nameptr, size_t len, unsigned int (!strcasecmp( name + len - 4, ".exe" ) || !strcasecmp( name + len - 4, ".com" ))) mode |= 0111; - if (!(file = alloc_object( &file_ops ))) goto error; - - file->access = file_map_access( &file->obj, access ); - file->options = options; + access = generic_file_map_access( access ); rw_mode = 0; - if (file->access & FILE_UNIX_READ_ACCESS) rw_mode |= FILE_READ_DATA; - if (file->access & FILE_UNIX_WRITE_ACCESS) rw_mode |= FILE_WRITE_DATA; + if (access & FILE_UNIX_READ_ACCESS) rw_mode |= FILE_READ_DATA; + if (access & FILE_UNIX_WRITE_ACCESS) rw_mode |= FILE_WRITE_DATA; switch(rw_mode) { case 0: break; @@ -168,29 +180,19 @@ static struct object *create_file( const char *nameptr, size_t len, unsigned int } /* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */ - if (!(file->fd = alloc_fd( &file_fd_ops, &file->obj )) || - !(file->fd = open_fd( file->fd, name, flags | O_NONBLOCK | O_LARGEFILE, - &mode, file->access, sharing, options ))) - { - free( name ); - release_object( file ); - return NULL; - } + fd = open_fd( name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options ); + if (!fd) goto done; + + if (S_ISCHR(mode) && is_serial_fd( fd )) + obj = create_serial( fd, options ); + else + obj = create_file_obj( fd, access, options ); + + release_object( fd ); + +done: free( name ); - - /* check for serial port */ - if (S_ISCHR(mode) && is_serial_fd( file->fd )) - { - struct object *obj = create_serial( file->fd, file->options ); - release_object( file ); - return obj; - } - - return &file->obj; - - error: - free( name ); - return NULL; + return obj; } /* check if two file objects point to the same file */ @@ -260,7 +262,7 @@ static struct fd *file_get_fd( struct object *obj ) return (struct fd *)grab_object( file->fd ); } -static unsigned int file_map_access( struct object *obj, unsigned int access ) +static unsigned int generic_file_map_access( unsigned int access ) { if (access & GENERIC_READ) access |= FILE_GENERIC_READ; if (access & GENERIC_WRITE) access |= FILE_GENERIC_WRITE; @@ -269,6 +271,11 @@ static unsigned int file_map_access( struct object *obj, unsigned int access ) return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); } +static unsigned int file_map_access( struct object *obj, unsigned int access ) +{ + return generic_file_map_access( access ); +} + static void file_destroy( struct object *obj ) { struct file *file = (struct file *)obj; diff --git a/server/file.h b/server/file.h index a4e8c7aaebd..5b139af0bde 100644 --- a/server/file.h +++ b/server/file.h @@ -46,13 +46,13 @@ struct fd_ops /* 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 *open_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, int unix_fd, struct object *user ); 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 int get_unix_fd( struct fd *fd ); extern int is_same_file_fd( struct fd *fd1, struct fd *fd2 ); extern void fd_poll_event( struct fd *fd, int event );