blob: f57ed97d3b1115c08068a9901b9555f9cf47e86c [file] [log] [blame]
Alexandre Julliard863637b2003-01-30 00:26:44 +00001/*
2 * Server-side file descriptor management
3 *
Alexandre Julliardce613492003-03-18 05:04:33 +00004 * Copyright (C) 2000, 2003 Alexandre Julliard
Alexandre Julliard863637b2003-01-30 00:26:44 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard863637b2003-01-30 00:26:44 +000019 */
20
21
22#include "config.h"
Alexandre Julliard49b7fdc2005-08-03 21:25:10 +000023#include "wine/port.h"
Alexandre Julliard863637b2003-01-30 00:26:44 +000024
25#include <assert.h>
Alexandre Julliardce613492003-03-18 05:04:33 +000026#include <errno.h>
Alexandre Julliard580da242003-03-12 22:38:14 +000027#include <fcntl.h>
Alexandre Julliardce613492003-03-18 05:04:33 +000028#include <limits.h>
Alexandre Julliarde66207e2003-02-19 00:33:32 +000029#include <signal.h>
Alexandre Julliard684b65c2004-04-16 04:31:35 +000030#include <stdarg.h>
Alexandre Julliard863637b2003-01-30 00:26:44 +000031#include <stdio.h>
32#include <string.h>
33#include <stdlib.h>
Steven Edwards57279182005-03-04 12:38:36 +000034#ifdef HAVE_POLL_H
35#include <poll.h>
36#endif
Alexandre Julliarde66207e2003-02-19 00:33:32 +000037#ifdef HAVE_SYS_POLL_H
38#include <sys/poll.h>
39#endif
Alexandre Julliard30b878b2006-11-01 13:28:05 +010040#ifdef HAVE_LINUX_MAJOR_H
41#include <linux/major.h>
42#endif
43#ifdef HAVE_SYS_STATVFS_H
44#include <sys/statvfs.h>
45#endif
46#ifdef HAVE_SYS_VFS_H
Petr Sumberaf4575aa2008-04-10 17:03:18 +020047/*
48 * Solaris defines its system list in sys/list.h.
49 * This need to be workaround it here.
50 */
51#define list SYSLIST
52#define list_next SYSLIST_NEXT
53#define list_prev SYSLIST_PREV
54#define list_head SYSLIST_HEAD
55#define list_tail SYSLIST_TAIL
56#define list_move_tail SYSLIST_MOVE_TAIL
57#define list_remove SYSLIST_REMOVE
Alexandre Julliard30b878b2006-11-01 13:28:05 +010058#include <sys/vfs.h>
Petr Sumberaf4575aa2008-04-10 17:03:18 +020059#undef list
60#undef list_next
61#undef list_prev
62#undef list_head
63#undef list_tail
64#undef list_move_tail
65#undef list_remove
Alexandre Julliard30b878b2006-11-01 13:28:05 +010066#endif
Gerald Pfeifer35f0a412006-11-05 06:50:45 +010067#ifdef HAVE_SYS_PARAM_H
68#include <sys/param.h>
69#endif
Alexandre Julliard30b878b2006-11-01 13:28:05 +010070#ifdef HAVE_SYS_MOUNT_H
71#include <sys/mount.h>
72#endif
73#ifdef HAVE_SYS_STATFS_H
74#include <sys/statfs.h>
75#endif
Alexandre Julliard8143d422007-06-15 12:41:43 +020076#ifdef HAVE_SYS_SYSCTL_H
77#include <sys/sysctl.h>
78#endif
Alexandre Julliardc8278922006-08-04 22:11:00 +020079#ifdef HAVE_SYS_EVENT_H
80#include <sys/event.h>
81#undef LIST_INIT
82#undef LIST_ENTRY
83#endif
Alexandre Julliard969f57c2004-09-23 04:48:24 +000084#ifdef HAVE_STDINT_H
85#include <stdint.h>
86#endif
Alexandre Julliard580da242003-03-12 22:38:14 +000087#include <sys/stat.h>
Alexandre Julliarde66207e2003-02-19 00:33:32 +000088#include <sys/time.h>
89#include <sys/types.h>
Alexandre Julliard863637b2003-01-30 00:26:44 +000090#include <unistd.h>
91
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010092#include "ntstatus.h"
93#define WIN32_NO_STATUS
Alexandre Julliard863637b2003-01-30 00:26:44 +000094#include "object.h"
95#include "file.h"
96#include "handle.h"
97#include "process.h"
98#include "request.h"
99
Alexandre Julliard684b65c2004-04-16 04:31:35 +0000100#include "winternl.h"
Alexandre Julliard2669af72007-04-16 14:54:52 +0200101#include "winioctl.h"
Alexandre Julliard684b65c2004-04-16 04:31:35 +0000102
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000103#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL_CREATE)
Alexandre Julliard626aa332004-10-27 01:03:30 +0000104# include <sys/epoll.h>
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000105# define USE_EPOLL
Alexandre Julliard626aa332004-10-27 01:03:30 +0000106#elif defined(linux) && defined(__i386__) && defined(HAVE_STDINT_H)
107# define USE_EPOLL
108# define EPOLLIN POLLIN
109# define EPOLLOUT POLLOUT
110# define EPOLLERR POLLERR
111# define EPOLLHUP POLLHUP
112# define EPOLL_CTL_ADD 1
113# define EPOLL_CTL_DEL 2
114# define EPOLL_CTL_MOD 3
115
116typedef union epoll_data
117{
118 void *ptr;
119 int fd;
120 uint32_t u32;
121 uint64_t u64;
122} epoll_data_t;
123
124struct epoll_event
125{
126 uint32_t events;
127 epoll_data_t data;
128};
129
130#define SYSCALL_RET(ret) do { \
131 if (ret < 0) { errno = -ret; ret = -1; } \
132 return ret; \
133 } while(0)
134
135static inline int epoll_create( int size )
136{
137 int ret;
138 __asm__( "pushl %%ebx; movl %2,%%ebx; int $0x80; popl %%ebx"
Peter Chapman505dfde2004-12-02 18:19:25 +0000139 : "=a" (ret) : "0" (254 /*NR_epoll_create*/), "r" (size) );
Alexandre Julliard626aa332004-10-27 01:03:30 +0000140 SYSCALL_RET(ret);
141}
142
143static inline int epoll_ctl( int epfd, int op, int fd, const struct epoll_event *event )
144{
145 int ret;
146 __asm__( "pushl %%ebx; movl %2,%%ebx; int $0x80; popl %%ebx"
147 : "=a" (ret)
Peter Chapman505dfde2004-12-02 18:19:25 +0000148 : "0" (255 /*NR_epoll_ctl*/), "r" (epfd), "c" (op), "d" (fd), "S" (event), "m" (*event) );
Alexandre Julliard626aa332004-10-27 01:03:30 +0000149 SYSCALL_RET(ret);
150}
151
152static inline int epoll_wait( int epfd, struct epoll_event *events, int maxevents, int timeout )
153{
154 int ret;
155 __asm__( "pushl %%ebx; movl %2,%%ebx; int $0x80; popl %%ebx"
156 : "=a" (ret)
Peter Chapman505dfde2004-12-02 18:19:25 +0000157 : "0" (256 /*NR_epoll_wait*/), "r" (epfd), "c" (events), "d" (maxevents), "S" (timeout)
Alexandre Julliard626aa332004-10-27 01:03:30 +0000158 : "memory" );
159 SYSCALL_RET(ret);
160}
161#undef SYSCALL_RET
162
163#endif /* linux && __i386__ && HAVE_STDINT_H */
164
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000165
Alexandre Julliardce613492003-03-18 05:04:33 +0000166/* Because of the stupid Posix locking semantics, we need to keep
167 * track of all file descriptors referencing a given file, and not
168 * close a single one until all the locks are gone (sigh).
169 */
170
Alexandre Julliard580da242003-03-12 22:38:14 +0000171/* file descriptor object */
172
173/* closed_fd is used to keep track of the unix fd belonging to a closed fd object */
174struct closed_fd
175{
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000176 struct list entry; /* entry in inode closed list */
Alexandre Julliardc1325422005-07-28 10:48:57 +0000177 int unix_fd; /* the unix file descriptor */
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000178 char unlink[1]; /* name to unlink on close (if any) */
Alexandre Julliard580da242003-03-12 22:38:14 +0000179};
180
Alexandre Julliard863637b2003-01-30 00:26:44 +0000181struct fd
182{
Alexandre Julliard580da242003-03-12 22:38:14 +0000183 struct object obj; /* object header */
184 const struct fd_ops *fd_ops; /* file descriptor operations */
185 struct inode *inode; /* inode that this fd belongs to */
186 struct list inode_entry; /* entry in inode fd list */
187 struct closed_fd *closed; /* structure to store the unix fd at destroy time */
188 struct object *user; /* object using this file descriptor */
Alexandre Julliardce613492003-03-18 05:04:33 +0000189 struct list locks; /* list of locks on this fd */
Alexandre Julliarda510a7e2005-12-12 16:46:17 +0100190 unsigned int access; /* file access (FILE_READ_DATA etc.) */
Alexandre Julliardf85437c2007-04-10 22:25:07 +0200191 unsigned int options; /* file options (FILE_DELETE_ON_CLOSE, FILE_SYNCHRONOUS...) */
Alexandre Julliard74bd1e42004-03-27 20:48:42 +0000192 unsigned int sharing; /* file sharing mode */
Henri Verbeet27705d52009-11-12 15:10:12 +0100193 char *unix_name; /* unix file name */
Alexandre Julliard580da242003-03-12 22:38:14 +0000194 int unix_fd; /* unix file descriptor */
Alexandre Julliardf3fbae42007-04-18 16:05:59 +0200195 unsigned int no_fd_status;/* status to return when unix_fd is -1 */
Michael Stefaniuc0eed4402009-10-01 00:22:55 +0200196 unsigned int signaled :1; /* is the fd signaled? */
197 unsigned int fs_locks :1; /* can we use filesystem locks for this fd? */
Alexandre Julliard580da242003-03-12 22:38:14 +0000198 int poll_index; /* index of fd in poll array */
Alexandre Julliarddf09ac52007-04-02 20:09:29 +0200199 struct async_queue *read_q; /* async readers of this fd */
200 struct async_queue *write_q; /* async writers of this fd */
201 struct async_queue *wait_q; /* other async waiters of this fd */
Andrey Turkind1a81552007-09-28 00:03:39 +0400202 struct completion *completion; /* completion object attached to this fd */
Alexandre Julliarddc7f1702008-12-15 13:29:38 +0100203 apc_param_t comp_key; /* completion key to set in completion events */
Alexandre Julliard863637b2003-01-30 00:26:44 +0000204};
205
206static void fd_dump( struct object *obj, int verbose );
207static void fd_destroy( struct object *obj );
208
209static const struct object_ops fd_ops =
210{
211 sizeof(struct fd), /* size */
212 fd_dump, /* dump */
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100213 no_get_type, /* get_type */
Alexandre Julliard863637b2003-01-30 00:26:44 +0000214 no_add_queue, /* add_queue */
215 NULL, /* remove_queue */
216 NULL, /* signaled */
217 NULL, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +0000218 no_signal, /* signal */
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000219 no_get_fd, /* get_fd */
Alexandre Julliard28beba32005-12-12 14:57:40 +0100220 no_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +0100221 default_get_sd, /* get_sd */
222 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000223 no_lookup_name, /* lookup_name */
Alexandre Julliard7e71c1d2007-03-22 11:44:29 +0100224 no_open_file, /* open_file */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000225 no_close_handle, /* close_handle */
Alexandre Julliard863637b2003-01-30 00:26:44 +0000226 fd_destroy /* destroy */
227};
228
Alexandre Julliardd4325152005-07-30 19:09:43 +0000229/* device object */
230
231#define DEVICE_HASH_SIZE 7
232#define INODE_HASH_SIZE 17
233
234struct device
235{
236 struct object obj; /* object header */
237 struct list entry; /* entry in device hash list */
238 dev_t dev; /* device number */
Alexandre Julliardf62f6e82005-08-24 18:33:50 +0000239 int removable; /* removable device? (or -1 if unknown) */
Alexandre Julliardd4325152005-07-30 19:09:43 +0000240 struct list inode_hash[INODE_HASH_SIZE]; /* inodes hash table */
241};
242
243static void device_dump( struct object *obj, int verbose );
244static void device_destroy( struct object *obj );
245
246static const struct object_ops device_ops =
247{
248 sizeof(struct device), /* size */
249 device_dump, /* dump */
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100250 no_get_type, /* get_type */
Alexandre Julliardd4325152005-07-30 19:09:43 +0000251 no_add_queue, /* add_queue */
252 NULL, /* remove_queue */
253 NULL, /* signaled */
254 NULL, /* satisfied */
255 no_signal, /* signal */
256 no_get_fd, /* get_fd */
Alexandre Julliard28beba32005-12-12 14:57:40 +0100257 no_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +0100258 default_get_sd, /* get_sd */
259 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000260 no_lookup_name, /* lookup_name */
Alexandre Julliard7e71c1d2007-03-22 11:44:29 +0100261 no_open_file, /* open_file */
Alexandre Julliardd4325152005-07-30 19:09:43 +0000262 no_close_handle, /* close_handle */
263 device_destroy /* destroy */
264};
265
Alexandre Julliard580da242003-03-12 22:38:14 +0000266/* inode object */
267
268struct inode
269{
270 struct object obj; /* object header */
271 struct list entry; /* inode hash list entry */
Alexandre Julliardd4325152005-07-30 19:09:43 +0000272 struct device *device; /* device containing this inode */
Alexandre Julliard580da242003-03-12 22:38:14 +0000273 ino_t ino; /* inode number */
274 struct list open; /* list of open file descriptors */
Alexandre Julliardce613492003-03-18 05:04:33 +0000275 struct list locks; /* list of file locks */
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000276 struct list closed; /* list of file descriptors to close at destroy time */
Alexandre Julliard580da242003-03-12 22:38:14 +0000277};
278
279static void inode_dump( struct object *obj, int verbose );
280static void inode_destroy( struct object *obj );
281
282static const struct object_ops inode_ops =
283{
284 sizeof(struct inode), /* size */
285 inode_dump, /* dump */
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100286 no_get_type, /* get_type */
Alexandre Julliard580da242003-03-12 22:38:14 +0000287 no_add_queue, /* add_queue */
288 NULL, /* remove_queue */
289 NULL, /* signaled */
290 NULL, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +0000291 no_signal, /* signal */
Alexandre Julliard580da242003-03-12 22:38:14 +0000292 no_get_fd, /* get_fd */
Alexandre Julliard28beba32005-12-12 14:57:40 +0100293 no_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +0100294 default_get_sd, /* get_sd */
295 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000296 no_lookup_name, /* lookup_name */
Alexandre Julliard7e71c1d2007-03-22 11:44:29 +0100297 no_open_file, /* open_file */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000298 no_close_handle, /* close_handle */
Alexandre Julliard580da242003-03-12 22:38:14 +0000299 inode_destroy /* destroy */
300};
301
Alexandre Julliardce613492003-03-18 05:04:33 +0000302/* file lock object */
303
304struct file_lock
305{
306 struct object obj; /* object header */
307 struct fd *fd; /* fd owning this lock */
308 struct list fd_entry; /* entry in list of locks on a given fd */
309 struct list inode_entry; /* entry in inode list of locks */
310 int shared; /* shared lock? */
311 file_pos_t start; /* locked region is interval [start;end) */
312 file_pos_t end;
313 struct process *process; /* process owning this lock */
314 struct list proc_entry; /* entry in list of locks owned by the process */
315};
316
317static void file_lock_dump( struct object *obj, int verbose );
318static int file_lock_signaled( struct object *obj, struct thread *thread );
319
320static const struct object_ops file_lock_ops =
321{
322 sizeof(struct file_lock), /* size */
323 file_lock_dump, /* dump */
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100324 no_get_type, /* get_type */
Alexandre Julliardce613492003-03-18 05:04:33 +0000325 add_queue, /* add_queue */
326 remove_queue, /* remove_queue */
327 file_lock_signaled, /* signaled */
328 no_satisfied, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +0000329 no_signal, /* signal */
Alexandre Julliardce613492003-03-18 05:04:33 +0000330 no_get_fd, /* get_fd */
Alexandre Julliard28beba32005-12-12 14:57:40 +0100331 no_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +0100332 default_get_sd, /* get_sd */
333 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000334 no_lookup_name, /* lookup_name */
Alexandre Julliard7e71c1d2007-03-22 11:44:29 +0100335 no_open_file, /* open_file */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000336 no_close_handle, /* close_handle */
Alexandre Julliardce613492003-03-18 05:04:33 +0000337 no_destroy /* destroy */
338};
339
340
341#define OFF_T_MAX (~((file_pos_t)1 << (8*sizeof(off_t)-1)))
342#define FILE_POS_T_MAX (~(file_pos_t)0)
343
344static file_pos_t max_unix_offset = OFF_T_MAX;
345
Alexandre Julliard580da242003-03-12 22:38:14 +0000346#define DUMP_LONG_LONG(val) do { \
347 if (sizeof(val) > sizeof(unsigned long) && (val) > ~0UL) \
Alexandre Julliard0fa71702006-06-15 14:14:31 +0200348 fprintf( stderr, "%lx%08lx", (unsigned long)((unsigned long long)(val) >> 32), (unsigned long)(val) ); \
Alexandre Julliard580da242003-03-12 22:38:14 +0000349 else \
350 fprintf( stderr, "%lx", (unsigned long)(val) ); \
351 } while (0)
352
353
Alexandre Julliard863637b2003-01-30 00:26:44 +0000354
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000355/****************************************************************/
356/* timeouts support */
357
358struct timeout_user
359{
Alexandre Julliard15e12da2004-09-08 04:17:31 +0000360 struct list entry; /* entry in sorted timeout list */
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200361 timeout_t when; /* timeout expiry (absolute time) */
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000362 timeout_callback callback; /* callback function */
363 void *private; /* callback private data */
364};
365
Alexandre Julliard15e12da2004-09-08 04:17:31 +0000366static struct list timeout_list = LIST_INIT(timeout_list); /* sorted timeouts list */
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200367timeout_t current_time;
368
369static inline void set_current_time(void)
370{
371 static const timeout_t ticks_1601_to_1970 = (timeout_t)86400 * (369 * 365 + 89) * TICKS_PER_SEC;
372 struct timeval now;
373 gettimeofday( &now, NULL );
374 current_time = (timeout_t)now.tv_sec * TICKS_PER_SEC + now.tv_usec * 10 + ticks_1601_to_1970;
375}
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000376
377/* add a timeout user */
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200378struct timeout_user *add_timeout_user( timeout_t when, timeout_callback func, void *private )
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000379{
380 struct timeout_user *user;
Alexandre Julliard15e12da2004-09-08 04:17:31 +0000381 struct list *ptr;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000382
383 if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200384 user->when = (when > 0) ? when : current_time - when;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000385 user->callback = func;
386 user->private = private;
387
388 /* Now insert it in the linked list */
389
Alexandre Julliard15e12da2004-09-08 04:17:31 +0000390 LIST_FOR_EACH( ptr, &timeout_list )
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000391 {
Alexandre Julliard15e12da2004-09-08 04:17:31 +0000392 struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200393 if (timeout->when >= user->when) break;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000394 }
Alexandre Julliard15e12da2004-09-08 04:17:31 +0000395 list_add_before( ptr, &user->entry );
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000396 return user;
397}
398
399/* remove a timeout user */
400void remove_timeout_user( struct timeout_user *user )
401{
Alexandre Julliard15e12da2004-09-08 04:17:31 +0000402 list_remove( &user->entry );
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000403 free( user );
404}
405
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200406/* return a text description of a timeout for debugging purposes */
407const char *get_timeout_str( timeout_t timeout )
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000408{
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200409 static char buffer[64];
410 long secs, nsecs;
411
412 if (!timeout) return "0";
413 if (timeout == TIMEOUT_INFINITE) return "infinite";
414
415 if (timeout < 0) /* relative */
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000416 {
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200417 secs = -timeout / TICKS_PER_SEC;
418 nsecs = -timeout % TICKS_PER_SEC;
419 sprintf( buffer, "+%ld.%07ld", secs, nsecs );
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000420 }
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200421 else /* absolute */
422 {
423 secs = (timeout - current_time) / TICKS_PER_SEC;
424 nsecs = (timeout - current_time) % TICKS_PER_SEC;
425 if (nsecs < 0)
426 {
427 nsecs += TICKS_PER_SEC;
428 secs--;
429 }
430 if (secs >= 0)
431 sprintf( buffer, "%x%08x (+%ld.%07ld)",
432 (unsigned int)(timeout >> 32), (unsigned int)timeout, secs, nsecs );
433 else
434 sprintf( buffer, "%x%08x (-%ld.%07ld)",
435 (unsigned int)(timeout >> 32), (unsigned int)timeout,
436 -(secs + 1), TICKS_PER_SEC - nsecs );
437 }
438 return buffer;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000439}
440
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000441
442/****************************************************************/
443/* poll support */
444
445static struct fd **poll_users; /* users array */
446static struct pollfd *pollfd; /* poll fd array */
447static int nb_users; /* count of array entries actually in use */
448static int active_users; /* current number of active users */
449static int allocated_users; /* count of allocated entries in the array */
450static struct fd **freelist; /* list of free entries in the array */
451
Alexandre Julliard2f407272006-08-03 19:56:55 +0200452static int get_next_timeout(void);
453
Dmitry Timoshkovf2213dd2007-12-03 17:47:31 +0800454static inline void fd_poll_event( struct fd *fd, int event )
455{
456 fd->fd_ops->poll_event( fd, event );
457}
458
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000459#ifdef USE_EPOLL
460
Alexandre Julliardc8278922006-08-04 22:11:00 +0200461static int epoll_fd = -1;
Alexandre Julliard2f407272006-08-03 19:56:55 +0200462
463static inline void init_epoll(void)
464{
465 epoll_fd = epoll_create( 128 );
466}
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000467
468/* set the events that epoll waits for on this fd; helper for set_fd_events */
469static inline void set_fd_epoll_events( struct fd *fd, int user, int events )
470{
471 struct epoll_event ev;
472 int ctl;
473
474 if (epoll_fd == -1) return;
475
476 if (events == -1) /* stop waiting on this fd completely */
477 {
478 if (pollfd[user].fd == -1) return; /* already removed */
479 ctl = EPOLL_CTL_DEL;
480 }
481 else if (pollfd[user].fd == -1)
482 {
483 if (pollfd[user].events) return; /* stopped waiting on it, don't restart */
484 ctl = EPOLL_CTL_ADD;
485 }
486 else
487 {
488 if (pollfd[user].events == events) return; /* nothing to do */
489 ctl = EPOLL_CTL_MOD;
490 }
491
492 ev.events = events;
Eric Pouech2e0b5332006-01-27 16:17:51 +0100493 memset(&ev.data, 0, sizeof(ev.data));
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000494 ev.data.u32 = user;
495
496 if (epoll_ctl( epoll_fd, ctl, fd->unix_fd, &ev ) == -1)
497 {
498 if (errno == ENOMEM) /* not enough memory, give up on epoll */
499 {
500 close( epoll_fd );
501 epoll_fd = -1;
502 }
503 else perror( "epoll_ctl" ); /* should not happen */
504 }
505}
506
Alexandre Julliard2f407272006-08-03 19:56:55 +0200507static inline void remove_epoll_user( struct fd *fd, int user )
508{
509 if (epoll_fd == -1) return;
510
511 if (pollfd[user].fd != -1)
512 {
513 struct epoll_event dummy;
514 epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd->unix_fd, &dummy );
515 }
516}
517
518static inline void main_loop_epoll(void)
519{
520 int i, ret, timeout;
521 struct epoll_event events[128];
522
523 assert( POLLIN == EPOLLIN );
524 assert( POLLOUT == EPOLLOUT );
525 assert( POLLERR == EPOLLERR );
526 assert( POLLHUP == EPOLLHUP );
527
528 if (epoll_fd == -1) return;
529
530 while (active_users)
531 {
532 timeout = get_next_timeout();
533
534 if (!active_users) break; /* last user removed by a timeout */
535 if (epoll_fd == -1) break; /* an error occurred with epoll */
536
537 ret = epoll_wait( epoll_fd, events, sizeof(events)/sizeof(events[0]), timeout );
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200538 set_current_time();
Alexandre Julliard2f407272006-08-03 19:56:55 +0200539
540 /* put the events into the pollfd array first, like poll does */
541 for (i = 0; i < ret; i++)
542 {
543 int user = events[i].data.u32;
544 pollfd[user].revents = events[i].events;
545 }
546
547 /* read events from the pollfd array, as set_fd_events may modify them */
548 for (i = 0; i < ret; i++)
549 {
550 int user = events[i].data.u32;
551 if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents );
552 }
553 }
554}
555
Alexandre Julliardc8278922006-08-04 22:11:00 +0200556#elif defined(HAVE_KQUEUE)
557
558static int kqueue_fd = -1;
559
560static inline void init_epoll(void)
561{
Alexandre Julliard8143d422007-06-15 12:41:43 +0200562#ifdef __APPLE__ /* kqueue support is broken in Mac OS < 10.5 */
563 int mib[2];
564 char release[32];
565 size_t len = sizeof(release);
566
567 mib[0] = CTL_KERN;
568 mib[1] = KERN_OSRELEASE;
569 if (sysctl( mib, 2, release, &len, NULL, 0 ) == -1) return;
570 if (atoi(release) < 9) return;
Alexandre Julliardc8278922006-08-04 22:11:00 +0200571#endif
Alexandre Julliard8143d422007-06-15 12:41:43 +0200572 kqueue_fd = kqueue();
Alexandre Julliardc8278922006-08-04 22:11:00 +0200573}
574
575static inline void set_fd_epoll_events( struct fd *fd, int user, int events )
576{
577 struct kevent ev[2];
578
579 if (kqueue_fd == -1) return;
580
581 EV_SET( &ev[0], fd->unix_fd, EVFILT_READ, 0, NOTE_LOWAT, 1, (void *)user );
582 EV_SET( &ev[1], fd->unix_fd, EVFILT_WRITE, 0, NOTE_LOWAT, 1, (void *)user );
583
584 if (events == -1) /* stop waiting on this fd completely */
585 {
586 if (pollfd[user].fd == -1) return; /* already removed */
587 ev[0].flags |= EV_DELETE;
588 ev[1].flags |= EV_DELETE;
589 }
590 else if (pollfd[user].fd == -1)
591 {
592 if (pollfd[user].events) return; /* stopped waiting on it, don't restart */
593 ev[0].flags |= EV_ADD | ((events & POLLIN) ? EV_ENABLE : EV_DISABLE);
594 ev[1].flags |= EV_ADD | ((events & POLLOUT) ? EV_ENABLE : EV_DISABLE);
595 }
596 else
597 {
598 if (pollfd[user].events == events) return; /* nothing to do */
599 ev[0].flags |= (events & POLLIN) ? EV_ENABLE : EV_DISABLE;
600 ev[1].flags |= (events & POLLOUT) ? EV_ENABLE : EV_DISABLE;
601 }
602
603 if (kevent( kqueue_fd, ev, 2, NULL, 0, NULL ) == -1)
604 {
605 if (errno == ENOMEM) /* not enough memory, give up on kqueue */
606 {
607 close( kqueue_fd );
608 kqueue_fd = -1;
609 }
610 else perror( "kevent" ); /* should not happen */
611 }
612}
613
614static inline void remove_epoll_user( struct fd *fd, int user )
615{
616 if (kqueue_fd == -1) return;
617
618 if (pollfd[user].fd != -1)
619 {
620 struct kevent ev[2];
621
622 EV_SET( &ev[0], fd->unix_fd, EVFILT_READ, EV_DELETE, 0, 0, 0 );
623 EV_SET( &ev[1], fd->unix_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0 );
624 kevent( kqueue_fd, ev, 2, NULL, 0, NULL );
625 }
626}
627
628static inline void main_loop_epoll(void)
629{
630 int i, ret, timeout;
631 struct kevent events[128];
632
633 if (kqueue_fd == -1) return;
634
635 while (active_users)
636 {
637 timeout = get_next_timeout();
638
639 if (!active_users) break; /* last user removed by a timeout */
640 if (kqueue_fd == -1) break; /* an error occurred with kqueue */
641
642 if (timeout != -1)
643 {
644 struct timespec ts;
645
646 ts.tv_sec = timeout / 1000;
647 ts.tv_nsec = (timeout % 1000) * 1000000;
648 ret = kevent( kqueue_fd, NULL, 0, events, sizeof(events)/sizeof(events[0]), &ts );
649 }
650 else ret = kevent( kqueue_fd, NULL, 0, events, sizeof(events)/sizeof(events[0]), NULL );
651
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200652 set_current_time();
Alexandre Julliard753c8702006-08-10 16:42:09 +0200653
Alexandre Julliardc8278922006-08-04 22:11:00 +0200654 /* put the events into the pollfd array first, like poll does */
655 for (i = 0; i < ret; i++)
656 {
657 long user = (long)events[i].udata;
658 pollfd[user].revents = 0;
659 }
660 for (i = 0; i < ret; i++)
661 {
662 long user = (long)events[i].udata;
663 if (events[i].filter == EVFILT_READ) pollfd[user].revents |= POLLIN;
664 else if (events[i].filter == EVFILT_WRITE) pollfd[user].revents |= POLLOUT;
665 if (events[i].flags & EV_EOF) pollfd[user].revents |= POLLHUP;
666 if (events[i].flags & EV_ERROR) pollfd[user].revents |= POLLERR;
667 }
668
669 /* read events from the pollfd array, as set_fd_events may modify them */
670 for (i = 0; i < ret; i++)
671 {
672 long user = (long)events[i].udata;
673 if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents );
674 pollfd[user].revents = 0;
675 }
676 }
677}
678
679#else /* HAVE_KQUEUE */
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000680
Alexandre Julliard2f407272006-08-03 19:56:55 +0200681static inline void init_epoll(void) { }
682static inline void set_fd_epoll_events( struct fd *fd, int user, int events ) { }
683static inline void remove_epoll_user( struct fd *fd, int user ) { }
684static inline void main_loop_epoll(void) { }
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000685
686#endif /* USE_EPOLL */
687
688
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000689/* add a user in the poll array and return its index, or -1 on failure */
690static int add_poll_user( struct fd *fd )
691{
692 int ret;
693 if (freelist)
694 {
695 ret = freelist - poll_users;
696 freelist = (struct fd **)poll_users[ret];
697 }
698 else
699 {
700 if (nb_users == allocated_users)
701 {
702 struct fd **newusers;
703 struct pollfd *newpoll;
704 int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
705 if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
706 if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) )))
707 {
708 if (allocated_users)
709 poll_users = newusers;
710 else
711 free( newusers );
712 return -1;
713 }
714 poll_users = newusers;
715 pollfd = newpoll;
Alexandre Julliard2f407272006-08-03 19:56:55 +0200716 if (!allocated_users) init_epoll();
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000717 allocated_users = new_count;
718 }
719 ret = nb_users++;
720 }
721 pollfd[ret].fd = -1;
722 pollfd[ret].events = 0;
723 pollfd[ret].revents = 0;
724 poll_users[ret] = fd;
725 active_users++;
726 return ret;
727}
728
729/* remove a user from the poll list */
730static void remove_poll_user( struct fd *fd, int user )
731{
732 assert( user >= 0 );
733 assert( poll_users[user] == fd );
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000734
Alexandre Julliard2f407272006-08-03 19:56:55 +0200735 remove_epoll_user( fd, user );
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000736 pollfd[user].fd = -1;
737 pollfd[user].events = 0;
738 pollfd[user].revents = 0;
739 poll_users[user] = (struct fd *)freelist;
740 freelist = &poll_users[user];
741 active_users--;
742}
743
Alexandre Julliard4949a712004-09-20 19:14:35 +0000744/* process pending timeouts and return the time until the next timeout, in milliseconds */
745static int get_next_timeout(void)
746{
747 if (!list_empty( &timeout_list ))
748 {
749 struct list expired_list, *ptr;
Alexandre Julliard4949a712004-09-20 19:14:35 +0000750
751 /* first remove all expired timers from the list */
752
753 list_init( &expired_list );
754 while ((ptr = list_head( &timeout_list )) != NULL)
755 {
756 struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
757
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200758 if (timeout->when <= current_time)
Alexandre Julliard4949a712004-09-20 19:14:35 +0000759 {
760 list_remove( &timeout->entry );
761 list_add_tail( &expired_list, &timeout->entry );
762 }
763 else break;
764 }
765
766 /* now call the callback for all the removed timers */
767
768 while ((ptr = list_head( &expired_list )) != NULL)
769 {
770 struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
771 list_remove( &timeout->entry );
772 timeout->callback( timeout->private );
773 free( timeout );
774 }
775
776 if ((ptr = list_head( &timeout_list )) != NULL)
777 {
778 struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200779 int diff = (timeout->when - current_time + 9999) / 10000;
Alexandre Julliard4949a712004-09-20 19:14:35 +0000780 if (diff < 0) diff = 0;
781 return diff;
782 }
783 }
784 return -1; /* no pending timeouts */
785}
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000786
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000787/* server main poll() loop */
788void main_loop(void)
789{
Alexandre Julliard4949a712004-09-20 19:14:35 +0000790 int i, ret, timeout;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000791
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200792 set_current_time();
793 server_start_time = current_time;
Alexandre Julliard753c8702006-08-10 16:42:09 +0200794
Alexandre Julliard2f407272006-08-03 19:56:55 +0200795 main_loop_epoll();
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000796 /* fall through to normal poll loop */
Alexandre Julliard969f57c2004-09-23 04:48:24 +0000797
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000798 while (active_users)
799 {
Alexandre Julliard4949a712004-09-20 19:14:35 +0000800 timeout = get_next_timeout();
Alexandre Julliard0a6af132004-09-07 23:28:14 +0000801
Alexandre Julliard4949a712004-09-20 19:14:35 +0000802 if (!active_users) break; /* last user removed by a timeout */
Alexandre Julliard0a6af132004-09-07 23:28:14 +0000803
Alexandre Julliard4949a712004-09-20 19:14:35 +0000804 ret = poll( pollfd, nb_users, timeout );
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200805 set_current_time();
Alexandre Julliard753c8702006-08-10 16:42:09 +0200806
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000807 if (ret > 0)
808 {
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000809 for (i = 0; i < nb_users; i++)
810 {
811 if (pollfd[i].revents)
812 {
813 fd_poll_event( poll_users[i], pollfd[i].revents );
814 if (!--ret) break;
815 }
816 }
817 }
818 }
819}
820
Alexandre Julliard580da242003-03-12 22:38:14 +0000821
822/****************************************************************/
Alexandre Julliardd4325152005-07-30 19:09:43 +0000823/* device functions */
824
825static struct list device_hash[DEVICE_HASH_SIZE];
826
Alexandre Julliard30b878b2006-11-01 13:28:05 +0100827static int is_device_removable( dev_t dev, int unix_fd )
828{
829#if defined(linux) && defined(HAVE_FSTATFS)
830 struct statfs stfs;
831
832 /* check for floppy disk */
833 if (major(dev) == FLOPPY_MAJOR) return 1;
834
835 if (fstatfs( unix_fd, &stfs ) == -1) return 0;
836 return (stfs.f_type == 0x9660 || /* iso9660 */
837 stfs.f_type == 0x9fa1 || /* supermount */
838 stfs.f_type == 0x15013346); /* udf */
839#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
840 struct statfs stfs;
841
842 if (fstatfs( unix_fd, &stfs ) == -1) return 0;
Alexandre Julliard8765a0d2007-08-29 12:02:13 +0200843 return (!strcmp("cd9660", stfs.f_fstypename) || !strcmp("udf", stfs.f_fstypename));
Alexandre Julliard30b878b2006-11-01 13:28:05 +0100844#elif defined(__NetBSD__)
845 struct statvfs stfs;
846
847 if (fstatvfs( unix_fd, &stfs ) == -1) return 0;
Alexandre Julliard8765a0d2007-08-29 12:02:13 +0200848 return (!strcmp("cd9660", stfs.f_fstypename) || !strcmp("udf", stfs.f_fstypename));
Alexandre Julliard30b878b2006-11-01 13:28:05 +0100849#elif defined(sun)
850# include <sys/dkio.h>
851# include <sys/vtoc.h>
852 struct dk_cinfo dkinf;
853 if (ioctl( unix_fd, DKIOCINFO, &dkinf ) == -1) return 0;
854 return (dkinf.dki_ctype == DKC_CDROM ||
855 dkinf.dki_ctype == DKC_NCRFLOPPY ||
856 dkinf.dki_ctype == DKC_SMSFLOPPY ||
857 dkinf.dki_ctype == DKC_INTEL82072 ||
858 dkinf.dki_ctype == DKC_INTEL82077);
859#else
860 return 0;
861#endif
862}
863
Alexandre Julliardd4325152005-07-30 19:09:43 +0000864/* retrieve the device object for a given fd, creating it if needed */
Alexandre Julliard30b878b2006-11-01 13:28:05 +0100865static struct device *get_device( dev_t dev, int unix_fd )
Alexandre Julliardd4325152005-07-30 19:09:43 +0000866{
867 struct device *device;
868 unsigned int i, hash = dev % DEVICE_HASH_SIZE;
869
870 if (device_hash[hash].next)
871 {
872 LIST_FOR_EACH_ENTRY( device, &device_hash[hash], struct device, entry )
873 if (device->dev == dev) return (struct device *)grab_object( device );
874 }
875 else list_init( &device_hash[hash] );
876
877 /* not found, create it */
Alexandre Julliardf8037bd2005-10-27 11:20:50 +0000878
Alexandre Julliard30b878b2006-11-01 13:28:05 +0100879 if (unix_fd == -1) return NULL;
Alexandre Julliardd4325152005-07-30 19:09:43 +0000880 if ((device = alloc_object( &device_ops )))
881 {
882 device->dev = dev;
Alexandre Julliard30b878b2006-11-01 13:28:05 +0100883 device->removable = is_device_removable( dev, unix_fd );
Alexandre Julliardd4325152005-07-30 19:09:43 +0000884 for (i = 0; i < INODE_HASH_SIZE; i++) list_init( &device->inode_hash[i] );
885 list_add_head( &device_hash[hash], &device->entry );
886 }
887 return device;
888}
889
890static void device_dump( struct object *obj, int verbose )
891{
892 struct device *device = (struct device *)obj;
893 fprintf( stderr, "Device dev=" );
894 DUMP_LONG_LONG( device->dev );
895 fprintf( stderr, "\n" );
896}
897
898static void device_destroy( struct object *obj )
899{
900 struct device *device = (struct device *)obj;
901 unsigned int i;
902
903 for (i = 0; i < INODE_HASH_SIZE; i++)
904 assert( list_empty(&device->inode_hash[i]) );
905
906 list_remove( &device->entry ); /* remove it from the hash table */
907}
908
909
910/****************************************************************/
Alexandre Julliard580da242003-03-12 22:38:14 +0000911/* inode functions */
912
Alexandre Julliardce613492003-03-18 05:04:33 +0000913/* close all pending file descriptors in the closed list */
Alexandre Julliard964815b2005-08-08 15:11:03 +0000914static void inode_close_pending( struct inode *inode, int keep_unlinks )
Alexandre Julliardce613492003-03-18 05:04:33 +0000915{
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000916 struct list *ptr = list_head( &inode->closed );
917
918 while (ptr)
Alexandre Julliardce613492003-03-18 05:04:33 +0000919 {
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000920 struct closed_fd *fd = LIST_ENTRY( ptr, struct closed_fd, entry );
921 struct list *next = list_next( &inode->closed, ptr );
922
Alexandre Julliardc1325422005-07-28 10:48:57 +0000923 if (fd->unix_fd != -1)
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000924 {
Alexandre Julliardc1325422005-07-28 10:48:57 +0000925 close( fd->unix_fd );
926 fd->unix_fd = -1;
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000927 }
Alexandre Julliard964815b2005-08-08 15:11:03 +0000928 if (!keep_unlinks || !fd->unlink[0]) /* get rid of it unless there's an unlink pending on that file */
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000929 {
930 list_remove( ptr );
931 free( fd );
932 }
933 ptr = next;
Alexandre Julliardce613492003-03-18 05:04:33 +0000934 }
935}
936
Alexandre Julliard580da242003-03-12 22:38:14 +0000937static void inode_dump( struct object *obj, int verbose )
938{
939 struct inode *inode = (struct inode *)obj;
Alexandre Julliardd4325152005-07-30 19:09:43 +0000940 fprintf( stderr, "Inode device=%p ino=", inode->device );
Alexandre Julliard580da242003-03-12 22:38:14 +0000941 DUMP_LONG_LONG( inode->ino );
942 fprintf( stderr, "\n" );
943}
944
945static void inode_destroy( struct object *obj )
946{
947 struct inode *inode = (struct inode *)obj;
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000948 struct list *ptr;
Alexandre Julliard580da242003-03-12 22:38:14 +0000949
Alexandre Julliardce613492003-03-18 05:04:33 +0000950 assert( list_empty(&inode->open) );
951 assert( list_empty(&inode->locks) );
Alexandre Julliard580da242003-03-12 22:38:14 +0000952
953 list_remove( &inode->entry );
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000954
955 while ((ptr = list_head( &inode->closed )))
956 {
957 struct closed_fd *fd = LIST_ENTRY( ptr, struct closed_fd, entry );
958 list_remove( ptr );
Alexandre Julliardc1325422005-07-28 10:48:57 +0000959 if (fd->unix_fd != -1) close( fd->unix_fd );
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000960 if (fd->unlink[0])
961 {
962 /* make sure it is still the same file */
963 struct stat st;
Alexandre Julliardd4325152005-07-30 19:09:43 +0000964 if (!stat( fd->unlink, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
Alexandre Julliard684b65c2004-04-16 04:31:35 +0000965 {
966 if (S_ISDIR(st.st_mode)) rmdir( fd->unlink );
967 else unlink( fd->unlink );
968 }
Alexandre Julliard9ff78722004-04-02 19:50:49 +0000969 }
970 free( fd );
971 }
Alexandre Julliardd4325152005-07-30 19:09:43 +0000972 release_object( inode->device );
Alexandre Julliard580da242003-03-12 22:38:14 +0000973}
974
975/* retrieve the inode object for a given fd, creating it if needed */
Alexandre Julliard30b878b2006-11-01 13:28:05 +0100976static struct inode *get_inode( dev_t dev, ino_t ino, int unix_fd )
Alexandre Julliard580da242003-03-12 22:38:14 +0000977{
Alexandre Julliardd4325152005-07-30 19:09:43 +0000978 struct device *device;
Alexandre Julliard580da242003-03-12 22:38:14 +0000979 struct inode *inode;
Alexandre Julliardd4325152005-07-30 19:09:43 +0000980 unsigned int hash = ino % INODE_HASH_SIZE;
Alexandre Julliard580da242003-03-12 22:38:14 +0000981
Alexandre Julliard30b878b2006-11-01 13:28:05 +0100982 if (!(device = get_device( dev, unix_fd ))) return NULL;
Alexandre Julliardd4325152005-07-30 19:09:43 +0000983
984 LIST_FOR_EACH_ENTRY( inode, &device->inode_hash[hash], struct inode, entry )
Alexandre Julliard580da242003-03-12 22:38:14 +0000985 {
Alexandre Julliardd4325152005-07-30 19:09:43 +0000986 if (inode->ino == ino)
Alexandre Julliard580da242003-03-12 22:38:14 +0000987 {
Alexandre Julliardd4325152005-07-30 19:09:43 +0000988 release_object( device );
989 return (struct inode *)grab_object( inode );
Alexandre Julliard580da242003-03-12 22:38:14 +0000990 }
991 }
Alexandre Julliard580da242003-03-12 22:38:14 +0000992
993 /* not found, create it */
994 if ((inode = alloc_object( &inode_ops )))
995 {
Alexandre Julliardd4325152005-07-30 19:09:43 +0000996 inode->device = device;
Alexandre Julliard580da242003-03-12 22:38:14 +0000997 inode->ino = ino;
Alexandre Julliard580da242003-03-12 22:38:14 +0000998 list_init( &inode->open );
Alexandre Julliardce613492003-03-18 05:04:33 +0000999 list_init( &inode->locks );
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001000 list_init( &inode->closed );
Alexandre Julliardd4325152005-07-30 19:09:43 +00001001 list_add_head( &device->inode_hash[hash], &inode->entry );
Alexandre Julliard580da242003-03-12 22:38:14 +00001002 }
Alexandre Julliardd4325152005-07-30 19:09:43 +00001003 else release_object( device );
1004
Alexandre Julliard580da242003-03-12 22:38:14 +00001005 return inode;
1006}
1007
Alexandre Julliardc1325422005-07-28 10:48:57 +00001008/* add fd to the inode list of file descriptors to close */
Alexandre Julliard580da242003-03-12 22:38:14 +00001009static void inode_add_closed_fd( struct inode *inode, struct closed_fd *fd )
1010{
Alexandre Julliardce613492003-03-18 05:04:33 +00001011 if (!list_empty( &inode->locks ))
1012 {
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001013 list_add_head( &inode->closed, &fd->entry );
Alexandre Julliardce613492003-03-18 05:04:33 +00001014 }
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001015 else if (fd->unlink[0]) /* close the fd but keep the structure around for unlink */
1016 {
Alexandre Julliardc1325422005-07-28 10:48:57 +00001017 if (fd->unix_fd != -1) close( fd->unix_fd );
1018 fd->unix_fd = -1;
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001019 list_add_head( &inode->closed, &fd->entry );
1020 }
1021 else /* no locks on this inode and no unlink, get rid of the fd */
Alexandre Julliardce613492003-03-18 05:04:33 +00001022 {
Alexandre Julliardc1325422005-07-28 10:48:57 +00001023 if (fd->unix_fd != -1) close( fd->unix_fd );
Alexandre Julliardce613492003-03-18 05:04:33 +00001024 free( fd );
1025 }
1026}
1027
1028
1029/****************************************************************/
1030/* file lock functions */
1031
1032static void file_lock_dump( struct object *obj, int verbose )
1033{
1034 struct file_lock *lock = (struct file_lock *)obj;
1035 fprintf( stderr, "Lock %s fd=%p proc=%p start=",
1036 lock->shared ? "shared" : "excl", lock->fd, lock->process );
1037 DUMP_LONG_LONG( lock->start );
1038 fprintf( stderr, " end=" );
1039 DUMP_LONG_LONG( lock->end );
1040 fprintf( stderr, "\n" );
1041}
1042
1043static int file_lock_signaled( struct object *obj, struct thread *thread )
1044{
1045 struct file_lock *lock = (struct file_lock *)obj;
1046 /* lock is signaled if it has lost its owner */
1047 return !lock->process;
1048}
1049
1050/* set (or remove) a Unix lock if possible for the given range */
Alexandre Julliardb23aa942003-07-03 18:12:02 +00001051static int set_unix_lock( struct fd *fd, file_pos_t start, file_pos_t end, int type )
Alexandre Julliardce613492003-03-18 05:04:33 +00001052{
1053 struct flock fl;
1054
Alexandre Julliardb23aa942003-07-03 18:12:02 +00001055 if (!fd->fs_locks) return 1; /* no fs locks possible for this fd */
Alexandre Julliardce613492003-03-18 05:04:33 +00001056 for (;;)
1057 {
1058 if (start == end) return 1; /* can't set zero-byte lock */
1059 if (start > max_unix_offset) return 1; /* ignore it */
1060 fl.l_type = type;
1061 fl.l_whence = SEEK_SET;
1062 fl.l_start = start;
1063 if (!end || end > max_unix_offset) fl.l_len = 0;
1064 else fl.l_len = end - start;
1065 if (fcntl( fd->unix_fd, F_SETLK, &fl ) != -1) return 1;
1066
1067 switch(errno)
1068 {
Alexandre Julliardb23aa942003-07-03 18:12:02 +00001069 case EACCES:
1070 /* check whether locks work at all on this file system */
1071 if (fcntl( fd->unix_fd, F_GETLK, &fl ) != -1)
1072 {
1073 set_error( STATUS_FILE_LOCK_CONFLICT );
1074 return 0;
1075 }
1076 /* fall through */
Alexandre Julliardb9327232003-05-11 02:45:33 +00001077 case EIO:
1078 case ENOLCK:
1079 /* no locking on this fs, just ignore it */
Alexandre Julliardb23aa942003-07-03 18:12:02 +00001080 fd->fs_locks = 0;
Alexandre Julliardb9327232003-05-11 02:45:33 +00001081 return 1;
Alexandre Julliardce613492003-03-18 05:04:33 +00001082 case EAGAIN:
1083 set_error( STATUS_FILE_LOCK_CONFLICT );
1084 return 0;
Alexandre Julliardd71ba932003-03-21 21:31:35 +00001085 case EBADF:
1086 /* this can happen if we try to set a write lock on a read-only file */
1087 /* we just ignore that error */
1088 if (fl.l_type == F_WRLCK) return 1;
1089 set_error( STATUS_ACCESS_DENIED );
1090 return 0;
Wim Lewis99a01c02004-01-02 20:11:35 +00001091#ifdef EOVERFLOW
Alexandre Julliardce613492003-03-18 05:04:33 +00001092 case EOVERFLOW:
Wim Lewis99a01c02004-01-02 20:11:35 +00001093#endif
Alexandre Julliardb9327232003-05-11 02:45:33 +00001094 case EINVAL:
Alexandre Julliardce613492003-03-18 05:04:33 +00001095 /* this can happen if off_t is 64-bit but the kernel only supports 32-bit */
1096 /* in that case we shrink the limit and retry */
1097 if (max_unix_offset > INT_MAX)
1098 {
1099 max_unix_offset = INT_MAX;
1100 break; /* retry */
1101 }
1102 /* fall through */
1103 default:
1104 file_set_error();
1105 return 0;
1106 }
1107 }
1108}
1109
1110/* check if interval [start;end) overlaps the lock */
Andrew Talbotb1788c82007-03-17 10:52:14 +00001111static inline int lock_overlaps( struct file_lock *lock, file_pos_t start, file_pos_t end )
Alexandre Julliardce613492003-03-18 05:04:33 +00001112{
1113 if (lock->end && start >= lock->end) return 0;
1114 if (end && lock->start >= end) return 0;
1115 return 1;
1116}
1117
1118/* remove Unix locks for all bytes in the specified area that are no longer locked */
Alexandre Julliardb23aa942003-07-03 18:12:02 +00001119static void remove_unix_locks( struct fd *fd, file_pos_t start, file_pos_t end )
Alexandre Julliardce613492003-03-18 05:04:33 +00001120{
1121 struct hole
1122 {
1123 struct hole *next;
1124 struct hole *prev;
1125 file_pos_t start;
1126 file_pos_t end;
1127 } *first, *cur, *next, *buffer;
1128
1129 struct list *ptr;
1130 int count = 0;
1131
1132 if (!fd->inode) return;
Alexandre Julliardb23aa942003-07-03 18:12:02 +00001133 if (!fd->fs_locks) return;
Alexandre Julliardce613492003-03-18 05:04:33 +00001134 if (start == end || start > max_unix_offset) return;
1135 if (!end || end > max_unix_offset) end = max_unix_offset + 1;
1136
1137 /* count the number of locks overlapping the specified area */
1138
1139 LIST_FOR_EACH( ptr, &fd->inode->locks )
1140 {
1141 struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, inode_entry );
1142 if (lock->start == lock->end) continue;
1143 if (lock_overlaps( lock, start, end )) count++;
1144 }
1145
1146 if (!count) /* no locks at all, we can unlock everything */
1147 {
1148 set_unix_lock( fd, start, end, F_UNLCK );
1149 return;
1150 }
1151
1152 /* allocate space for the list of holes */
1153 /* max. number of holes is number of locks + 1 */
1154
1155 if (!(buffer = malloc( sizeof(*buffer) * (count+1) ))) return;
1156 first = buffer;
1157 first->next = NULL;
1158 first->prev = NULL;
1159 first->start = start;
1160 first->end = end;
1161 next = first + 1;
1162
1163 /* build a sorted list of unlocked holes in the specified area */
1164
1165 LIST_FOR_EACH( ptr, &fd->inode->locks )
1166 {
1167 struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, inode_entry );
1168 if (lock->start == lock->end) continue;
1169 if (!lock_overlaps( lock, start, end )) continue;
1170
1171 /* go through all the holes touched by this lock */
1172 for (cur = first; cur; cur = cur->next)
1173 {
1174 if (cur->end <= lock->start) continue; /* hole is before start of lock */
1175 if (lock->end && cur->start >= lock->end) break; /* hole is after end of lock */
1176
1177 /* now we know that lock is overlapping hole */
1178
1179 if (cur->start >= lock->start) /* lock starts before hole, shrink from start */
1180 {
1181 cur->start = lock->end;
1182 if (cur->start && cur->start < cur->end) break; /* done with this lock */
1183 /* now hole is empty, remove it */
1184 if (cur->next) cur->next->prev = cur->prev;
1185 if (cur->prev) cur->prev->next = cur->next;
1186 else if (!(first = cur->next)) goto done; /* no more holes at all */
1187 }
1188 else if (!lock->end || cur->end <= lock->end) /* lock larger than hole, shrink from end */
1189 {
1190 cur->end = lock->start;
1191 assert( cur->start < cur->end );
1192 }
1193 else /* lock is in the middle of hole, split hole in two */
1194 {
1195 next->prev = cur;
1196 next->next = cur->next;
1197 cur->next = next;
1198 next->start = lock->end;
1199 next->end = cur->end;
1200 cur->end = lock->start;
1201 assert( next->start < next->end );
1202 assert( cur->end < next->start );
1203 next++;
1204 break; /* done with this lock */
1205 }
1206 }
1207 }
1208
1209 /* clear Unix locks for all the holes */
1210
1211 for (cur = first; cur; cur = cur->next)
1212 set_unix_lock( fd, cur->start, cur->end, F_UNLCK );
1213
1214 done:
1215 free( buffer );
1216}
1217
1218/* create a new lock on a fd */
1219static struct file_lock *add_lock( struct fd *fd, int shared, file_pos_t start, file_pos_t end )
1220{
1221 struct file_lock *lock;
1222
Alexandre Julliardce613492003-03-18 05:04:33 +00001223 if (!(lock = alloc_object( &file_lock_ops ))) return NULL;
1224 lock->shared = shared;
1225 lock->start = start;
1226 lock->end = end;
1227 lock->fd = fd;
1228 lock->process = current->process;
1229
1230 /* now try to set a Unix lock */
1231 if (!set_unix_lock( lock->fd, lock->start, lock->end, lock->shared ? F_RDLCK : F_WRLCK ))
1232 {
1233 release_object( lock );
1234 return NULL;
1235 }
1236 list_add_head( &fd->locks, &lock->fd_entry );
1237 list_add_head( &fd->inode->locks, &lock->inode_entry );
1238 list_add_head( &lock->process->locks, &lock->proc_entry );
1239 return lock;
1240}
1241
1242/* remove an existing lock */
1243static void remove_lock( struct file_lock *lock, int remove_unix )
1244{
1245 struct inode *inode = lock->fd->inode;
1246
1247 list_remove( &lock->fd_entry );
1248 list_remove( &lock->inode_entry );
1249 list_remove( &lock->proc_entry );
1250 if (remove_unix) remove_unix_locks( lock->fd, lock->start, lock->end );
Alexandre Julliard964815b2005-08-08 15:11:03 +00001251 if (list_empty( &inode->locks )) inode_close_pending( inode, 1 );
Alexandre Julliardce613492003-03-18 05:04:33 +00001252 lock->process = NULL;
1253 wake_up( &lock->obj, 0 );
1254 release_object( lock );
1255}
1256
1257/* remove all locks owned by a given process */
1258void remove_process_locks( struct process *process )
1259{
1260 struct list *ptr;
1261
1262 while ((ptr = list_head( &process->locks )))
1263 {
1264 struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, proc_entry );
1265 remove_lock( lock, 1 ); /* this removes it from the list */
1266 }
1267}
1268
1269/* remove all locks on a given fd */
1270static void remove_fd_locks( struct fd *fd )
1271{
1272 file_pos_t start = FILE_POS_T_MAX, end = 0;
1273 struct list *ptr;
1274
1275 while ((ptr = list_head( &fd->locks )))
1276 {
1277 struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, fd_entry );
1278 if (lock->start < start) start = lock->start;
1279 if (!lock->end || lock->end > end) end = lock->end - 1;
1280 remove_lock( lock, 0 );
1281 }
1282 if (start < end) remove_unix_locks( fd, start, end + 1 );
1283}
1284
1285/* add a lock on an fd */
1286/* returns handle to wait on */
1287obj_handle_t lock_fd( struct fd *fd, file_pos_t start, file_pos_t count, int shared, int wait )
1288{
1289 struct list *ptr;
1290 file_pos_t end = start + count;
1291
Alexandre Julliard60901b72007-06-20 13:14:55 +02001292 if (!fd->inode) /* not a regular file */
1293 {
1294 set_error( STATUS_INVALID_DEVICE_REQUEST );
1295 return 0;
1296 }
1297
Alexandre Julliardce613492003-03-18 05:04:33 +00001298 /* don't allow wrapping locks */
1299 if (end && end < start)
1300 {
1301 set_error( STATUS_INVALID_PARAMETER );
1302 return 0;
1303 }
1304
1305 /* check if another lock on that file overlaps the area */
1306 LIST_FOR_EACH( ptr, &fd->inode->locks )
1307 {
1308 struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, inode_entry );
1309 if (!lock_overlaps( lock, start, end )) continue;
1310 if (lock->shared && shared) continue;
1311 /* found one */
1312 if (!wait)
1313 {
1314 set_error( STATUS_FILE_LOCK_CONFLICT );
1315 return 0;
1316 }
1317 set_error( STATUS_PENDING );
1318 return alloc_handle( current->process, lock, SYNCHRONIZE, 0 );
1319 }
1320
1321 /* not found, add it */
1322 if (add_lock( fd, shared, start, end )) return 0;
1323 if (get_error() == STATUS_FILE_LOCK_CONFLICT)
1324 {
1325 /* Unix lock conflict -> tell client to wait and retry */
1326 if (wait) set_error( STATUS_PENDING );
1327 }
1328 return 0;
1329}
1330
1331/* remove a lock on an fd */
1332void unlock_fd( struct fd *fd, file_pos_t start, file_pos_t count )
1333{
1334 struct list *ptr;
1335 file_pos_t end = start + count;
1336
1337 /* find an existing lock with the exact same parameters */
1338 LIST_FOR_EACH( ptr, &fd->locks )
1339 {
1340 struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, fd_entry );
1341 if ((lock->start == start) && (lock->end == end))
1342 {
1343 remove_lock( lock, 1 );
1344 return;
1345 }
1346 }
1347 set_error( STATUS_FILE_LOCK_CONFLICT );
Alexandre Julliard580da242003-03-12 22:38:14 +00001348}
1349
1350
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001351/****************************************************************/
1352/* file descriptor functions */
1353
Alexandre Julliard863637b2003-01-30 00:26:44 +00001354static void fd_dump( struct object *obj, int verbose )
1355{
1356 struct fd *fd = (struct fd *)obj;
Alexandre Julliardf85437c2007-04-10 22:25:07 +02001357 fprintf( stderr, "Fd unix_fd=%d user=%p options=%08x", fd->unix_fd, fd->user, fd->options );
Alexandre Julliarde432d542005-02-03 10:45:18 +00001358 if (fd->inode) fprintf( stderr, " inode=%p unlink='%s'", fd->inode, fd->closed->unlink );
1359 fprintf( stderr, "\n" );
Alexandre Julliard863637b2003-01-30 00:26:44 +00001360}
1361
1362static void fd_destroy( struct object *obj )
1363{
Alexandre Julliard863637b2003-01-30 00:26:44 +00001364 struct fd *fd = (struct fd *)obj;
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001365
Alexandre Julliardb2cba952007-04-03 19:36:07 +02001366 free_async_queue( fd->read_q );
1367 free_async_queue( fd->write_q );
1368 free_async_queue( fd->wait_q );
Robert Shearmand6a4e342005-06-07 20:09:01 +00001369
Andrey Turkind1a81552007-09-28 00:03:39 +04001370 if (fd->completion) release_object( fd->completion );
Alexandre Julliardce613492003-03-18 05:04:33 +00001371 remove_fd_locks( fd );
Henri Verbeet27705d52009-11-12 15:10:12 +01001372 free( fd->unix_name );
Alexandre Julliard580da242003-03-12 22:38:14 +00001373 list_remove( &fd->inode_entry );
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001374 if (fd->poll_index != -1) remove_poll_user( fd, fd->poll_index );
Alexandre Julliard580da242003-03-12 22:38:14 +00001375 if (fd->inode)
1376 {
1377 inode_add_closed_fd( fd->inode, fd->closed );
1378 release_object( fd->inode );
1379 }
1380 else /* no inode, close it right away */
1381 {
1382 if (fd->unix_fd != -1) close( fd->unix_fd );
1383 }
Alexandre Julliard863637b2003-01-30 00:26:44 +00001384}
1385
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001386/* set the events that select waits for on this fd */
1387void set_fd_events( struct fd *fd, int events )
Alexandre Julliard863637b2003-01-30 00:26:44 +00001388{
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001389 int user = fd->poll_index;
1390 assert( poll_users[user] == fd );
Alexandre Julliard969f57c2004-09-23 04:48:24 +00001391
1392 set_fd_epoll_events( fd, user, events );
1393
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001394 if (events == -1) /* stop waiting on this fd completely */
1395 {
1396 pollfd[user].fd = -1;
1397 pollfd[user].events = POLLERR;
1398 pollfd[user].revents = 0;
1399 }
1400 else if (pollfd[user].fd != -1 || !pollfd[user].events)
1401 {
1402 pollfd[user].fd = fd->unix_fd;
1403 pollfd[user].events = events;
1404 }
1405}
Alexandre Julliard863637b2003-01-30 00:26:44 +00001406
Alexandre Julliard964815b2005-08-08 15:11:03 +00001407/* prepare an fd for unmounting its corresponding device */
1408static inline void unmount_fd( struct fd *fd )
1409{
1410 assert( fd->inode );
1411
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001412 async_wake_up( fd->read_q, STATUS_VOLUME_DISMOUNTED );
1413 async_wake_up( fd->write_q, STATUS_VOLUME_DISMOUNTED );
Alexandre Julliard964815b2005-08-08 15:11:03 +00001414
1415 if (fd->poll_index != -1) set_fd_events( fd, -1 );
1416
1417 if (fd->unix_fd != -1) close( fd->unix_fd );
1418
1419 fd->unix_fd = -1;
Alexandre Julliardf3fbae42007-04-18 16:05:59 +02001420 fd->no_fd_status = STATUS_VOLUME_DISMOUNTED;
Alexandre Julliard964815b2005-08-08 15:11:03 +00001421 fd->closed->unix_fd = -1;
1422 fd->closed->unlink[0] = 0;
1423
1424 /* stop using Unix locks on this fd (existing locks have been removed by close) */
1425 fd->fs_locks = 0;
1426}
1427
Alexandre Julliard580da242003-03-12 22:38:14 +00001428/* allocate an fd object, without setting the unix fd yet */
Mike McCormack9a7124e2006-01-24 13:30:55 +01001429static struct fd *alloc_fd_object(void)
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001430{
1431 struct fd *fd = alloc_object( &fd_ops );
1432
Alexandre Julliard580da242003-03-12 22:38:14 +00001433 if (!fd) return NULL;
1434
Mike McCormack9a7124e2006-01-24 13:30:55 +01001435 fd->fd_ops = NULL;
1436 fd->user = NULL;
Alexandre Julliard580da242003-03-12 22:38:14 +00001437 fd->inode = NULL;
1438 fd->closed = NULL;
Alexandre Julliard74bd1e42004-03-27 20:48:42 +00001439 fd->access = 0;
Alexandre Julliardf85437c2007-04-10 22:25:07 +02001440 fd->options = 0;
Alexandre Julliard74bd1e42004-03-27 20:48:42 +00001441 fd->sharing = 0;
Alexandre Julliard580da242003-03-12 22:38:14 +00001442 fd->unix_fd = -1;
Henri Verbeet27705d52009-11-12 15:10:12 +01001443 fd->unix_name = NULL;
Alexandre Julliardba896e72007-04-04 19:39:29 +02001444 fd->signaled = 1;
Alexandre Julliardb23aa942003-07-03 18:12:02 +00001445 fd->fs_locks = 1;
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001446 fd->poll_index = -1;
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001447 fd->read_q = NULL;
1448 fd->write_q = NULL;
1449 fd->wait_q = NULL;
Andrey Turkind1a81552007-09-28 00:03:39 +04001450 fd->completion = NULL;
Alexandre Julliard580da242003-03-12 22:38:14 +00001451 list_init( &fd->inode_entry );
Alexandre Julliardce613492003-03-18 05:04:33 +00001452 list_init( &fd->locks );
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001453
Alexandre Julliard580da242003-03-12 22:38:14 +00001454 if ((fd->poll_index = add_poll_user( fd )) == -1)
Alexandre Julliard863637b2003-01-30 00:26:44 +00001455 {
1456 release_object( fd );
1457 return NULL;
1458 }
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001459 return fd;
Alexandre Julliard863637b2003-01-30 00:26:44 +00001460}
1461
Alexandre Julliard67505c02005-12-12 14:27:45 +01001462/* allocate a pseudo fd object, for objects that need to behave like files but don't have a unix fd */
Alexandre Julliard017480d2007-05-03 16:07:30 +02001463struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *user, unsigned int options )
Alexandre Julliard67505c02005-12-12 14:27:45 +01001464{
1465 struct fd *fd = alloc_object( &fd_ops );
1466
1467 if (!fd) return NULL;
1468
1469 fd->fd_ops = fd_user_ops;
1470 fd->user = user;
1471 fd->inode = NULL;
1472 fd->closed = NULL;
1473 fd->access = 0;
Alexandre Julliard017480d2007-05-03 16:07:30 +02001474 fd->options = options;
Alexandre Julliard67505c02005-12-12 14:27:45 +01001475 fd->sharing = 0;
Henri Verbeet27705d52009-11-12 15:10:12 +01001476 fd->unix_name = NULL;
Alexandre Julliard67505c02005-12-12 14:27:45 +01001477 fd->unix_fd = -1;
Alexandre Julliardba896e72007-04-04 19:39:29 +02001478 fd->signaled = 0;
Alexandre Julliard67505c02005-12-12 14:27:45 +01001479 fd->fs_locks = 0;
Alexandre Julliard67505c02005-12-12 14:27:45 +01001480 fd->poll_index = -1;
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001481 fd->read_q = NULL;
1482 fd->write_q = NULL;
1483 fd->wait_q = NULL;
Andrey Turkind1a81552007-09-28 00:03:39 +04001484 fd->completion = NULL;
Alexandre Julliardf3fbae42007-04-18 16:05:59 +02001485 fd->no_fd_status = STATUS_BAD_DEVICE_TYPE;
Alexandre Julliard67505c02005-12-12 14:27:45 +01001486 list_init( &fd->inode_entry );
1487 list_init( &fd->locks );
Alexandre Julliard67505c02005-12-12 14:27:45 +01001488 return fd;
1489}
1490
Alexandre Julliardf3fbae42007-04-18 16:05:59 +02001491/* set the status to return when the fd has no associated unix fd */
1492void set_no_fd_status( struct fd *fd, unsigned int status )
1493{
1494 fd->no_fd_status = status;
1495}
1496
Alexandre Julliard74bd1e42004-03-27 20:48:42 +00001497/* check if the desired access is possible without violating */
1498/* the sharing mode of other opens of the same file */
1499static int check_sharing( struct fd *fd, unsigned int access, unsigned int sharing )
1500{
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001501 unsigned int existing_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
Alexandre Julliard74bd1e42004-03-27 20:48:42 +00001502 unsigned int existing_access = 0;
1503 struct list *ptr;
1504
1505 /* if access mode is 0, sharing mode is ignored */
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001506 if (!access) sharing = existing_sharing;
Alexandre Julliard74bd1e42004-03-27 20:48:42 +00001507 fd->access = access;
1508 fd->sharing = sharing;
1509
1510 LIST_FOR_EACH( ptr, &fd->inode->open )
1511 {
1512 struct fd *fd_ptr = LIST_ENTRY( ptr, struct fd, inode_entry );
1513 if (fd_ptr != fd)
1514 {
1515 existing_sharing &= fd_ptr->sharing;
1516 existing_access |= fd_ptr->access;
1517 }
1518 }
1519
Alexandre Julliarda510a7e2005-12-12 16:46:17 +01001520 if ((access & FILE_UNIX_READ_ACCESS) && !(existing_sharing & FILE_SHARE_READ)) return 0;
1521 if ((access & FILE_UNIX_WRITE_ACCESS) && !(existing_sharing & FILE_SHARE_WRITE)) return 0;
Alexandre Julliard8b0feb22006-01-27 15:50:38 +01001522 if ((access & DELETE) && !(existing_sharing & FILE_SHARE_DELETE)) return 0;
Alexandre Julliarda510a7e2005-12-12 16:46:17 +01001523 if ((existing_access & FILE_UNIX_READ_ACCESS) && !(sharing & FILE_SHARE_READ)) return 0;
1524 if ((existing_access & FILE_UNIX_WRITE_ACCESS) && !(sharing & FILE_SHARE_WRITE)) return 0;
Alexandre Julliard8b0feb22006-01-27 15:50:38 +01001525 if ((existing_access & DELETE) && !(sharing & FILE_SHARE_DELETE)) return 0;
Alexandre Julliard74bd1e42004-03-27 20:48:42 +00001526 return 1;
1527}
1528
Mike McCormack9a7124e2006-01-24 13:30:55 +01001529/* sets the user of an fd that previously had no user */
1530void set_fd_user( struct fd *fd, const struct fd_ops *user_ops, struct object *user )
1531{
1532 assert( fd->fd_ops == NULL );
1533 fd->fd_ops = user_ops;
1534 fd->user = user;
1535}
1536
1537/* open() wrapper that returns a struct fd with no fd user set */
1538struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int access,
1539 unsigned int sharing, unsigned int options )
Alexandre Julliard580da242003-03-12 22:38:14 +00001540{
1541 struct stat st;
1542 struct closed_fd *closed_fd;
Mike McCormack9a7124e2006-01-24 13:30:55 +01001543 struct fd *fd;
Alexandre Julliard684b65c2004-04-16 04:31:35 +00001544 const char *unlink_name = "";
Alexandre Julliard471782a2006-01-25 15:06:48 +01001545 int rw_mode;
Alexandre Julliard580da242003-03-12 22:38:14 +00001546
Alexandre Julliard8b0feb22006-01-27 15:50:38 +01001547 if ((options & FILE_DELETE_ON_CLOSE) && !(access & DELETE))
1548 {
1549 set_error( STATUS_INVALID_PARAMETER );
1550 return NULL;
1551 }
1552
Mike McCormack9a7124e2006-01-24 13:30:55 +01001553 if (!(fd = alloc_fd_object())) return NULL;
Alexandre Julliard580da242003-03-12 22:38:14 +00001554
Alexandre Julliardf85437c2007-04-10 22:25:07 +02001555 fd->options = options;
Alexandre Julliard684b65c2004-04-16 04:31:35 +00001556 if (options & FILE_DELETE_ON_CLOSE) unlink_name = name;
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001557 if (!(closed_fd = mem_alloc( sizeof(*closed_fd) + strlen(unlink_name) )))
Alexandre Julliard580da242003-03-12 22:38:14 +00001558 {
1559 release_object( fd );
1560 return NULL;
1561 }
Alexandre Julliard471782a2006-01-25 15:06:48 +01001562
Alexandre Julliardad9b7992004-04-27 02:27:09 +00001563 /* create the directory if needed */
1564 if ((options & FILE_DIRECTORY_FILE) && (flags & O_CREAT))
1565 {
1566 if (mkdir( name, 0777 ) == -1)
1567 {
1568 if (errno != EEXIST || (flags & O_EXCL))
1569 {
1570 file_set_error();
Mike McCormack9a7124e2006-01-24 13:30:55 +01001571 goto error;
Alexandre Julliardad9b7992004-04-27 02:27:09 +00001572 }
1573 }
1574 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
1575 }
Alexandre Julliard471782a2006-01-25 15:06:48 +01001576
1577 if ((access & FILE_UNIX_WRITE_ACCESS) && !(options & FILE_DIRECTORY_FILE))
Alexandre Julliard580da242003-03-12 22:38:14 +00001578 {
Alexandre Julliard471782a2006-01-25 15:06:48 +01001579 if (access & FILE_UNIX_READ_ACCESS) rw_mode = O_RDWR;
1580 else rw_mode = O_WRONLY;
Alexandre Julliard580da242003-03-12 22:38:14 +00001581 }
Alexandre Julliard471782a2006-01-25 15:06:48 +01001582 else rw_mode = O_RDONLY;
1583
Henri Verbeet27705d52009-11-12 15:10:12 +01001584 if (!(fd->unix_name = mem_alloc( strlen(name) + 1 ))) goto error;
1585 strcpy( fd->unix_name, name );
1586
Alexandre Julliard471782a2006-01-25 15:06:48 +01001587 if ((fd->unix_fd = open( name, rw_mode | (flags & ~O_TRUNC), *mode )) == -1)
1588 {
1589 /* if we tried to open a directory for write access, retry read-only */
1590 if (errno != EISDIR ||
1591 !(access & FILE_UNIX_WRITE_ACCESS) ||
Jeff Zaroykoafce6152008-12-03 17:30:54 +11001592 (fd->unix_fd = open( name, O_RDONLY | (flags & ~(O_TRUNC | O_CREAT | O_EXCL)), *mode )) == -1)
Alexandre Julliard471782a2006-01-25 15:06:48 +01001593 {
1594 file_set_error();
1595 goto error;
1596 }
1597 }
1598
Alexandre Julliardc1325422005-07-28 10:48:57 +00001599 closed_fd->unix_fd = fd->unix_fd;
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001600 closed_fd->unlink[0] = 0;
Alexandre Julliard580da242003-03-12 22:38:14 +00001601 fstat( fd->unix_fd, &st );
1602 *mode = st.st_mode;
1603
Alexandre Julliard684b65c2004-04-16 04:31:35 +00001604 /* only bother with an inode for normal files and directories */
1605 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
Alexandre Julliard580da242003-03-12 22:38:14 +00001606 {
Alexandre Julliard30b878b2006-11-01 13:28:05 +01001607 struct inode *inode = get_inode( st.st_dev, st.st_ino, fd->unix_fd );
Alexandre Julliard580da242003-03-12 22:38:14 +00001608
1609 if (!inode)
1610 {
1611 /* we can close the fd because there are no others open on the same file,
1612 * otherwise we wouldn't have failed to allocate a new inode
1613 */
Alexandre Julliard684b65c2004-04-16 04:31:35 +00001614 goto error;
Alexandre Julliard580da242003-03-12 22:38:14 +00001615 }
1616 fd->inode = inode;
1617 fd->closed = closed_fd;
1618 list_add_head( &inode->open, &fd->inode_entry );
Alexandre Julliard17c775f2004-09-09 00:28:36 +00001619
1620 /* check directory options */
1621 if ((options & FILE_DIRECTORY_FILE) && !S_ISDIR(st.st_mode))
1622 {
1623 release_object( fd );
1624 set_error( STATUS_NOT_A_DIRECTORY );
1625 return NULL;
1626 }
1627 if ((options & FILE_NON_DIRECTORY_FILE) && S_ISDIR(st.st_mode))
1628 {
1629 release_object( fd );
1630 set_error( STATUS_FILE_IS_A_DIRECTORY );
1631 return NULL;
1632 }
Alexandre Julliard74bd1e42004-03-27 20:48:42 +00001633 if (!check_sharing( fd, access, sharing ))
1634 {
1635 release_object( fd );
1636 set_error( STATUS_SHARING_VIOLATION );
1637 return NULL;
1638 }
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001639 strcpy( closed_fd->unlink, unlink_name );
Alexandre Julliard60287d02004-05-22 03:15:04 +00001640 if (flags & O_TRUNC) ftruncate( fd->unix_fd, 0 );
Alexandre Julliard580da242003-03-12 22:38:14 +00001641 }
Alexandre Julliard17c775f2004-09-09 00:28:36 +00001642 else /* special file */
Alexandre Julliard580da242003-03-12 22:38:14 +00001643 {
Alexandre Julliard17c775f2004-09-09 00:28:36 +00001644 if (options & FILE_DIRECTORY_FILE)
1645 {
1646 set_error( STATUS_NOT_A_DIRECTORY );
1647 goto error;
1648 }
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001649 if (unlink_name[0]) /* we can't unlink special files */
1650 {
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001651 set_error( STATUS_INVALID_PARAMETER );
Alexandre Julliard684b65c2004-04-16 04:31:35 +00001652 goto error;
Alexandre Julliard9ff78722004-04-02 19:50:49 +00001653 }
Alexandre Julliard684b65c2004-04-16 04:31:35 +00001654 free( closed_fd );
Alexandre Julliard580da242003-03-12 22:38:14 +00001655 }
1656 return fd;
Alexandre Julliard684b65c2004-04-16 04:31:35 +00001657
1658error:
1659 release_object( fd );
1660 free( closed_fd );
1661 return NULL;
Alexandre Julliard580da242003-03-12 22:38:14 +00001662}
1663
1664/* create an fd for an anonymous file */
1665/* if the function fails the unix fd is closed */
Alexandre Julliardf85437c2007-04-10 22:25:07 +02001666struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, int unix_fd, struct object *user,
1667 unsigned int options )
Alexandre Julliard580da242003-03-12 22:38:14 +00001668{
Mike McCormack9a7124e2006-01-24 13:30:55 +01001669 struct fd *fd = alloc_fd_object();
Alexandre Julliard580da242003-03-12 22:38:14 +00001670
1671 if (fd)
1672 {
Mike McCormack9a7124e2006-01-24 13:30:55 +01001673 set_fd_user( fd, fd_user_ops, user );
Alexandre Julliard580da242003-03-12 22:38:14 +00001674 fd->unix_fd = unix_fd;
Alexandre Julliardf85437c2007-04-10 22:25:07 +02001675 fd->options = options;
Alexandre Julliard580da242003-03-12 22:38:14 +00001676 return fd;
1677 }
1678 close( unix_fd );
1679 return NULL;
1680}
1681
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00001682/* retrieve the object that is using an fd */
1683void *get_fd_user( struct fd *fd )
Alexandre Julliard863637b2003-01-30 00:26:44 +00001684{
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00001685 return fd->user;
1686}
Alexandre Julliard863637b2003-01-30 00:26:44 +00001687
Alexandre Julliardf85437c2007-04-10 22:25:07 +02001688/* retrieve the opening options for the fd */
1689unsigned int get_fd_options( struct fd *fd )
1690{
1691 return fd->options;
1692}
1693
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00001694/* retrieve the unix fd for an object */
1695int get_unix_fd( struct fd *fd )
1696{
Alexandre Julliardf3fbae42007-04-18 16:05:59 +02001697 if (fd->unix_fd == -1) set_error( fd->no_fd_status );
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001698 return fd->unix_fd;
Alexandre Julliard863637b2003-01-30 00:26:44 +00001699}
1700
Alexandre Julliard74bd1e42004-03-27 20:48:42 +00001701/* check if two file descriptors point to the same file */
1702int is_same_file_fd( struct fd *fd1, struct fd *fd2 )
1703{
1704 return fd1->inode == fd2->inode;
1705}
1706
Alexandre Julliard5bd51362007-01-12 14:42:43 +01001707/* check if fd is on a removable device */
1708int is_fd_removable( struct fd *fd )
1709{
1710 return (fd->inode && fd->inode->device->removable);
1711}
1712
Alexandre Julliardba896e72007-04-04 19:39:29 +02001713/* set or clear the fd signaled state */
1714void set_fd_signaled( struct fd *fd, int signaled )
1715{
1716 fd->signaled = signaled;
1717 if (signaled) wake_up( fd->user, 0 );
1718}
1719
Alexandre Julliard7a344c12009-06-09 12:11:05 +02001720/* set or clear the fd signaled state */
1721int is_fd_signaled( struct fd *fd )
1722{
1723 return fd->signaled;
1724}
1725
Alexandre Julliard715d78e2006-11-02 20:52:22 +01001726/* handler for close_handle that refuses to close fd-associated handles in other processes */
1727int fd_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
1728{
1729 return (!current || current->process == process);
1730}
1731
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00001732/* check if events are pending and if yes return which one(s) */
1733int check_fd_events( struct fd *fd, int events )
1734{
1735 struct pollfd pfd;
1736
Alexandre Julliard964815b2005-08-08 15:11:03 +00001737 if (fd->unix_fd == -1) return POLLERR;
Alexandre Julliard72bff2e2007-04-10 17:07:27 +02001738 if (fd->inode) return events; /* regular files are always signaled */
Alexandre Julliard964815b2005-08-08 15:11:03 +00001739
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00001740 pfd.fd = fd->unix_fd;
1741 pfd.events = events;
1742 if (poll( &pfd, 1, 0 ) <= 0) return 0;
1743 return pfd.revents;
Alexandre Julliard863637b2003-01-30 00:26:44 +00001744}
1745
Alexandre Julliard863637b2003-01-30 00:26:44 +00001746/* default signaled() routine for objects that poll() on an fd */
1747int default_fd_signaled( struct object *obj, struct thread *thread )
1748{
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001749 struct fd *fd = get_obj_fd( obj );
Alexandre Julliardba896e72007-04-04 19:39:29 +02001750 int ret = fd->signaled;
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001751 release_object( fd );
1752 return ret;
Alexandre Julliard863637b2003-01-30 00:26:44 +00001753}
1754
Alexandre Julliard24001e82007-10-02 14:20:15 +02001755/* default map_access() routine for objects that behave like an fd */
1756unsigned int default_fd_map_access( struct object *obj, unsigned int access )
1757{
1758 if (access & GENERIC_READ) access |= FILE_GENERIC_READ;
1759 if (access & GENERIC_WRITE) access |= FILE_GENERIC_WRITE;
1760 if (access & GENERIC_EXECUTE) access |= FILE_GENERIC_EXECUTE;
1761 if (access & GENERIC_ALL) access |= FILE_ALL_ACCESS;
1762 return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
1763}
1764
Robert Shearmand6a4e342005-06-07 20:09:01 +00001765int default_fd_get_poll_events( struct fd *fd )
1766{
1767 int events = 0;
1768
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001769 if (async_waiting( fd->read_q )) events |= POLLIN;
1770 if (async_waiting( fd->write_q )) events |= POLLOUT;
Robert Shearmand6a4e342005-06-07 20:09:01 +00001771 return events;
1772}
1773
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00001774/* default handler for poll() events */
1775void default_poll_event( struct fd *fd, int event )
1776{
Alexandre Julliard72bff2e2007-04-10 17:07:27 +02001777 if (event & (POLLIN | POLLERR | POLLHUP)) async_wake_up( fd->read_q, STATUS_ALERTED );
1778 if (event & (POLLOUT | POLLERR | POLLHUP)) async_wake_up( fd->write_q, STATUS_ALERTED );
Robert Shearmand6a4e342005-06-07 20:09:01 +00001779
1780 /* if an error occurred, stop polling this fd to avoid busy-looping */
Alexandre Julliarde66207e2003-02-19 00:33:32 +00001781 if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 );
Alexandre Julliard72bff2e2007-04-10 17:07:27 +02001782 else if (!fd->inode) set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) );
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00001783}
1784
Alexandre Julliard9ed42d22008-12-26 12:27:48 +01001785struct async *fd_queue_async( struct fd *fd, const async_data_t *data, int type )
Robert Shearmand6a4e342005-06-07 20:09:01 +00001786{
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001787 struct async_queue *queue;
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +02001788 struct async *async;
Robert Shearmand6a4e342005-06-07 20:09:01 +00001789
1790 switch (type)
1791 {
1792 case ASYNC_TYPE_READ:
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +02001793 if (!fd->read_q && !(fd->read_q = create_async_queue( fd ))) return NULL;
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001794 queue = fd->read_q;
Robert Shearmand6a4e342005-06-07 20:09:01 +00001795 break;
1796 case ASYNC_TYPE_WRITE:
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +02001797 if (!fd->write_q && !(fd->write_q = create_async_queue( fd ))) return NULL;
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001798 queue = fd->write_q;
Robert Shearmand6a4e342005-06-07 20:09:01 +00001799 break;
Alexandre Julliard95ba4b52007-04-02 12:47:52 +02001800 case ASYNC_TYPE_WAIT:
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +02001801 if (!fd->wait_q && !(fd->wait_q = create_async_queue( fd ))) return NULL;
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001802 queue = fd->wait_q;
Alexandre Julliard95ba4b52007-04-02 12:47:52 +02001803 break;
Robert Shearmand6a4e342005-06-07 20:09:01 +00001804 default:
Gerald Pfeiferd529c632007-04-20 13:11:54 +02001805 queue = NULL;
Alexandre Julliard02ed7042007-04-02 20:24:55 +02001806 assert(0);
Robert Shearmand6a4e342005-06-07 20:09:01 +00001807 }
1808
Alexandre Julliardc18e8d62007-04-18 16:28:01 +02001809 if ((async = create_async( current, queue, data )) && type != ASYNC_TYPE_WAIT)
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +02001810 {
1811 if (!fd->inode)
1812 set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) );
1813 else /* regular files are always ready for read and write */
Alexandre Julliardc18e8d62007-04-18 16:28:01 +02001814 async_wake_up( queue, STATUS_ALERTED );
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +02001815 }
1816 return async;
Robert Shearmand6a4e342005-06-07 20:09:01 +00001817}
1818
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001819void fd_async_wake_up( struct fd *fd, int type, unsigned int status )
Alexandre Julliard95ba4b52007-04-02 12:47:52 +02001820{
1821 switch (type)
1822 {
1823 case ASYNC_TYPE_READ:
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001824 async_wake_up( fd->read_q, status );
Alexandre Julliard95ba4b52007-04-02 12:47:52 +02001825 break;
1826 case ASYNC_TYPE_WRITE:
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001827 async_wake_up( fd->write_q, status );
Alexandre Julliard95ba4b52007-04-02 12:47:52 +02001828 break;
1829 case ASYNC_TYPE_WAIT:
Alexandre Julliarddf09ac52007-04-02 20:09:29 +02001830 async_wake_up( fd->wait_q, status );
Alexandre Julliard95ba4b52007-04-02 12:47:52 +02001831 break;
1832 default:
1833 assert(0);
1834 }
1835}
1836
Alexandre Julliard72bff2e2007-04-10 17:07:27 +02001837void fd_reselect_async( struct fd *fd, struct async_queue *queue )
1838{
1839 fd->fd_ops->reselect_async( fd, queue );
1840}
1841
Alexandre Julliard111610c2007-03-20 20:21:12 +01001842void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
Robert Shearman37773dd2005-07-14 12:18:05 +00001843{
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +02001844 struct async *async;
Alexandre Julliarde92f8542007-04-02 12:48:13 +02001845
Alexandre Julliard9ed42d22008-12-26 12:27:48 +01001846 if ((async = fd_queue_async( fd, data, type )))
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +02001847 {
1848 release_object( async );
1849 set_error( STATUS_PENDING );
1850 }
Robert Shearman37773dd2005-07-14 12:18:05 +00001851}
1852
Alexandre Julliard72bff2e2007-04-10 17:07:27 +02001853/* default reselect_async() fd routine */
1854void default_fd_reselect_async( struct fd *fd, struct async_queue *queue )
1855{
1856 if (queue != fd->wait_q)
1857 {
1858 int poll_events = fd->fd_ops->get_poll_events( fd );
1859 int events = check_fd_events( fd, poll_events );
1860 if (events) fd->fd_ops->poll_event( fd, events );
1861 else set_fd_events( fd, poll_events );
1862 }
1863}
1864
1865/* default cancel_async() fd routine */
Mike Kaplinskiyb05774e2009-08-09 00:08:27 -04001866void default_fd_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb )
Robert Shearmand6a4e342005-06-07 20:09:01 +00001867{
Mike Kaplinskiyb05774e2009-08-09 00:08:27 -04001868 int n = 0;
1869
1870 n += async_wake_up_by( fd->read_q, process, thread, iosb, STATUS_CANCELLED );
1871 n += async_wake_up_by( fd->write_q, process, thread, iosb, STATUS_CANCELLED );
1872 n += async_wake_up_by( fd->wait_q, process, thread, iosb, STATUS_CANCELLED );
1873 if (!n && iosb)
1874 set_error( STATUS_NOT_FOUND );
Robert Shearmand6a4e342005-06-07 20:09:01 +00001875}
1876
Alexandre Julliard863637b2003-01-30 00:26:44 +00001877/* default flush() routine */
Alexandre Julliarddf651872007-03-27 16:51:44 +02001878void no_flush( struct fd *fd, struct event **event )
Alexandre Julliard863637b2003-01-30 00:26:44 +00001879{
1880 set_error( STATUS_OBJECT_TYPE_MISMATCH );
Alexandre Julliard863637b2003-01-30 00:26:44 +00001881}
1882
Alexandre Julliard01dd1ff2006-10-03 14:54:21 +02001883static inline int is_valid_mounted_device( struct stat *st )
1884{
1885#if defined(linux) || defined(__sun__)
1886 return S_ISBLK( st->st_mode );
1887#else
1888 /* disks are char devices on *BSD */
1889 return S_ISCHR( st->st_mode );
1890#endif
1891}
1892
Alexandre Julliard964815b2005-08-08 15:11:03 +00001893/* close all Unix file descriptors on a device to allow unmounting it */
Alexandre Julliardf8037bd2005-10-27 11:20:50 +00001894static void unmount_device( struct fd *device_fd )
Alexandre Julliard964815b2005-08-08 15:11:03 +00001895{
1896 unsigned int i;
Alexandre Julliardf8037bd2005-10-27 11:20:50 +00001897 struct stat st;
1898 struct device *device;
Alexandre Julliard964815b2005-08-08 15:11:03 +00001899 struct inode *inode;
1900 struct fd *fd;
Alexandre Julliard67505c02005-12-12 14:27:45 +01001901 int unix_fd = get_unix_fd( device_fd );
Alexandre Julliard964815b2005-08-08 15:11:03 +00001902
Alexandre Julliard67505c02005-12-12 14:27:45 +01001903 if (unix_fd == -1) return;
1904
Alexandre Julliard01dd1ff2006-10-03 14:54:21 +02001905 if (fstat( unix_fd, &st ) == -1 || !is_valid_mounted_device( &st ))
Alexandre Julliardf8037bd2005-10-27 11:20:50 +00001906 {
1907 set_error( STATUS_INVALID_PARAMETER );
1908 return;
1909 }
1910
Alexandre Julliard30b878b2006-11-01 13:28:05 +01001911 if (!(device = get_device( st.st_rdev, -1 ))) return;
Alexandre Julliardf8037bd2005-10-27 11:20:50 +00001912
Alexandre Julliard964815b2005-08-08 15:11:03 +00001913 for (i = 0; i < INODE_HASH_SIZE; i++)
1914 {
1915 LIST_FOR_EACH_ENTRY( inode, &device->inode_hash[i], struct inode, entry )
1916 {
1917 LIST_FOR_EACH_ENTRY( fd, &inode->open, struct fd, inode_entry )
1918 {
1919 unmount_fd( fd );
1920 }
1921 inode_close_pending( inode, 0 );
1922 }
1923 }
1924 /* remove it from the hash table */
1925 list_remove( &device->entry );
1926 list_init( &device->entry );
Alexandre Julliardf8037bd2005-10-27 11:20:50 +00001927 release_object( device );
Alexandre Julliard964815b2005-08-08 15:11:03 +00001928}
1929
Alexandre Julliard2669af72007-04-16 14:54:52 +02001930/* default ioctl() routine */
Alexandre Julliardfd59e152007-05-03 17:43:18 +02001931obj_handle_t default_fd_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
Alexandre Julliard7ec95c52008-12-30 20:37:20 +01001932 int blocking, const void *data, data_size_t size )
Alexandre Julliard2669af72007-04-16 14:54:52 +02001933{
1934 switch(code)
1935 {
1936 case FSCTL_DISMOUNT_VOLUME:
1937 unmount_device( fd );
Alexandre Julliardfd59e152007-05-03 17:43:18 +02001938 return 0;
Alexandre Julliard2669af72007-04-16 14:54:52 +02001939 default:
1940 set_error( STATUS_NOT_SUPPORTED );
Alexandre Julliardfd59e152007-05-03 17:43:18 +02001941 return 0;
Alexandre Julliard2669af72007-04-16 14:54:52 +02001942 }
1943}
1944
Alexandre Julliard863637b2003-01-30 00:26:44 +00001945/* same as get_handle_obj but retrieve the struct fd associated to the object */
1946static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handle,
1947 unsigned int access )
1948{
1949 struct fd *fd = NULL;
1950 struct object *obj;
1951
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00001952 if ((obj = get_handle_obj( process, handle, access, NULL )))
Alexandre Julliard863637b2003-01-30 00:26:44 +00001953 {
Bill Medland3f7c3ff2003-04-17 02:14:04 +00001954 fd = get_obj_fd( obj );
Alexandre Julliard863637b2003-01-30 00:26:44 +00001955 release_object( obj );
1956 }
1957 return fd;
1958}
1959
Alexandre Julliard50171c52009-03-02 20:34:39 +01001960struct completion *fd_get_completion( struct fd *fd, apc_param_t *p_key )
Andrey Turkinc702a912007-11-10 01:11:48 +03001961{
Andrey Turkin3afbee52007-12-17 22:06:17 +03001962 *p_key = fd->comp_key;
Alexandre Julliard50171c52009-03-02 20:34:39 +01001963 return fd->completion ? (struct completion *)grab_object( fd->completion ) : NULL;
1964}
1965
1966void fd_copy_completion( struct fd *src, struct fd *dst )
1967{
1968 assert( !dst->completion );
1969 dst->completion = fd_get_completion( src, &dst->comp_key );
Andrey Turkinc702a912007-11-10 01:11:48 +03001970}
1971
Alexandre Julliard863637b2003-01-30 00:26:44 +00001972/* flush a file buffers */
1973DECL_HANDLER(flush_file)
1974{
1975 struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
Mike McCormackef8b9462003-05-15 04:22:45 +00001976 struct event * event = NULL;
Alexandre Julliard863637b2003-01-30 00:26:44 +00001977
1978 if (fd)
1979 {
Mike McCormackef8b9462003-05-15 04:22:45 +00001980 fd->fd_ops->flush( fd, &event );
Eric Pouech46344472005-01-14 19:54:38 +00001981 if ( event )
Mike McCormackef8b9462003-05-15 04:22:45 +00001982 {
1983 reply->event = alloc_handle( current->process, event, SYNCHRONIZE, 0 );
1984 }
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00001985 release_object( fd );
1986 }
1987}
1988
Alexandre Julliard67505c02005-12-12 14:27:45 +01001989/* open a file object */
1990DECL_HANDLER(open_file_object)
1991{
1992 struct unicode_str name;
1993 struct directory *root = NULL;
Alexandre Julliard94655c82007-03-22 11:52:40 +01001994 struct object *obj, *result;
Alexandre Julliard67505c02005-12-12 14:27:45 +01001995
1996 get_req_unicode_str( &name );
1997 if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
1998 return;
1999
2000 if ((obj = open_object_dir( root, &name, req->attributes, NULL )))
2001 {
Alexandre Julliard94655c82007-03-22 11:52:40 +01002002 if ((result = obj->ops->open_file( obj, req->access, req->sharing, req->options )))
Alexandre Julliard67505c02005-12-12 14:27:45 +01002003 {
Alexandre Julliard94655c82007-03-22 11:52:40 +01002004 reply->handle = alloc_handle( current->process, result, req->access, req->attributes );
2005 release_object( result );
Alexandre Julliard67505c02005-12-12 14:27:45 +01002006 }
2007 release_object( obj );
2008 }
2009
2010 if (root) release_object( root );
2011}
2012
Henri Verbeet27705d52009-11-12 15:10:12 +01002013/* get the Unix name from a file handle */
2014DECL_HANDLER(get_handle_unix_name)
2015{
2016 struct fd *fd;
2017
2018 if ((fd = get_handle_fd_obj( current->process, req->handle, 0 )))
2019 {
2020 if (fd->unix_name)
2021 {
2022 data_size_t name_len = strlen( fd->unix_name );
2023 reply->name_len = name_len;
2024 if (name_len <= get_reply_max_size()) set_reply_data( fd->unix_name, name_len );
2025 else set_error( STATUS_BUFFER_OVERFLOW );
2026 }
2027 release_object( fd );
2028 }
2029}
2030
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00002031/* get a Unix fd to access a file */
2032DECL_HANDLER(get_handle_fd)
2033{
2034 struct fd *fd;
2035
Alexandre Julliardd85121f2007-04-10 22:32:46 +02002036 if ((fd = get_handle_fd_obj( current->process, req->handle, 0 )))
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00002037 {
Alexandre Julliardf3fbae42007-04-18 16:05:59 +02002038 int unix_fd = get_unix_fd( fd );
2039 if (unix_fd != -1)
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00002040 {
Alexandre Julliardf3fbae42007-04-18 16:05:59 +02002041 reply->type = fd->fd_ops->get_fd_type( fd );
2042 reply->removable = is_fd_removable(fd);
2043 reply->options = fd->options;
2044 reply->access = get_handle_access( current->process, req->handle );
Alexandre Julliarda3192632008-02-19 16:51:16 +01002045 send_client_fd( current->process, unix_fd, req->handle );
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +00002046 }
Alexandre Julliard863637b2003-01-30 00:26:44 +00002047 release_object( fd );
2048 }
2049}
2050
Alexandre Julliard63571432007-04-16 14:45:03 +02002051/* perform an ioctl on a file */
2052DECL_HANDLER(ioctl)
2053{
2054 unsigned int access = (req->code >> 14) & (FILE_READ_DATA|FILE_WRITE_DATA);
Alexandre Julliarda7b3efd2008-12-26 12:17:20 +01002055 struct fd *fd = get_handle_fd_obj( current->process, req->async.handle, access );
Alexandre Julliard63571432007-04-16 14:45:03 +02002056
2057 if (fd)
2058 {
Alexandre Julliard7ec95c52008-12-30 20:37:20 +01002059 reply->wait = fd->fd_ops->ioctl( fd, req->code, &req->async, req->blocking,
Alexandre Julliardfd59e152007-05-03 17:43:18 +02002060 get_req_data(), get_req_data_size() );
2061 reply->options = fd->options;
Alexandre Julliard63571432007-04-16 14:45:03 +02002062 release_object( fd );
2063 }
2064}
2065
Alexandre Julliard863637b2003-01-30 00:26:44 +00002066/* create / reschedule an async I/O */
2067DECL_HANDLER(register_async)
2068{
Alexandre Julliard02ed7042007-04-02 20:24:55 +02002069 unsigned int access;
2070 struct fd *fd;
Alexandre Julliard863637b2003-01-30 00:26:44 +00002071
Alexandre Julliard02ed7042007-04-02 20:24:55 +02002072 switch(req->type)
2073 {
2074 case ASYNC_TYPE_READ:
2075 access = FILE_READ_DATA;
2076 break;
2077 case ASYNC_TYPE_WRITE:
2078 access = FILE_WRITE_DATA;
2079 break;
2080 default:
2081 set_error( STATUS_INVALID_PARAMETER );
2082 return;
2083 }
Alexandre Julliard863637b2003-01-30 00:26:44 +00002084
Alexandre Julliarda7b3efd2008-12-26 12:17:20 +01002085 if ((fd = get_handle_fd_obj( current->process, req->async.handle, access )))
Alexandre Julliard863637b2003-01-30 00:26:44 +00002086 {
Alexandre Julliardf3fbae42007-04-18 16:05:59 +02002087 if (get_unix_fd( fd ) != -1) fd->fd_ops->queue_async( fd, &req->async, req->type, req->count );
Alexandre Julliard863637b2003-01-30 00:26:44 +00002088 release_object( fd );
2089 }
2090}
Eric Pouech46344472005-01-14 19:54:38 +00002091
2092/* cancels all async I/O */
2093DECL_HANDLER(cancel_async)
2094{
2095 struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
Mike Kaplinskiyb05774e2009-08-09 00:08:27 -04002096 struct thread *thread = req->only_thread ? current : NULL;
Alexandre Julliardf3fbae42007-04-18 16:05:59 +02002097
Eric Pouech46344472005-01-14 19:54:38 +00002098 if (fd)
2099 {
Mike Kaplinskiyb05774e2009-08-09 00:08:27 -04002100 if (get_unix_fd( fd ) != -1) fd->fd_ops->cancel_async( fd, current->process, thread, req->iosb );
Eric Pouech46344472005-01-14 19:54:38 +00002101 release_object( fd );
Alexandre Julliardf3fbae42007-04-18 16:05:59 +02002102 }
Eric Pouech46344472005-01-14 19:54:38 +00002103}
Andrey Turkind1a81552007-09-28 00:03:39 +04002104
2105/* attach completion object to a fd */
2106DECL_HANDLER(set_completion_info)
2107{
2108 struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
2109
2110 if (fd)
2111 {
Andrey Turkinf1dcf4b2007-12-17 02:02:12 +03002112 if (!(fd->options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) && !fd->completion)
Andrey Turkind1a81552007-09-28 00:03:39 +04002113 {
2114 fd->completion = get_completion_obj( current->process, req->chandle, IO_COMPLETION_MODIFY_STATE );
2115 fd->comp_key = req->ckey;
2116 }
2117 else set_error( STATUS_INVALID_PARAMETER );
2118 release_object( fd );
2119 }
2120}
Andrey Turkin27cb7c72007-11-10 01:11:58 +03002121
2122/* push new completion msg into a completion queue attached to the fd */
2123DECL_HANDLER(add_fd_completion)
2124{
2125 struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
2126 if (fd)
2127 {
Andrey Turkin3afbee52007-12-17 22:06:17 +03002128 if (fd->completion)
2129 add_completion( fd->completion, fd->comp_key, req->cvalue, req->status, req->information );
Andrey Turkin27cb7c72007-11-10 01:11:58 +03002130 release_object( fd );
2131 }
2132}