ntdll: Remove superfluous semicolon.
[wine] / dlls / ntdll / file.c
1 /*
2  * Copyright 1999, 2000 Juergen Schmied
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20 #include "wine/port.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <assert.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_SYS_ERRNO_H
31 #include <sys/errno.h>
32 #endif
33 #ifdef HAVE_LINUX_MAJOR_H
34 # include <linux/major.h>
35 #endif
36 #ifdef HAVE_SYS_STATVFS_H
37 # include <sys/statvfs.h>
38 #endif
39 #ifdef HAVE_SYS_PARAM_H
40 # include <sys/param.h>
41 #endif
42 #ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 #endif
45 #ifdef HAVE_SYS_IOCTL_H
46 #include <sys/ioctl.h>
47 #endif
48 #ifdef HAVE_SYS_FILIO_H
49 # include <sys/filio.h>
50 #endif
51 #ifdef HAVE_POLL_H
52 #include <poll.h>
53 #endif
54 #ifdef HAVE_SYS_POLL_H
55 #include <sys/poll.h>
56 #endif
57 #ifdef HAVE_SYS_SOCKET_H
58 #include <sys/socket.h>
59 #endif
60 #ifdef HAVE_UTIME_H
61 # include <utime.h>
62 #endif
63 #ifdef HAVE_SYS_VFS_H
64 # include <sys/vfs.h>
65 #endif
66 #ifdef HAVE_SYS_MOUNT_H
67 # include <sys/mount.h>
68 #endif
69 #ifdef HAVE_SYS_STATFS_H
70 # include <sys/statfs.h>
71 #endif
72
73 #define NONAMELESSUNION
74 #define NONAMELESSSTRUCT
75 #include "ntstatus.h"
76 #define WIN32_NO_STATUS
77 #include "wine/unicode.h"
78 #include "wine/debug.h"
79 #include "wine/server.h"
80 #include "ntdll_misc.h"
81
82 #include "winternl.h"
83 #include "winioctl.h"
84 #include "ddk/ntddser.h"
85
86 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
87
88 mode_t FILE_umask = 0;
89
90 #define SECSPERDAY         86400
91 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
92
93 /**************************************************************************
94  *                 NtOpenFile                           [NTDLL.@]
95  *                 ZwOpenFile                           [NTDLL.@]
96  *
97  * Open a file.
98  *
99  * PARAMS
100  *  handle    [O] Variable that receives the file handle on return
101  *  access    [I] Access desired by the caller to the file
102  *  attr      [I] Structure describing the file to be opened
103  *  io        [O] Receives details about the result of the operation
104  *  sharing   [I] Type of shared access the caller requires
105  *  options   [I] Options for the file open
106  *
107  * RETURNS
108  *  Success: 0. FileHandle and IoStatusBlock are updated.
109  *  Failure: An NTSTATUS error code describing the error.
110  */
111 NTSTATUS WINAPI NtOpenFile( PHANDLE handle, ACCESS_MASK access,
112                             POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK io,
113                             ULONG sharing, ULONG options )
114 {
115     return NtCreateFile( handle, access, attr, io, NULL, 0,
116                          sharing, FILE_OPEN, options, NULL, 0 );
117 }
118
119 /**************************************************************************
120  *              NtCreateFile                            [NTDLL.@]
121  *              ZwCreateFile                            [NTDLL.@]
122  *
123  * Either create a new file or directory, or open an existing file, device,
124  * directory or volume.
125  *
126  * PARAMS
127  *      handle       [O] Points to a variable which receives the file handle on return
128  *      access       [I] Desired access to the file
129  *      attr         [I] Structure describing the file
130  *      io           [O] Receives information about the operation on return
131  *      alloc_size   [I] Initial size of the file in bytes
132  *      attributes   [I] Attributes to create the file with
133  *      sharing      [I] Type of shared access the caller would like to the file
134  *      disposition  [I] Specifies what to do, depending on whether the file already exists
135  *      options      [I] Options for creating a new file
136  *      ea_buffer    [I] Pointer to an extended attributes buffer
137  *      ea_length    [I] Length of ea_buffer
138  *
139  * RETURNS
140  *  Success: 0. handle and io are updated.
141  *  Failure: An NTSTATUS error code describing the error.
142  */
143 NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
144                               PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
145                               ULONG attributes, ULONG sharing, ULONG disposition,
146                               ULONG options, PVOID ea_buffer, ULONG ea_length )
147 {
148     ANSI_STRING unix_name;
149     int created = FALSE;
150
151     TRACE("handle=%p access=%08x name=%s objattr=%08x root=%p sec=%p io=%p alloc_size=%p\n"
152           "attr=%08x sharing=%08x disp=%d options=%08x ea=%p.0x%08x\n",
153           handle, access, debugstr_us(attr->ObjectName), attr->Attributes,
154           attr->RootDirectory, attr->SecurityDescriptor, io, alloc_size,
155           attributes, sharing, disposition, options, ea_buffer, ea_length );
156
157     if (!attr || !attr->ObjectName) return STATUS_INVALID_PARAMETER;
158
159     if (alloc_size) FIXME( "alloc_size not supported\n" );
160
161     if (attr->RootDirectory ||
162         (io->u.Status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, disposition,
163                                  !(attr->Attributes & OBJ_CASE_INSENSITIVE) )) == STATUS_BAD_DEVICE_TYPE)
164     {
165         SERVER_START_REQ( open_file_object )
166         {
167             req->access     = access;
168             req->attributes = attr->Attributes;
169             req->rootdir    = wine_server_obj_handle( attr->RootDirectory );
170             req->sharing    = sharing;
171             req->options    = options;
172             wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
173             io->u.Status = wine_server_call( req );
174             *handle = wine_server_ptr_handle( reply->handle );
175         }
176         SERVER_END_REQ;
177         if (io->u.Status == STATUS_SUCCESS) io->Information = FILE_OPENED;
178         return io->u.Status;
179     }
180
181     if (io->u.Status == STATUS_NO_SUCH_FILE &&
182         disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
183     {
184         created = TRUE;
185         io->u.Status = STATUS_SUCCESS;
186     }
187
188     if (io->u.Status == STATUS_SUCCESS)
189     {
190         struct security_descriptor *sd = NULL;
191         struct object_attributes objattr;
192
193         objattr.rootdir = 0;
194         objattr.sd_len = 0;
195         objattr.name_len = 0;
196         if (attr)
197         {
198             io->u.Status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
199             if (io->u.Status != STATUS_SUCCESS)
200             {
201                 RtlFreeAnsiString( &unix_name );
202                 return io->u.Status;
203             }
204         }
205
206         SERVER_START_REQ( create_file )
207         {
208             req->access     = access;
209             req->attributes = attr->Attributes;
210             req->sharing    = sharing;
211             req->create     = disposition;
212             req->options    = options;
213             req->attrs      = attributes;
214             wine_server_add_data( req, &objattr, sizeof(objattr) );
215             if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
216             wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
217             io->u.Status = wine_server_call( req );
218             *handle = wine_server_ptr_handle( reply->handle );
219         }
220         SERVER_END_REQ;
221         NTDLL_free_struct_sd( sd );
222         RtlFreeAnsiString( &unix_name );
223     }
224     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
225
226     if (io->u.Status == STATUS_SUCCESS)
227     {
228         if (created) io->Information = FILE_CREATED;
229         else switch(disposition)
230         {
231         case FILE_SUPERSEDE:
232             io->Information = FILE_SUPERSEDED;
233             break;
234         case FILE_CREATE:
235             io->Information = FILE_CREATED;
236             break;
237         case FILE_OPEN:
238         case FILE_OPEN_IF:
239             io->Information = FILE_OPENED;
240             break;
241         case FILE_OVERWRITE:
242         case FILE_OVERWRITE_IF:
243             io->Information = FILE_OVERWRITTEN;
244             break;
245         }
246     }
247
248     return io->u.Status;
249 }
250
251 /***********************************************************************
252  *                  Asynchronous file I/O                              *
253  */
254
255 struct async_fileio
256 {
257     HANDLE              handle;
258     PIO_APC_ROUTINE     apc;
259     void               *apc_arg;
260 };
261
262 typedef struct
263 {
264     struct async_fileio io;
265     char*               buffer;
266     unsigned int        already;
267     unsigned int        count;
268     BOOL                avail_mode;
269 } async_fileio_read;
270
271 typedef struct
272 {
273     struct async_fileio io;
274     const char         *buffer;
275     unsigned int        already;
276     unsigned int        count;
277 } async_fileio_write;
278
279
280 /* callback for file I/O user APC */
281 static void WINAPI fileio_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved )
282 {
283     struct async_fileio *async = arg;
284     if (async->apc) async->apc( async->apc_arg, io, reserved );
285     RtlFreeHeap( GetProcessHeap(), 0, async );
286 }
287
288 /***********************************************************************
289  *           FILE_GetNtStatus(void)
290  *
291  * Retrieve the Nt Status code from errno.
292  * Try to be consistent with FILE_SetDosError().
293  */
294 NTSTATUS FILE_GetNtStatus(void)
295 {
296     int err = errno;
297
298     TRACE( "errno = %d\n", errno );
299     switch (err)
300     {
301     case EAGAIN:    return STATUS_SHARING_VIOLATION;
302     case EBADF:     return STATUS_INVALID_HANDLE;
303     case EBUSY:     return STATUS_DEVICE_BUSY;
304     case ENOSPC:    return STATUS_DISK_FULL;
305     case EPERM:
306     case EROFS:
307     case EACCES:    return STATUS_ACCESS_DENIED;
308     case ENOTDIR:   return STATUS_OBJECT_PATH_NOT_FOUND;
309     case ENOENT:    return STATUS_OBJECT_NAME_NOT_FOUND;
310     case EISDIR:    return STATUS_FILE_IS_A_DIRECTORY;
311     case EMFILE:
312     case ENFILE:    return STATUS_TOO_MANY_OPENED_FILES;
313     case EINVAL:    return STATUS_INVALID_PARAMETER;
314     case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
315     case EPIPE:     return STATUS_PIPE_DISCONNECTED;
316     case EIO:       return STATUS_DEVICE_NOT_READY;
317 #ifdef ENOMEDIUM
318     case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE;
319 #endif
320     case ENXIO:     return STATUS_NO_SUCH_DEVICE;
321     case ENOTTY:
322     case EOPNOTSUPP:return STATUS_NOT_SUPPORTED;
323     case ECONNRESET:return STATUS_PIPE_DISCONNECTED;
324     case EFAULT:    return STATUS_ACCESS_VIOLATION;
325     case ESPIPE:    return STATUS_ILLEGAL_FUNCTION;
326     case ENOEXEC:   /* ?? */
327     case EEXIST:    /* ?? */
328     default:
329         FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
330         return STATUS_UNSUCCESSFUL;
331     }
332 }
333
334 /***********************************************************************
335  *             FILE_AsyncReadService      (INTERNAL)
336  */
337 static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc)
338 {
339     async_fileio_read *fileio = user;
340     int fd, needs_close, result;
341
342     switch (status)
343     {
344     case STATUS_ALERTED: /* got some new data */
345         /* check to see if the data is ready (non-blocking) */
346         if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
347                                           &needs_close, NULL, NULL )))
348             break;
349
350         result = read(fd, &fileio->buffer[fileio->already], fileio->count - fileio->already);
351         if (needs_close) close( fd );
352
353         if (result < 0)
354         {
355             if (errno == EAGAIN || errno == EINTR)
356                 status = STATUS_PENDING;
357             else /* check to see if the transfer is complete */
358                 status = FILE_GetNtStatus();
359         }
360         else if (result == 0)
361         {
362             status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN;
363         }
364         else
365         {
366             fileio->already += result;
367             if (fileio->already >= fileio->count || fileio->avail_mode)
368                 status = STATUS_SUCCESS;
369             else
370             {
371                 /* if we only have to read the available data, and none is available,
372                  * simply cancel the request. If data was available, it has been read
373                  * while in by previous call (NtDelayExecution)
374                  */
375                 status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING;
376             }
377         }
378         break;
379
380     case STATUS_TIMEOUT:
381     case STATUS_IO_TIMEOUT:
382         if (fileio->already) status = STATUS_SUCCESS;
383         break;
384     }
385     if (status != STATUS_PENDING)
386     {
387         iosb->u.Status = status;
388         iosb->Information = fileio->already;
389         *apc = fileio_apc;
390     }
391     return status;
392 }
393
394 struct io_timeouts
395 {
396     int interval;   /* max interval between two bytes */
397     int total;      /* total timeout for the whole operation */
398     int end_time;   /* absolute time of end of operation */
399 };
400
401 /* retrieve the I/O timeouts to use for a given handle */
402 static NTSTATUS get_io_timeouts( HANDLE handle, enum server_fd_type type, ULONG count, BOOL is_read,
403                                  struct io_timeouts *timeouts )
404 {
405     NTSTATUS status = STATUS_SUCCESS;
406
407     timeouts->interval = timeouts->total = -1;
408
409     switch(type)
410     {
411     case FD_TYPE_SERIAL:
412         {
413             /* GetCommTimeouts */
414             SERIAL_TIMEOUTS st;
415             IO_STATUS_BLOCK io;
416
417             status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
418                                             IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
419             if (status) break;
420
421             if (is_read)
422             {
423                 if (st.ReadIntervalTimeout)
424                     timeouts->interval = st.ReadIntervalTimeout;
425
426                 if (st.ReadTotalTimeoutMultiplier || st.ReadTotalTimeoutConstant)
427                 {
428                     timeouts->total = st.ReadTotalTimeoutConstant;
429                     if (st.ReadTotalTimeoutMultiplier != MAXDWORD)
430                         timeouts->total += count * st.ReadTotalTimeoutMultiplier;
431                 }
432                 else if (st.ReadIntervalTimeout == MAXDWORD)
433                     timeouts->interval = timeouts->total = 0;
434             }
435             else  /* write */
436             {
437                 if (st.WriteTotalTimeoutMultiplier || st.WriteTotalTimeoutConstant)
438                 {
439                     timeouts->total = st.WriteTotalTimeoutConstant;
440                     if (st.WriteTotalTimeoutMultiplier != MAXDWORD)
441                         timeouts->total += count * st.WriteTotalTimeoutMultiplier;
442                 }
443             }
444         }
445         break;
446     case FD_TYPE_MAILSLOT:
447         if (is_read)
448         {
449             timeouts->interval = 0;  /* return as soon as we got something */
450             SERVER_START_REQ( set_mailslot_info )
451             {
452                 req->handle = wine_server_obj_handle( handle );
453                 req->flags = 0;
454                 if (!(status = wine_server_call( req )) &&
455                     reply->read_timeout != TIMEOUT_INFINITE)
456                     timeouts->total = reply->read_timeout / -10000;
457             }
458             SERVER_END_REQ;
459         }
460         break;
461     case FD_TYPE_SOCKET:
462     case FD_TYPE_PIPE:
463     case FD_TYPE_CHAR:
464         if (is_read) timeouts->interval = 0;  /* return as soon as we got something */
465         break;
466     default:
467         break;
468     }
469     if (timeouts->total != -1) timeouts->end_time = NtGetTickCount() + timeouts->total;
470     return STATUS_SUCCESS;
471 }
472
473
474 /* retrieve the timeout for the next wait, in milliseconds */
475 static inline int get_next_io_timeout( const struct io_timeouts *timeouts, ULONG already )
476 {
477     int ret = -1;
478
479     if (timeouts->total != -1)
480     {
481         ret = timeouts->end_time - NtGetTickCount();
482         if (ret < 0) ret = 0;
483     }
484     if (already && timeouts->interval != -1)
485     {
486         if (ret == -1 || ret > timeouts->interval) ret = timeouts->interval;
487     }
488     return ret;
489 }
490
491
492 /* retrieve the avail_mode flag for async reads */
493 static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL *avail_mode )
494 {
495     NTSTATUS status = STATUS_SUCCESS;
496
497     switch(type)
498     {
499     case FD_TYPE_SERIAL:
500         {
501             /* GetCommTimeouts */
502             SERIAL_TIMEOUTS st;
503             IO_STATUS_BLOCK io;
504
505             status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
506                                             IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
507             if (status) break;
508             *avail_mode = (!st.ReadTotalTimeoutMultiplier &&
509                            !st.ReadTotalTimeoutConstant &&
510                            st.ReadIntervalTimeout == MAXDWORD);
511         }
512         break;
513     case FD_TYPE_MAILSLOT:
514     case FD_TYPE_SOCKET:
515     case FD_TYPE_PIPE:
516     case FD_TYPE_CHAR:
517         *avail_mode = TRUE;
518         break;
519     default:
520         *avail_mode = FALSE;
521         break;
522     }
523     return status;
524 }
525
526
527 /******************************************************************************
528  *  NtReadFile                                  [NTDLL.@]
529  *  ZwReadFile                                  [NTDLL.@]
530  *
531  * Read from an open file handle.
532  *
533  * PARAMS
534  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
535  *  Event         [I] Event to signal upon completion (or NULL)
536  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
537  *  ApcContext    [I] Context for ApcRoutine (or NULL)
538  *  IoStatusBlock [O] Receives information about the operation on return
539  *  Buffer        [O] Destination for the data read
540  *  Length        [I] Size of Buffer
541  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
542  *  Key           [O] Function unknown (may be NULL)
543  *
544  * RETURNS
545  *  Success: 0. IoStatusBlock is updated, and the Information member contains
546  *           The number of bytes read.
547  *  Failure: An NTSTATUS error code describing the error.
548  */
549 NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
550                            PIO_APC_ROUTINE apc, void* apc_user,
551                            PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
552                            PLARGE_INTEGER offset, PULONG key)
553 {
554     int result, unix_handle, needs_close, timeout_init_done = 0;
555     unsigned int options;
556     struct io_timeouts timeouts;
557     NTSTATUS status;
558     ULONG total = 0;
559     enum server_fd_type type;
560     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
561
562     TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
563           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
564
565     if (!io_status) return STATUS_ACCESS_VIOLATION;
566
567     status = server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
568                                  &needs_close, &type, &options );
569     if (status) return status;
570
571     if (!virtual_check_buffer_for_write( buffer, length ))
572     {
573         status = STATUS_ACCESS_VIOLATION;
574         goto done;
575     }
576
577     if (type == FD_TYPE_FILE && offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */ )
578     {
579         /* async I/O doesn't make sense on regular files */
580         while ((result = pread( unix_handle, buffer, length, offset->QuadPart )) == -1)
581         {
582             if (errno != EINTR)
583             {
584                 status = FILE_GetNtStatus();
585                 goto done;
586             }
587         }
588         if (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
589             /* update file pointer position */
590             lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
591
592         total = result;
593         status = total ? STATUS_SUCCESS : STATUS_END_OF_FILE;
594         goto done;
595     }
596
597     for (;;)
598     {
599         if ((result = read( unix_handle, (char *)buffer + total, length - total )) >= 0)
600         {
601             total += result;
602             if (!result || total == length)
603             {
604                 if (total)
605                 {
606                     status = STATUS_SUCCESS;
607                     goto done;
608                 }
609                 switch (type)
610                 {
611                 case FD_TYPE_FILE:
612                 case FD_TYPE_CHAR:
613                     status = STATUS_END_OF_FILE;
614                     goto done;
615                 case FD_TYPE_SERIAL:
616                     break;
617                 default:
618                     status = STATUS_PIPE_BROKEN;
619                     goto done;
620                 }
621             }
622             else if (type == FD_TYPE_FILE) continue;  /* no async I/O on regular files */
623         }
624         else if (errno != EAGAIN)
625         {
626             if (errno == EINTR) continue;
627             if (!total) status = FILE_GetNtStatus();
628             goto done;
629         }
630
631         if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
632         {
633             async_fileio_read *fileio;
634             BOOL avail_mode;
635
636             if ((status = get_io_avail_mode( hFile, type, &avail_mode )))
637                 goto err;
638             if (total && avail_mode)
639             {
640                 status = STATUS_SUCCESS;
641                 goto done;
642             }
643
644             if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio))))
645             {
646                 status = STATUS_NO_MEMORY;
647                 goto err;
648             }
649             fileio->io.handle  = hFile;
650             fileio->io.apc     = apc;
651             fileio->io.apc_arg = apc_user;
652             fileio->already = total;
653             fileio->count = length;
654             fileio->buffer = buffer;
655             fileio->avail_mode = avail_mode;
656
657             SERVER_START_REQ( register_async )
658             {
659                 req->type   = ASYNC_TYPE_READ;
660                 req->count  = length;
661                 req->async.handle   = wine_server_obj_handle( hFile );
662                 req->async.event    = wine_server_obj_handle( hEvent );
663                 req->async.callback = wine_server_client_ptr( FILE_AsyncReadService );
664                 req->async.iosb     = wine_server_client_ptr( io_status );
665                 req->async.arg      = wine_server_client_ptr( fileio );
666                 req->async.cvalue   = cvalue;
667                 status = wine_server_call( req );
668             }
669             SERVER_END_REQ;
670
671             if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
672             goto err;
673         }
674         else  /* synchronous read, wait for the fd to become ready */
675         {
676             struct pollfd pfd;
677             int ret, timeout;
678
679             if (!timeout_init_done)
680             {
681                 timeout_init_done = 1;
682                 if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts )))
683                     goto err;
684                 if (hEvent) NtResetEvent( hEvent, NULL );
685             }
686             timeout = get_next_io_timeout( &timeouts, total );
687
688             pfd.fd = unix_handle;
689             pfd.events = POLLIN;
690
691             if (!timeout || !(ret = poll( &pfd, 1, timeout )))
692             {
693                 if (total)  /* return with what we got so far */
694                     status = STATUS_SUCCESS;
695                 else
696                     status = (type == FD_TYPE_MAILSLOT) ? STATUS_IO_TIMEOUT : STATUS_TIMEOUT;
697                 goto done;
698             }
699             if (ret == -1 && errno != EINTR)
700             {
701                 status = FILE_GetNtStatus();
702                 goto done;
703             }
704             /* will now restart the read */
705         }
706     }
707
708 done:
709     if (cvalue) NTDLL_AddCompletion( hFile, cvalue, status, total );
710
711 err:
712     if (needs_close) close( unix_handle );
713     if (status == STATUS_SUCCESS)
714     {
715         io_status->u.Status = status;
716         io_status->Information = total;
717         TRACE("= SUCCESS (%u)\n", total);
718         if (hEvent) NtSetEvent( hEvent, NULL );
719         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
720                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
721     }
722     else
723     {
724         TRACE("= 0x%08x\n", status);
725         if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
726     }
727     return status;
728 }
729
730
731 /******************************************************************************
732  *  NtReadFileScatter   [NTDLL.@]
733  *  ZwReadFileScatter   [NTDLL.@]
734  */
735 NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
736                                    PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
737                                    ULONG length, PLARGE_INTEGER offset, PULONG key )
738 {
739     size_t page_size = getpagesize();
740     int result, unix_handle, needs_close;
741     unsigned int options;
742     NTSTATUS status;
743     ULONG pos = 0, total = 0;
744     enum server_fd_type type;
745     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
746
747     TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
748            file, event, apc, apc_user, io_status, segments, length, offset, key);
749
750     if (length % page_size) return STATUS_INVALID_PARAMETER;
751     if (!io_status) return STATUS_ACCESS_VIOLATION;
752
753     status = server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
754                                  &needs_close, &type, &options );
755     if (status) return status;
756
757     if ((type != FD_TYPE_FILE) ||
758         (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
759         !(options & FILE_NO_INTERMEDIATE_BUFFERING))
760     {
761         status = STATUS_INVALID_PARAMETER;
762         goto error;
763     }
764
765     while (length)
766     {
767         if (offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */)
768             result = pread( unix_handle, (char *)segments->Buffer + pos,
769                             page_size - pos, offset->QuadPart + total );
770         else
771             result = read( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
772
773         if (result == -1)
774         {
775             if (errno == EINTR) continue;
776             status = FILE_GetNtStatus();
777             break;
778         }
779         if (!result)
780         {
781             status = STATUS_END_OF_FILE;
782             break;
783         }
784         total += result;
785         length -= result;
786         if ((pos += result) == page_size)
787         {
788             pos = 0;
789             segments++;
790         }
791     }
792
793     if (cvalue) NTDLL_AddCompletion( file, cvalue, status, total );
794
795  error:
796     if (needs_close) close( unix_handle );
797     if (status == STATUS_SUCCESS)
798     {
799         io_status->u.Status = status;
800         io_status->Information = total;
801         TRACE("= SUCCESS (%u)\n", total);
802         if (event) NtSetEvent( event, NULL );
803         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
804                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
805     }
806     else
807     {
808         TRACE("= 0x%08x\n", status);
809         if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
810     }
811     return status;
812 }
813
814
815 /***********************************************************************
816  *             FILE_AsyncWriteService      (INTERNAL)
817  */
818 static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status, void **apc)
819 {
820     async_fileio_write *fileio = user;
821     int result, fd, needs_close;
822     enum server_fd_type type;
823
824     switch (status)
825     {
826     case STATUS_ALERTED:
827         /* write some data (non-blocking) */
828         if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
829                                           &needs_close, &type, NULL )))
830             break;
831
832         if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
833             result = send( fd, fileio->buffer, 0, 0 );
834         else
835             result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already );
836
837         if (needs_close) close( fd );
838
839         if (result < 0)
840         {
841             if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING;
842             else status = FILE_GetNtStatus();
843         }
844         else
845         {
846             fileio->already += result;
847             status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
848         }
849         break;
850
851     case STATUS_TIMEOUT:
852     case STATUS_IO_TIMEOUT:
853         if (fileio->already) status = STATUS_SUCCESS;
854         break;
855     }
856     if (status != STATUS_PENDING)
857     {
858         iosb->u.Status = status;
859         iosb->Information = fileio->already;
860         *apc = fileio_apc;
861     }
862     return status;
863 }
864
865 /******************************************************************************
866  *  NtWriteFile                                 [NTDLL.@]
867  *  ZwWriteFile                                 [NTDLL.@]
868  *
869  * Write to an open file handle.
870  *
871  * PARAMS
872  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
873  *  Event         [I] Event to signal upon completion (or NULL)
874  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
875  *  ApcContext    [I] Context for ApcRoutine (or NULL)
876  *  IoStatusBlock [O] Receives information about the operation on return
877  *  Buffer        [I] Source for the data to write
878  *  Length        [I] Size of Buffer
879  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
880  *  Key           [O] Function unknown (may be NULL)
881  *
882  * RETURNS
883  *  Success: 0. IoStatusBlock is updated, and the Information member contains
884  *           The number of bytes written.
885  *  Failure: An NTSTATUS error code describing the error.
886  */
887 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
888                             PIO_APC_ROUTINE apc, void* apc_user,
889                             PIO_STATUS_BLOCK io_status, 
890                             const void* buffer, ULONG length,
891                             PLARGE_INTEGER offset, PULONG key)
892 {
893     int result, unix_handle, needs_close, timeout_init_done = 0;
894     unsigned int options;
895     struct io_timeouts timeouts;
896     NTSTATUS status;
897     ULONG total = 0;
898     enum server_fd_type type;
899     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
900
901     TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)!\n",
902           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
903
904     if (!io_status) return STATUS_ACCESS_VIOLATION;
905
906     status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
907                                  &needs_close, &type, &options );
908     if (status) return status;
909
910     if (!virtual_check_buffer_for_read( buffer, length ))
911     {
912         status = STATUS_INVALID_USER_BUFFER;
913         goto done;
914     }
915
916     if (type == FD_TYPE_FILE && offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */ )
917     {
918         /* async I/O doesn't make sense on regular files */
919         while ((result = pwrite( unix_handle, buffer, length, offset->QuadPart )) == -1)
920         {
921             if (errno != EINTR)
922             {
923                 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
924                 else status = FILE_GetNtStatus();
925                 goto done;
926             }
927         }
928
929         if (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
930             /* update file pointer position */
931             lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
932
933         total = result;
934         status = STATUS_SUCCESS;
935         goto done;
936     }
937
938     for (;;)
939     {
940         /* zero-length writes on sockets may not work with plain write(2) */
941         if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
942             result = send( unix_handle, buffer, 0, 0 );
943         else
944             result = write( unix_handle, (const char *)buffer + total, length - total );
945
946         if (result >= 0)
947         {
948             total += result;
949             if (total == length)
950             {
951                 status = STATUS_SUCCESS;
952                 goto done;
953             }
954             if (type == FD_TYPE_FILE) continue;  /* no async I/O on regular files */
955         }
956         else if (errno != EAGAIN)
957         {
958             if (errno == EINTR) continue;
959             if (!total)
960             {
961                 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
962                 else status = FILE_GetNtStatus();
963             }
964             goto done;
965         }
966
967         if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
968         {
969             async_fileio_write *fileio;
970
971             if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio))))
972             {
973                 status = STATUS_NO_MEMORY;
974                 goto err;
975             }
976             fileio->io.handle  = hFile;
977             fileio->io.apc     = apc;
978             fileio->io.apc_arg = apc_user;
979             fileio->already = total;
980             fileio->count = length;
981             fileio->buffer = buffer;
982
983             SERVER_START_REQ( register_async )
984             {
985                 req->type   = ASYNC_TYPE_WRITE;
986                 req->count  = length;
987                 req->async.handle   = wine_server_obj_handle( hFile );
988                 req->async.event    = wine_server_obj_handle( hEvent );
989                 req->async.callback = wine_server_client_ptr( FILE_AsyncWriteService );
990                 req->async.iosb     = wine_server_client_ptr( io_status );
991                 req->async.arg      = wine_server_client_ptr( fileio );
992                 req->async.cvalue   = cvalue;
993                 status = wine_server_call( req );
994             }
995             SERVER_END_REQ;
996
997             if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
998             goto err;
999         }
1000         else  /* synchronous write, wait for the fd to become ready */
1001         {
1002             struct pollfd pfd;
1003             int ret, timeout;
1004
1005             if (!timeout_init_done)
1006             {
1007                 timeout_init_done = 1;
1008                 if ((status = get_io_timeouts( hFile, type, length, FALSE, &timeouts )))
1009                     goto err;
1010                 if (hEvent) NtResetEvent( hEvent, NULL );
1011             }
1012             timeout = get_next_io_timeout( &timeouts, total );
1013
1014             pfd.fd = unix_handle;
1015             pfd.events = POLLOUT;
1016
1017             if (!timeout || !(ret = poll( &pfd, 1, timeout )))
1018             {
1019                 /* return with what we got so far */
1020                 status = total ? STATUS_SUCCESS : STATUS_TIMEOUT;
1021                 goto done;
1022             }
1023             if (ret == -1 && errno != EINTR)
1024             {
1025                 status = FILE_GetNtStatus();
1026                 goto done;
1027             }
1028             /* will now restart the write */
1029         }
1030     }
1031
1032 done:
1033     if (cvalue) NTDLL_AddCompletion( hFile, cvalue, status, total );
1034
1035 err:
1036     if (needs_close) close( unix_handle );
1037     if (status == STATUS_SUCCESS)
1038     {
1039         io_status->u.Status = status;
1040         io_status->Information = total;
1041         TRACE("= SUCCESS (%u)\n", total);
1042         if (hEvent) NtSetEvent( hEvent, NULL );
1043         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1044                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1045     }
1046     else
1047     {
1048         TRACE("= 0x%08x\n", status);
1049         if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
1050     }
1051     return status;
1052 }
1053
1054
1055 /******************************************************************************
1056  *  NtWriteFileGather   [NTDLL.@]
1057  *  ZwWriteFileGather   [NTDLL.@]
1058  */
1059 NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1060                                    PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
1061                                    ULONG length, PLARGE_INTEGER offset, PULONG key )
1062 {
1063     size_t page_size = getpagesize();
1064     int result, unix_handle, needs_close;
1065     unsigned int options;
1066     NTSTATUS status;
1067     ULONG pos = 0, total = 0;
1068     enum server_fd_type type;
1069     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1070
1071     TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
1072            file, event, apc, apc_user, io_status, segments, length, offset, key);
1073
1074     if (length % page_size) return STATUS_INVALID_PARAMETER;
1075     if (!io_status) return STATUS_ACCESS_VIOLATION;
1076
1077     status = server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
1078                                  &needs_close, &type, &options );
1079     if (status) return status;
1080
1081     if ((type != FD_TYPE_FILE) ||
1082         (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
1083         !(options & FILE_NO_INTERMEDIATE_BUFFERING))
1084     {
1085         status = STATUS_INVALID_PARAMETER;
1086         goto error;
1087     }
1088
1089     while (length)
1090     {
1091         if (offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */)
1092             result = pwrite( unix_handle, (char *)segments->Buffer + pos,
1093                              page_size - pos, offset->QuadPart + total );
1094         else
1095             result = write( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
1096
1097         if (result == -1)
1098         {
1099             if (errno == EINTR) continue;
1100             if (errno == EFAULT)
1101             {
1102                 status = STATUS_INVALID_USER_BUFFER;
1103                 goto error;
1104             }
1105             status = FILE_GetNtStatus();
1106             break;
1107         }
1108         if (!result)
1109         {
1110             status = STATUS_DISK_FULL;
1111             break;
1112         }
1113         total += result;
1114         length -= result;
1115         if ((pos += result) == page_size)
1116         {
1117             pos = 0;
1118             segments++;
1119         }
1120     }
1121
1122     if (cvalue) NTDLL_AddCompletion( file, cvalue, status, total );
1123
1124  error:
1125     if (needs_close) close( unix_handle );
1126     if (status == STATUS_SUCCESS)
1127     {
1128         io_status->u.Status = status;
1129         io_status->Information = total;
1130         TRACE("= SUCCESS (%u)\n", total);
1131         if (event) NtSetEvent( event, NULL );
1132         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1133                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1134     }
1135     else
1136     {
1137         TRACE("= 0x%08x\n", status);
1138         if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
1139     }
1140     return status;
1141 }
1142
1143
1144 struct async_ioctl
1145 {
1146     HANDLE          handle;   /* handle to the device */
1147     HANDLE          event;    /* async event */
1148     void           *buffer;   /* buffer for output */
1149     ULONG           size;     /* size of buffer */
1150     PIO_APC_ROUTINE apc;      /* user apc params */
1151     void           *apc_arg;
1152 };
1153
1154 /* callback for ioctl user APC */
1155 static void WINAPI ioctl_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved )
1156 {
1157     struct async_ioctl *async = arg;
1158     if (async->apc) async->apc( async->apc_arg, io, reserved );
1159     RtlFreeHeap( GetProcessHeap(), 0, async );
1160 }
1161
1162 /* callback for ioctl async I/O completion */
1163 static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS status, void **apc )
1164 {
1165     struct async_ioctl *async = arg;
1166
1167     if (status == STATUS_ALERTED)
1168     {
1169         SERVER_START_REQ( get_ioctl_result )
1170         {
1171             req->handle   = wine_server_obj_handle( async->handle );
1172             req->user_arg = wine_server_client_ptr( async );
1173             wine_server_set_reply( req, async->buffer, async->size );
1174             if (!(status = wine_server_call( req )))
1175                 io->Information = wine_server_reply_size( reply );
1176         }
1177         SERVER_END_REQ;
1178     }
1179     if (status != STATUS_PENDING)
1180     {
1181         io->u.Status = status;
1182         if (async->apc || async->event) *apc = ioctl_apc;
1183     }
1184     return status;
1185 }
1186
1187 /* do a ioctl call through the server */
1188 static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
1189                                    PIO_APC_ROUTINE apc, PVOID apc_context,
1190                                    IO_STATUS_BLOCK *io, ULONG code,
1191                                    const void *in_buffer, ULONG in_size,
1192                                    PVOID out_buffer, ULONG out_size )
1193 {
1194     struct async_ioctl *async;
1195     NTSTATUS status;
1196     HANDLE wait_handle;
1197     ULONG options;
1198     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
1199
1200     if (!(async = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*async) )))
1201         return STATUS_NO_MEMORY;
1202     async->handle  = handle;
1203     async->event   = event;
1204     async->buffer  = out_buffer;
1205     async->size    = out_size;
1206     async->apc     = apc;
1207     async->apc_arg = apc_context;
1208
1209     SERVER_START_REQ( ioctl )
1210     {
1211         req->code           = code;
1212         req->blocking       = !apc && !event;
1213         req->async.handle   = wine_server_obj_handle( handle );
1214         req->async.callback = wine_server_client_ptr( ioctl_completion );
1215         req->async.iosb     = wine_server_client_ptr( io );
1216         req->async.arg      = wine_server_client_ptr( async );
1217         req->async.event    = wine_server_obj_handle( event );
1218         req->async.cvalue   = cvalue;
1219         wine_server_add_data( req, in_buffer, in_size );
1220         wine_server_set_reply( req, out_buffer, out_size );
1221         if (!(status = wine_server_call( req )))
1222             io->Information = wine_server_reply_size( reply );
1223         wait_handle = wine_server_ptr_handle( reply->wait );
1224         options     = reply->options;
1225     }
1226     SERVER_END_REQ;
1227
1228     if (status == STATUS_NOT_SUPPORTED)
1229         FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
1230               code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1231
1232     if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
1233
1234     if (wait_handle)
1235     {
1236         NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL );
1237         status = io->u.Status;
1238         NtClose( wait_handle );
1239         RtlFreeHeap( GetProcessHeap(), 0, async );
1240     }
1241
1242     return status;
1243 }
1244
1245
1246 /**************************************************************************
1247  *              NtDeviceIoControlFile                   [NTDLL.@]
1248  *              ZwDeviceIoControlFile                   [NTDLL.@]
1249  *
1250  * Perform an I/O control operation on an open file handle.
1251  *
1252  * PARAMS
1253  *  handle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1254  *  event          [I] Event to signal upon completion (or NULL)
1255  *  apc            [I] Callback to call upon completion (or NULL)
1256  *  apc_context    [I] Context for ApcRoutine (or NULL)
1257  *  io             [O] Receives information about the operation on return
1258  *  code           [I] Control code for the operation to perform
1259  *  in_buffer      [I] Source for any input data required (or NULL)
1260  *  in_size        [I] Size of InputBuffer
1261  *  out_buffer     [O] Source for any output data returned (or NULL)
1262  *  out_size       [I] Size of OutputBuffer
1263  *
1264  * RETURNS
1265  *  Success: 0. IoStatusBlock is updated.
1266  *  Failure: An NTSTATUS error code describing the error.
1267  */
1268 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
1269                                       PIO_APC_ROUTINE apc, PVOID apc_context,
1270                                       PIO_STATUS_BLOCK io, ULONG code,
1271                                       PVOID in_buffer, ULONG in_size,
1272                                       PVOID out_buffer, ULONG out_size)
1273 {
1274     ULONG device = (code >> 16);
1275     NTSTATUS status = STATUS_NOT_SUPPORTED;
1276
1277     TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1278           handle, event, apc, apc_context, io, code,
1279           in_buffer, in_size, out_buffer, out_size);
1280
1281     switch(device)
1282     {
1283     case FILE_DEVICE_DISK:
1284     case FILE_DEVICE_CD_ROM:
1285     case FILE_DEVICE_DVD:
1286     case FILE_DEVICE_CONTROLLER:
1287     case FILE_DEVICE_MASS_STORAGE:
1288         status = CDROM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1289                                        in_buffer, in_size, out_buffer, out_size);
1290         break;
1291     case FILE_DEVICE_SERIAL_PORT:
1292         status = COMM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1293                                       in_buffer, in_size, out_buffer, out_size);
1294         break;
1295     case FILE_DEVICE_TAPE:
1296         status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
1297                                       in_buffer, in_size, out_buffer, out_size);
1298         break;
1299     }
1300
1301     if (status == STATUS_NOT_SUPPORTED || status == STATUS_BAD_DEVICE_TYPE)
1302         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1303                                     in_buffer, in_size, out_buffer, out_size );
1304
1305     if (status != STATUS_PENDING) io->u.Status = status;
1306     return status;
1307 }
1308
1309
1310 /**************************************************************************
1311  *              NtFsControlFile                 [NTDLL.@]
1312  *              ZwFsControlFile                 [NTDLL.@]
1313  *
1314  * Perform a file system control operation on an open file handle.
1315  *
1316  * PARAMS
1317  *  handle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1318  *  event          [I] Event to signal upon completion (or NULL)
1319  *  apc            [I] Callback to call upon completion (or NULL)
1320  *  apc_context    [I] Context for ApcRoutine (or NULL)
1321  *  io             [O] Receives information about the operation on return
1322  *  code           [I] Control code for the operation to perform
1323  *  in_buffer      [I] Source for any input data required (or NULL)
1324  *  in_size        [I] Size of InputBuffer
1325  *  out_buffer     [O] Source for any output data returned (or NULL)
1326  *  out_size       [I] Size of OutputBuffer
1327  *
1328  * RETURNS
1329  *  Success: 0. IoStatusBlock is updated.
1330  *  Failure: An NTSTATUS error code describing the error.
1331  */
1332 NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
1333                                 PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code,
1334                                 PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size)
1335 {
1336     NTSTATUS status;
1337
1338     TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1339           handle, event, apc, apc_context, io, code,
1340           in_buffer, in_size, out_buffer, out_size);
1341
1342     if (!io) return STATUS_INVALID_PARAMETER;
1343
1344     switch(code)
1345     {
1346     case FSCTL_DISMOUNT_VOLUME:
1347         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1348                                     in_buffer, in_size, out_buffer, out_size );
1349         if (!status) status = DIR_unmount_device( handle );
1350         break;
1351
1352     case FSCTL_PIPE_PEEK:
1353         {
1354             FILE_PIPE_PEEK_BUFFER *buffer = out_buffer;
1355             int avail = 0, fd, needs_close;
1356
1357             if (out_size < FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ))
1358             {
1359                 status = STATUS_INFO_LENGTH_MISMATCH;
1360                 break;
1361             }
1362
1363             if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )))
1364                 break;
1365
1366 #ifdef FIONREAD
1367             if (ioctl( fd, FIONREAD, &avail ) != 0)
1368             {
1369                 TRACE("FIONREAD failed reason: %s\n",strerror(errno));
1370                 if (needs_close) close( fd );
1371                 status = FILE_GetNtStatus();
1372                 break;
1373             }
1374 #endif
1375             if (!avail)  /* check for closed pipe */
1376             {
1377                 struct pollfd pollfd;
1378                 int ret;
1379
1380                 pollfd.fd = fd;
1381                 pollfd.events = POLLIN;
1382                 pollfd.revents = 0;
1383                 ret = poll( &pollfd, 1, 0 );
1384                 if (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR))))
1385                 {
1386                     if (needs_close) close( fd );
1387                     status = STATUS_PIPE_BROKEN;
1388                     break;
1389                 }
1390             }
1391             buffer->NamedPipeState    = 0;  /* FIXME */
1392             buffer->ReadDataAvailable = avail;
1393             buffer->NumberOfMessages  = 0;  /* FIXME */
1394             buffer->MessageLength     = 0;  /* FIXME */
1395             io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1396             status = STATUS_SUCCESS;
1397             if (avail)
1398             {
1399                 ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1400                 if (data_size)
1401                 {
1402                     int res = recv( fd, buffer->Data, data_size, MSG_PEEK );
1403                     if (res >= 0) io->Information += res;
1404                 }
1405             }
1406             if (needs_close) close( fd );
1407         }
1408         break;
1409
1410     case FSCTL_PIPE_DISCONNECT:
1411         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1412                                     in_buffer, in_size, out_buffer, out_size );
1413         if (!status)
1414         {
1415             int fd = server_remove_fd_from_cache( handle );
1416             if (fd != -1) close( fd );
1417         }
1418         break;
1419
1420     case FSCTL_PIPE_IMPERSONATE:
1421         FIXME("FSCTL_PIPE_IMPERSONATE: impersonating self\n");
1422         status = RtlImpersonateSelf( SecurityImpersonation );
1423         break;
1424
1425     case FSCTL_LOCK_VOLUME:
1426     case FSCTL_UNLOCK_VOLUME:
1427         FIXME("stub! return success - Unsupported fsctl %x (device=%x access=%x func=%x method=%x)\n",
1428               code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1429         status = STATUS_SUCCESS;
1430         break;
1431
1432     case FSCTL_PIPE_LISTEN:
1433     case FSCTL_PIPE_WAIT:
1434     default:
1435         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1436                                     in_buffer, in_size, out_buffer, out_size );
1437         break;
1438     }
1439
1440     if (status != STATUS_PENDING) io->u.Status = status;
1441     return status;
1442 }
1443
1444 /******************************************************************************
1445  *  NtSetVolumeInformationFile          [NTDLL.@]
1446  *  ZwSetVolumeInformationFile          [NTDLL.@]
1447  *
1448  * Set volume information for an open file handle.
1449  *
1450  * PARAMS
1451  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1452  *  IoStatusBlock      [O] Receives information about the operation on return
1453  *  FsInformation      [I] Source for volume information
1454  *  Length             [I] Size of FsInformation
1455  *  FsInformationClass [I] Type of volume information to set
1456  *
1457  * RETURNS
1458  *  Success: 0. IoStatusBlock is updated.
1459  *  Failure: An NTSTATUS error code describing the error.
1460  */
1461 NTSTATUS WINAPI NtSetVolumeInformationFile(
1462         IN HANDLE FileHandle,
1463         PIO_STATUS_BLOCK IoStatusBlock,
1464         PVOID FsInformation,
1465         ULONG Length,
1466         FS_INFORMATION_CLASS FsInformationClass)
1467 {
1468         FIXME("(%p,%p,%p,0x%08x,0x%08x) stub\n",
1469         FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
1470         return 0;
1471 }
1472
1473 /******************************************************************************
1474  *  NtQueryInformationFile              [NTDLL.@]
1475  *  ZwQueryInformationFile              [NTDLL.@]
1476  *
1477  * Get information about an open file handle.
1478  *
1479  * PARAMS
1480  *  hFile    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1481  *  io       [O] Receives information about the operation on return
1482  *  ptr      [O] Destination for file information
1483  *  len      [I] Size of FileInformation
1484  *  class    [I] Type of file information to get
1485  *
1486  * RETURNS
1487  *  Success: 0. IoStatusBlock and FileInformation are updated.
1488  *  Failure: An NTSTATUS error code describing the error.
1489  */
1490 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
1491                                         PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
1492 {
1493     static const size_t info_sizes[] =
1494     {
1495         0,
1496         sizeof(FILE_DIRECTORY_INFORMATION),            /* FileDirectoryInformation */
1497         sizeof(FILE_FULL_DIRECTORY_INFORMATION),       /* FileFullDirectoryInformation */
1498         sizeof(FILE_BOTH_DIRECTORY_INFORMATION),       /* FileBothDirectoryInformation */
1499         sizeof(FILE_BASIC_INFORMATION),                /* FileBasicInformation */
1500         sizeof(FILE_STANDARD_INFORMATION),             /* FileStandardInformation */
1501         sizeof(FILE_INTERNAL_INFORMATION),             /* FileInternalInformation */
1502         sizeof(FILE_EA_INFORMATION),                   /* FileEaInformation */
1503         sizeof(FILE_ACCESS_INFORMATION),               /* FileAccessInformation */
1504         sizeof(FILE_NAME_INFORMATION)-sizeof(WCHAR),   /* FileNameInformation */
1505         sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
1506         0,                                             /* FileLinkInformation */
1507         sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR),  /* FileNamesInformation */
1508         sizeof(FILE_DISPOSITION_INFORMATION),          /* FileDispositionInformation */
1509         sizeof(FILE_POSITION_INFORMATION),             /* FilePositionInformation */
1510         sizeof(FILE_FULL_EA_INFORMATION),              /* FileFullEaInformation */
1511         sizeof(FILE_MODE_INFORMATION),                 /* FileModeInformation */
1512         sizeof(FILE_ALIGNMENT_INFORMATION),            /* FileAlignmentInformation */
1513         sizeof(FILE_ALL_INFORMATION)-sizeof(WCHAR),    /* FileAllInformation */
1514         sizeof(FILE_ALLOCATION_INFORMATION),           /* FileAllocationInformation */
1515         sizeof(FILE_END_OF_FILE_INFORMATION),          /* FileEndOfFileInformation */
1516         0,                                             /* FileAlternateNameInformation */
1517         sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
1518         0,                                             /* FilePipeInformation */
1519         sizeof(FILE_PIPE_LOCAL_INFORMATION),           /* FilePipeLocalInformation */
1520         0,                                             /* FilePipeRemoteInformation */
1521         sizeof(FILE_MAILSLOT_QUERY_INFORMATION),       /* FileMailslotQueryInformation */
1522         0,                                             /* FileMailslotSetInformation */
1523         0,                                             /* FileCompressionInformation */
1524         0,                                             /* FileObjectIdInformation */
1525         0,                                             /* FileCompletionInformation */
1526         0,                                             /* FileMoveClusterInformation */
1527         0,                                             /* FileQuotaInformation */
1528         0,                                             /* FileReparsePointInformation */
1529         0,                                             /* FileNetworkOpenInformation */
1530         0,                                             /* FileAttributeTagInformation */
1531         0                                              /* FileTrackingInformation */
1532     };
1533
1534     struct stat st;
1535     int fd, needs_close = FALSE;
1536
1537     TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
1538
1539     io->Information = 0;
1540
1541     if (class <= 0 || class >= FileMaximumInformation)
1542         return io->u.Status = STATUS_INVALID_INFO_CLASS;
1543     if (!info_sizes[class])
1544     {
1545         FIXME("Unsupported class (%d)\n", class);
1546         return io->u.Status = STATUS_NOT_IMPLEMENTED;
1547     }
1548     if (len < info_sizes[class])
1549         return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
1550
1551     if (class != FilePipeLocalInformation)
1552     {
1553         if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, NULL )))
1554             return io->u.Status;
1555     }
1556
1557     switch (class)
1558     {
1559     case FileBasicInformation:
1560         {
1561             FILE_BASIC_INFORMATION *info = ptr;
1562
1563             if (fstat( fd, &st ) == -1)
1564                 io->u.Status = FILE_GetNtStatus();
1565             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1566                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1567             else
1568             {
1569                 if (S_ISDIR(st.st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1570                 else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1571                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1572                     info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1573                 RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime);
1574                 RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime);
1575                 RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime);
1576                 RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime);
1577 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1578                 info->CreationTime.QuadPart += st.st_mtim.tv_nsec / 100;
1579                 info->LastWriteTime.QuadPart += st.st_mtim.tv_nsec / 100;
1580 #endif
1581 #ifdef HAVE_STRUCT_STAT_ST_CTIM
1582                 info->ChangeTime.QuadPart += st.st_ctim.tv_nsec / 100;
1583 #endif
1584 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1585                 info->LastAccessTime.QuadPart += st.st_atim.tv_nsec / 100;
1586 #endif
1587             }
1588         }
1589         break;
1590     case FileStandardInformation:
1591         {
1592             FILE_STANDARD_INFORMATION *info = ptr;
1593
1594             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1595             else
1596             {
1597                 if ((info->Directory = S_ISDIR(st.st_mode)))
1598                 {
1599                     info->AllocationSize.QuadPart = 0;
1600                     info->EndOfFile.QuadPart      = 0;
1601                     info->NumberOfLinks           = 1;
1602                     info->DeletePending           = FALSE;
1603                 }
1604                 else
1605                 {
1606                     info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1607                     info->EndOfFile.QuadPart      = st.st_size;
1608                     info->NumberOfLinks           = st.st_nlink;
1609                     info->DeletePending           = FALSE; /* FIXME */
1610                 }
1611             }
1612         }
1613         break;
1614     case FilePositionInformation:
1615         {
1616             FILE_POSITION_INFORMATION *info = ptr;
1617             off_t res = lseek( fd, 0, SEEK_CUR );
1618             if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
1619             else info->CurrentByteOffset.QuadPart = res;
1620         }
1621         break;
1622     case FileInternalInformation:
1623         {
1624             FILE_INTERNAL_INFORMATION *info = ptr;
1625
1626             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1627             else info->IndexNumber.QuadPart = st.st_ino;
1628         }
1629         break;
1630     case FileEaInformation:
1631         {
1632             FILE_EA_INFORMATION *info = ptr;
1633             info->EaSize = 0;
1634         }
1635         break;
1636     case FileEndOfFileInformation:
1637         {
1638             FILE_END_OF_FILE_INFORMATION *info = ptr;
1639
1640             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1641             else info->EndOfFile.QuadPart = S_ISDIR(st.st_mode) ? 0 : st.st_size;
1642         }
1643         break;
1644     case FileAllInformation:
1645         {
1646             FILE_ALL_INFORMATION *info = ptr;
1647
1648             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1649             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1650                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1651             else
1652             {
1653                 if ((info->StandardInformation.Directory = S_ISDIR(st.st_mode)))
1654                 {
1655                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1656                     info->StandardInformation.AllocationSize.QuadPart = 0;
1657                     info->StandardInformation.EndOfFile.QuadPart      = 0;
1658                     info->StandardInformation.NumberOfLinks           = 1;
1659                     info->StandardInformation.DeletePending           = FALSE;
1660                 }
1661                 else
1662                 {
1663                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1664                     info->StandardInformation.AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1665                     info->StandardInformation.EndOfFile.QuadPart      = st.st_size;
1666                     info->StandardInformation.NumberOfLinks           = st.st_nlink;
1667                     info->StandardInformation.DeletePending           = FALSE; /* FIXME */
1668                 }
1669                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1670                     info->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_READONLY;
1671                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.CreationTime);
1672                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.LastWriteTime);
1673                 RtlSecondsSince1970ToTime( st.st_ctime, &info->BasicInformation.ChangeTime);
1674                 RtlSecondsSince1970ToTime( st.st_atime, &info->BasicInformation.LastAccessTime);
1675 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1676                 info->BasicInformation.CreationTime.QuadPart += st.st_mtim.tv_nsec / 100;
1677                 info->BasicInformation.LastWriteTime.QuadPart += st.st_mtim.tv_nsec / 100;
1678 #endif
1679 #ifdef HAVE_STRUCT_STAT_ST_CTIM
1680                 info->BasicInformation.ChangeTime.QuadPart += st.st_ctim.tv_nsec / 100;
1681 #endif
1682 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1683                 info->BasicInformation.LastAccessTime.QuadPart += st.st_atim.tv_nsec / 100;
1684 #endif
1685                 info->InternalInformation.IndexNumber.QuadPart = st.st_ino;
1686                 info->EaInformation.EaSize = 0;
1687                 info->AccessInformation.AccessFlags = 0;  /* FIXME */
1688                 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
1689                 info->ModeInformation.Mode = 0;  /* FIXME */
1690                 info->AlignmentInformation.AlignmentRequirement = 1;  /* FIXME */
1691                 info->NameInformation.FileNameLength = 0;
1692                 io->Information = sizeof(*info) - sizeof(WCHAR);
1693             }
1694         }
1695         break;
1696     case FileMailslotQueryInformation:
1697         {
1698             FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
1699
1700             SERVER_START_REQ( set_mailslot_info )
1701             {
1702                 req->handle = wine_server_obj_handle( hFile );
1703                 req->flags = 0;
1704                 io->u.Status = wine_server_call( req );
1705                 if( io->u.Status == STATUS_SUCCESS )
1706                 {
1707                     info->MaximumMessageSize = reply->max_msgsize;
1708                     info->MailslotQuota = 0;
1709                     info->NextMessageSize = 0;
1710                     info->MessagesAvailable = 0;
1711                     info->ReadTimeout.QuadPart = reply->read_timeout;
1712                 }
1713             }
1714             SERVER_END_REQ;
1715             if (!io->u.Status)
1716             {
1717                 char *tmpbuf;
1718                 ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000;
1719                 if (size > 0x10000) size = 0x10000;
1720                 if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
1721                 {
1722                     int fd, needs_close;
1723                     if (!server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
1724                     {
1725                         int res = recv( fd, tmpbuf, size, MSG_PEEK );
1726                         info->MessagesAvailable = (res > 0);
1727                         info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE;
1728                         if (needs_close) close( fd );
1729                     }
1730                     RtlFreeHeap( GetProcessHeap(), 0, tmpbuf );
1731                 }
1732             }
1733         }
1734         break;
1735     case FilePipeLocalInformation:
1736         {
1737             FILE_PIPE_LOCAL_INFORMATION* pli = ptr;
1738
1739             SERVER_START_REQ( get_named_pipe_info )
1740             {
1741                 req->handle = wine_server_obj_handle( hFile );
1742                 if (!(io->u.Status = wine_server_call( req )))
1743                 {
1744                     pli->NamedPipeType = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ? 
1745                         FILE_PIPE_TYPE_MESSAGE : FILE_PIPE_TYPE_BYTE;
1746                     pli->NamedPipeConfiguration = 0; /* FIXME */
1747                     pli->MaximumInstances = reply->maxinstances;
1748                     pli->CurrentInstances = reply->instances;
1749                     pli->InboundQuota = reply->insize;
1750                     pli->ReadDataAvailable = 0; /* FIXME */
1751                     pli->OutboundQuota = reply->outsize;
1752                     pli->WriteQuotaAvailable = 0; /* FIXME */
1753                     pli->NamedPipeState = 0; /* FIXME */
1754                     pli->NamedPipeEnd = (reply->flags & NAMED_PIPE_SERVER_END) ?
1755                         FILE_PIPE_SERVER_END : FILE_PIPE_CLIENT_END;
1756                 }
1757             }
1758             SERVER_END_REQ;
1759         }
1760         break;
1761     default:
1762         FIXME("Unsupported class (%d)\n", class);
1763         io->u.Status = STATUS_NOT_IMPLEMENTED;
1764         break;
1765     }
1766     if (needs_close) close( fd );
1767     if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
1768     return io->u.Status;
1769 }
1770
1771 /******************************************************************************
1772  *  NtSetInformationFile                [NTDLL.@]
1773  *  ZwSetInformationFile                [NTDLL.@]
1774  *
1775  * Set information about an open file handle.
1776  *
1777  * PARAMS
1778  *  handle  [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1779  *  io      [O] Receives information about the operation on return
1780  *  ptr     [I] Source for file information
1781  *  len     [I] Size of FileInformation
1782  *  class   [I] Type of file information to set
1783  *
1784  * RETURNS
1785  *  Success: 0. io is updated.
1786  *  Failure: An NTSTATUS error code describing the error.
1787  */
1788 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
1789                                      PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
1790 {
1791     int fd, needs_close;
1792
1793     TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", handle, io, ptr, len, class);
1794
1795     io->u.Status = STATUS_SUCCESS;
1796     switch (class)
1797     {
1798     case FileBasicInformation:
1799         if (len >= sizeof(FILE_BASIC_INFORMATION))
1800         {
1801             struct stat st;
1802             const FILE_BASIC_INFORMATION *info = ptr;
1803
1804             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1805                 return io->u.Status;
1806
1807             if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
1808             {
1809                 ULONGLONG sec, nsec;
1810                 struct timeval tv[2];
1811
1812                 if (!info->LastAccessTime.QuadPart || !info->LastWriteTime.QuadPart)
1813                 {
1814
1815                     tv[0].tv_sec = tv[0].tv_usec = 0;
1816                     tv[1].tv_sec = tv[1].tv_usec = 0;
1817                     if (!fstat( fd, &st ))
1818                     {
1819                         tv[0].tv_sec = st.st_atime;
1820                         tv[1].tv_sec = st.st_mtime;
1821                     }
1822                 }
1823                 if (info->LastAccessTime.QuadPart)
1824                 {
1825                     sec = RtlLargeIntegerDivide( info->LastAccessTime.QuadPart, 10000000, &nsec );
1826                     tv[0].tv_sec = sec - SECS_1601_TO_1970;
1827                     tv[0].tv_usec = (UINT)nsec / 10;
1828                 }
1829                 if (info->LastWriteTime.QuadPart)
1830                 {
1831                     sec = RtlLargeIntegerDivide( info->LastWriteTime.QuadPart, 10000000, &nsec );
1832                     tv[1].tv_sec = sec - SECS_1601_TO_1970;
1833                     tv[1].tv_usec = (UINT)nsec / 10;
1834                 }
1835                 if (futimes( fd, tv ) == -1) io->u.Status = FILE_GetNtStatus();
1836             }
1837
1838             if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
1839             {
1840                 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1841                 else
1842                 {
1843                     if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
1844                     {
1845                         if (S_ISDIR( st.st_mode))
1846                             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
1847                         else
1848                             st.st_mode &= ~0222; /* clear write permission bits */
1849                     }
1850                     else
1851                     {
1852                         /* add write permission only where we already have read permission */
1853                         st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
1854                     }
1855                     if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
1856                 }
1857             }
1858
1859             if (needs_close) close( fd );
1860         }
1861         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1862         break;
1863
1864     case FilePositionInformation:
1865         if (len >= sizeof(FILE_POSITION_INFORMATION))
1866         {
1867             const FILE_POSITION_INFORMATION *info = ptr;
1868
1869             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1870                 return io->u.Status;
1871
1872             if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
1873                 io->u.Status = FILE_GetNtStatus();
1874
1875             if (needs_close) close( fd );
1876         }
1877         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1878         break;
1879
1880     case FileEndOfFileInformation:
1881         if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
1882         {
1883             struct stat st;
1884             const FILE_END_OF_FILE_INFORMATION *info = ptr;
1885
1886             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1887                 return io->u.Status;
1888
1889             /* first try normal truncate */
1890             if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1891
1892             /* now check for the need to extend the file */
1893             if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
1894             {
1895                 static const char zero;
1896
1897                 /* extend the file one byte beyond the requested size and then truncate it */
1898                 /* this should work around ftruncate implementations that can't extend files */
1899                 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
1900                     ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1901             }
1902             io->u.Status = FILE_GetNtStatus();
1903
1904             if (needs_close) close( fd );
1905         }
1906         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1907         break;
1908
1909     case FileMailslotSetInformation:
1910         {
1911             FILE_MAILSLOT_SET_INFORMATION *info = ptr;
1912
1913             SERVER_START_REQ( set_mailslot_info )
1914             {
1915                 req->handle = wine_server_obj_handle( handle );
1916                 req->flags = MAILSLOT_SET_READ_TIMEOUT;
1917                 req->read_timeout = info->ReadTimeout.QuadPart;
1918                 io->u.Status = wine_server_call( req );
1919             }
1920             SERVER_END_REQ;
1921         }
1922         break;
1923
1924     case FileCompletionInformation:
1925         if (len >= sizeof(FILE_COMPLETION_INFORMATION))
1926         {
1927             FILE_COMPLETION_INFORMATION *info = ptr;
1928
1929             SERVER_START_REQ( set_completion_info )
1930             {
1931                 req->handle   = wine_server_obj_handle( handle );
1932                 req->chandle  = wine_server_obj_handle( info->CompletionPort );
1933                 req->ckey     = info->CompletionKey;
1934                 io->u.Status  = wine_server_call( req );
1935             }
1936             SERVER_END_REQ;
1937         } else
1938             io->u.Status = STATUS_INVALID_PARAMETER_3;
1939         break;
1940
1941     default:
1942         FIXME("Unsupported class (%d)\n", class);
1943         io->u.Status = STATUS_NOT_IMPLEMENTED;
1944         break;
1945     }
1946     io->Information = 0;
1947     return io->u.Status;
1948 }
1949
1950
1951 /******************************************************************************
1952  *              NtQueryFullAttributesFile   (NTDLL.@)
1953  */
1954 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
1955                                            FILE_NETWORK_OPEN_INFORMATION *info )
1956 {
1957     ANSI_STRING unix_name;
1958     NTSTATUS status;
1959
1960     if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN,
1961                                               !(attr->Attributes & OBJ_CASE_INSENSITIVE) )))
1962     {
1963         struct stat st;
1964
1965         if (stat( unix_name.Buffer, &st ) == -1)
1966             status = FILE_GetNtStatus();
1967         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1968             status = STATUS_INVALID_INFO_CLASS;
1969         else
1970         {
1971             if (S_ISDIR(st.st_mode))
1972             {
1973                 info->FileAttributes          = FILE_ATTRIBUTE_DIRECTORY;
1974                 info->AllocationSize.QuadPart = 0;
1975                 info->EndOfFile.QuadPart      = 0;
1976             }
1977             else
1978             {
1979                 info->FileAttributes          = FILE_ATTRIBUTE_ARCHIVE;
1980                 info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1981                 info->EndOfFile.QuadPart      = st.st_size;
1982             }
1983             if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1984                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1985             RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime );
1986             RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime );
1987             RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime );
1988             RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime );
1989             if (DIR_is_hidden_file( attr->ObjectName ))
1990                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1991         }
1992         RtlFreeAnsiString( &unix_name );
1993     }
1994     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
1995     return status;
1996 }
1997
1998
1999 /******************************************************************************
2000  *              NtQueryAttributesFile   (NTDLL.@)
2001  *              ZwQueryAttributesFile   (NTDLL.@)
2002  */
2003 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
2004 {
2005     FILE_NETWORK_OPEN_INFORMATION full_info;
2006     NTSTATUS status;
2007
2008     if (!(status = NtQueryFullAttributesFile( attr, &full_info )))
2009     {
2010         info->CreationTime.QuadPart   = full_info.CreationTime.QuadPart;
2011         info->LastAccessTime.QuadPart = full_info.LastAccessTime.QuadPart;
2012         info->LastWriteTime.QuadPart  = full_info.LastWriteTime.QuadPart;
2013         info->ChangeTime.QuadPart     = full_info.ChangeTime.QuadPart;
2014         info->FileAttributes          = full_info.FileAttributes;
2015     }
2016     return status;
2017 }
2018
2019
2020 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
2021 /* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */
2022 static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename,
2023                                             unsigned int flags )
2024 {
2025     if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename))
2026     {
2027         info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2028         /* Don't assume read-only, let the mount options set it below */
2029         info->Characteristics |= FILE_REMOVABLE_MEDIA;
2030     }
2031     else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) ||
2032              !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename))
2033     {
2034         info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2035         info->Characteristics |= FILE_REMOTE_DEVICE;
2036     }
2037     else if (!strcmp("procfs", fstypename))
2038         info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2039     else
2040         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2041
2042     if (flags & MNT_RDONLY)
2043         info->Characteristics |= FILE_READ_ONLY_DEVICE;
2044
2045     if (!(flags & MNT_LOCAL))
2046     {
2047         info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2048         info->Characteristics |= FILE_REMOTE_DEVICE;
2049     }
2050 }
2051 #endif
2052
2053 static inline int is_device_placeholder( int fd )
2054 {
2055     static const char wine_placeholder[] = "Wine device placeholder";
2056     char buffer[sizeof(wine_placeholder)-1];
2057
2058     if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
2059         return 0;
2060     return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
2061 }
2062
2063 /******************************************************************************
2064  *              get_device_info
2065  *
2066  * Implementation of the FileFsDeviceInformation query for NtQueryVolumeInformationFile.
2067  */
2068 static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
2069 {
2070     struct stat st;
2071
2072     info->Characteristics = 0;
2073     if (fstat( fd, &st ) < 0) return FILE_GetNtStatus();
2074     if (S_ISCHR( st.st_mode ))
2075     {
2076         info->DeviceType = FILE_DEVICE_UNKNOWN;
2077 #ifdef linux
2078         switch(major(st.st_rdev))
2079         {
2080         case MEM_MAJOR:
2081             info->DeviceType = FILE_DEVICE_NULL;
2082             break;
2083         case TTY_MAJOR:
2084             info->DeviceType = FILE_DEVICE_SERIAL_PORT;
2085             break;
2086         case LP_MAJOR:
2087             info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
2088             break;
2089         case SCSI_TAPE_MAJOR:
2090             info->DeviceType = FILE_DEVICE_TAPE;
2091             break;
2092         }
2093 #endif
2094     }
2095     else if (S_ISBLK( st.st_mode ))
2096     {
2097         info->DeviceType = FILE_DEVICE_DISK;
2098     }
2099     else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
2100     {
2101         info->DeviceType = FILE_DEVICE_NAMED_PIPE;
2102     }
2103     else if (is_device_placeholder( fd ))
2104     {
2105         info->DeviceType = FILE_DEVICE_DISK;
2106     }
2107     else  /* regular file or directory */
2108     {
2109 #if defined(linux) && defined(HAVE_FSTATFS)
2110         struct statfs stfs;
2111
2112         /* check for floppy disk */
2113         if (major(st.st_dev) == FLOPPY_MAJOR)
2114             info->Characteristics |= FILE_REMOVABLE_MEDIA;
2115
2116         if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
2117         switch (stfs.f_type)
2118         {
2119         case 0x9660:      /* iso9660 */
2120         case 0x9fa1:      /* supermount */
2121         case 0x15013346:  /* udf */
2122             info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2123             info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2124             break;
2125         case 0x6969:  /* nfs */
2126         case 0x517B:  /* smbfs */
2127         case 0x564c:  /* ncpfs */
2128             info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2129             info->Characteristics |= FILE_REMOTE_DEVICE;
2130             break;
2131         case 0x01021994:  /* tmpfs */
2132         case 0x28cd3d45:  /* cramfs */
2133         case 0x1373:      /* devfs */
2134         case 0x9fa0:      /* procfs */
2135             info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2136             break;
2137         default:
2138             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2139             break;
2140         }
2141 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__APPLE__)
2142         struct statfs stfs;
2143
2144         if (fstatfs( fd, &stfs ) < 0)
2145             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2146         else
2147             get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags );
2148 #elif defined(__NetBSD__)
2149         struct statvfs stfs;
2150
2151         if (fstatvfs( fd, &stfs) < 0)
2152             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2153         else
2154             get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag );
2155 #elif defined(sun)
2156         /* Use dkio to work out device types */
2157         {
2158 # include <sys/dkio.h>
2159 # include <sys/vtoc.h>
2160             struct dk_cinfo dkinf;
2161             int retval = ioctl(fd, DKIOCINFO, &dkinf);
2162             if(retval==-1){
2163                 WARN("Unable to get disk device type information - assuming a disk like device\n");
2164                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2165             }
2166             switch (dkinf.dki_ctype)
2167             {
2168             case DKC_CDROM:
2169                 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2170                 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2171                 break;
2172             case DKC_NCRFLOPPY:
2173             case DKC_SMSFLOPPY:
2174             case DKC_INTEL82072:
2175             case DKC_INTEL82077:
2176                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2177                 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2178                 break;
2179             case DKC_MD:
2180                 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2181                 break;
2182             default:
2183                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2184             }
2185         }
2186 #else
2187         static int warned;
2188         if (!warned++) FIXME( "device info not properly supported on this platform\n" );
2189         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2190 #endif
2191         info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
2192     }
2193     return STATUS_SUCCESS;
2194 }
2195
2196
2197 /******************************************************************************
2198  *  NtQueryVolumeInformationFile                [NTDLL.@]
2199  *  ZwQueryVolumeInformationFile                [NTDLL.@]
2200  *
2201  * Get volume information for an open file handle.
2202  *
2203  * PARAMS
2204  *  handle      [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2205  *  io          [O] Receives information about the operation on return
2206  *  buffer      [O] Destination for volume information
2207  *  length      [I] Size of FsInformation
2208  *  info_class  [I] Type of volume information to set
2209  *
2210  * RETURNS
2211  *  Success: 0. io and buffer are updated.
2212  *  Failure: An NTSTATUS error code describing the error.
2213  */
2214 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
2215                                               PVOID buffer, ULONG length,
2216                                               FS_INFORMATION_CLASS info_class )
2217 {
2218     int fd, needs_close;
2219     struct stat st;
2220
2221     if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
2222         return io->u.Status;
2223
2224     io->u.Status = STATUS_NOT_IMPLEMENTED;
2225     io->Information = 0;
2226
2227     switch( info_class )
2228     {
2229     case FileFsVolumeInformation:
2230         FIXME( "%p: volume info not supported\n", handle );
2231         break;
2232     case FileFsLabelInformation:
2233         FIXME( "%p: label info not supported\n", handle );
2234         break;
2235     case FileFsSizeInformation:
2236         if (length < sizeof(FILE_FS_SIZE_INFORMATION))
2237             io->u.Status = STATUS_BUFFER_TOO_SMALL;
2238         else
2239         {
2240             FILE_FS_SIZE_INFORMATION *info = buffer;
2241
2242             if (fstat( fd, &st ) < 0)
2243             {
2244                 io->u.Status = FILE_GetNtStatus();
2245                 break;
2246             }
2247             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2248             {
2249                 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
2250             }
2251             else
2252             {
2253                 ULONGLONG bsize;
2254                 /* Linux's fstatvfs is buggy */
2255 #if !defined(linux) || !defined(HAVE_FSTATFS)
2256                 struct statvfs stfs;
2257
2258                 if (fstatvfs( fd, &stfs ) < 0)
2259                 {
2260                     io->u.Status = FILE_GetNtStatus();
2261                     break;
2262                 }
2263                 bsize = stfs.f_frsize;
2264 #else
2265                 struct statfs stfs;
2266                 if (fstatfs( fd, &stfs ) < 0)
2267                 {
2268                     io->u.Status = FILE_GetNtStatus();
2269                     break;
2270                 }
2271                 bsize = stfs.f_bsize;
2272 #endif
2273                 if (bsize == 2048)  /* assume CD-ROM */
2274                 {
2275                     info->BytesPerSector = 2048;
2276                     info->SectorsPerAllocationUnit = 1;
2277                 }
2278                 else
2279                 {
2280                     info->BytesPerSector = 512;
2281                     info->SectorsPerAllocationUnit = 8;
2282                 }
2283                 info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2284                 info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2285                 io->Information = sizeof(*info);
2286                 io->u.Status = STATUS_SUCCESS;
2287             }
2288         }
2289         break;
2290     case FileFsDeviceInformation:
2291         if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
2292             io->u.Status = STATUS_BUFFER_TOO_SMALL;
2293         else
2294         {
2295             FILE_FS_DEVICE_INFORMATION *info = buffer;
2296
2297             if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS)
2298                 io->Information = sizeof(*info);
2299         }
2300         break;
2301     case FileFsAttributeInformation:
2302         FIXME( "%p: attribute info not supported\n", handle );
2303         break;
2304     case FileFsControlInformation:
2305         FIXME( "%p: control info not supported\n", handle );
2306         break;
2307     case FileFsFullSizeInformation:
2308         FIXME( "%p: full size info not supported\n", handle );
2309         break;
2310     case FileFsObjectIdInformation:
2311         FIXME( "%p: object id info not supported\n", handle );
2312         break;
2313     case FileFsMaximumInformation:
2314         FIXME( "%p: maximum info not supported\n", handle );
2315         break;
2316     default:
2317         io->u.Status = STATUS_INVALID_PARAMETER;
2318         break;
2319     }
2320     if (needs_close) close( fd );
2321     return io->u.Status;
2322 }
2323
2324
2325 /******************************************************************
2326  *              NtQueryEaFile  (NTDLL.@)
2327  *
2328  * Read extended attributes from NTFS files.
2329  *
2330  * PARAMS
2331  *  hFile         [I] File handle, must be opened with FILE_READ_EA access
2332  *  iosb          [O] Receives information about the operation on return
2333  *  buffer        [O] Output buffer
2334  *  length        [I] Length of output buffer
2335  *  single_entry  [I] Only read and return one entry
2336  *  ea_list       [I] Optional list with names of EAs to return
2337  *  ea_list_len   [I] Length of ea_list in bytes
2338  *  ea_index      [I] Optional pointer to 1-based index of attribute to return
2339  *  restart       [I] restart EA scan
2340  *
2341  * RETURNS
2342  *  Success: 0. Atrributes read into buffer
2343  *  Failure: An NTSTATUS error code describing the error.
2344  */
2345 NTSTATUS WINAPI NtQueryEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length,
2346                                BOOLEAN single_entry, PVOID ea_list, ULONG ea_list_len,
2347                                PULONG ea_index, BOOLEAN restart )
2348 {
2349     FIXME("(%p,%p,%p,%d,%d,%p,%d,%p,%d) stub\n",
2350             hFile, iosb, buffer, length, single_entry, ea_list,
2351             ea_list_len, ea_index, restart);
2352     return STATUS_ACCESS_DENIED;
2353 }
2354
2355
2356 /******************************************************************
2357  *              NtSetEaFile  (NTDLL.@)
2358  *
2359  * Update extended attributes for NTFS files.
2360  *
2361  * PARAMS
2362  *  hFile         [I] File handle, must be opened with FILE_READ_EA access
2363  *  iosb          [O] Receives information about the operation on return
2364  *  buffer        [I] Buffer with EA information
2365  *  length        [I] Length of buffer
2366  *
2367  * RETURNS
2368  *  Success: 0. Attributes are updated
2369  *  Failure: An NTSTATUS error code describing the error.
2370  */
2371 NTSTATUS WINAPI NtSetEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length )
2372 {
2373     FIXME("(%p,%p,%p,%d) stub\n", hFile, iosb, buffer, length);
2374     return STATUS_ACCESS_DENIED;
2375 }
2376
2377
2378 /******************************************************************
2379  *              NtFlushBuffersFile  (NTDLL.@)
2380  *
2381  * Flush any buffered data on an open file handle.
2382  *
2383  * PARAMS
2384  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2385  *  IoStatusBlock      [O] Receives information about the operation on return
2386  *
2387  * RETURNS
2388  *  Success: 0. IoStatusBlock is updated.
2389  *  Failure: An NTSTATUS error code describing the error.
2390  */
2391 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
2392 {
2393     NTSTATUS ret;
2394     HANDLE hEvent = NULL;
2395
2396     SERVER_START_REQ( flush_file )
2397     {
2398         req->handle = wine_server_obj_handle( hFile );
2399         ret = wine_server_call( req );
2400         hEvent = wine_server_ptr_handle( reply->event );
2401     }
2402     SERVER_END_REQ;
2403     if (!ret && hEvent)
2404     {
2405         ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
2406         NtClose( hEvent );
2407     }
2408     return ret;
2409 }
2410
2411 /******************************************************************
2412  *              NtLockFile       (NTDLL.@)
2413  *
2414  *
2415  */
2416 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
2417                             PIO_APC_ROUTINE apc, void* apc_user,
2418                             PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
2419                             PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
2420                             BOOLEAN exclusive )
2421 {
2422     NTSTATUS    ret;
2423     HANDLE      handle;
2424     BOOLEAN     async;
2425     static BOOLEAN     warn = TRUE;
2426
2427     if (apc || io_status || key)
2428     {
2429         FIXME("Unimplemented yet parameter\n");
2430         return STATUS_NOT_IMPLEMENTED;
2431     }
2432
2433     if (apc_user && warn)
2434     {
2435         FIXME("I/O completion on lock not implemented yet\n");
2436         warn = FALSE;
2437     }
2438
2439     for (;;)
2440     {
2441         SERVER_START_REQ( lock_file )
2442         {
2443             req->handle      = wine_server_obj_handle( hFile );
2444             req->offset      = offset->QuadPart;
2445             req->count       = count->QuadPart;
2446             req->shared      = !exclusive;
2447             req->wait        = !dont_wait;
2448             ret = wine_server_call( req );
2449             handle = wine_server_ptr_handle( reply->handle );
2450             async  = reply->overlapped;
2451         }
2452         SERVER_END_REQ;
2453         if (ret != STATUS_PENDING)
2454         {
2455             if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
2456             return ret;
2457         }
2458
2459         if (async)
2460         {
2461             FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
2462             if (handle) NtClose( handle );
2463             return STATUS_PENDING;
2464         }
2465         if (handle)
2466         {
2467             NtWaitForSingleObject( handle, FALSE, NULL );
2468             NtClose( handle );
2469         }
2470         else
2471         {
2472             LARGE_INTEGER time;
2473     
2474             /* Unix lock conflict, sleep a bit and retry */
2475             time.QuadPart = 100 * (ULONGLONG)10000;
2476             time.QuadPart = -time.QuadPart;
2477             NtDelayExecution( FALSE, &time );
2478         }
2479     }
2480 }
2481
2482
2483 /******************************************************************
2484  *              NtUnlockFile    (NTDLL.@)
2485  *
2486  *
2487  */
2488 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
2489                               PLARGE_INTEGER offset, PLARGE_INTEGER count,
2490                               PULONG key )
2491 {
2492     NTSTATUS status;
2493
2494     TRACE( "%p %x%08x %x%08x\n",
2495            hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
2496
2497     if (io_status || key)
2498     {
2499         FIXME("Unimplemented yet parameter\n");
2500         return STATUS_NOT_IMPLEMENTED;
2501     }
2502
2503     SERVER_START_REQ( unlock_file )
2504     {
2505         req->handle = wine_server_obj_handle( hFile );
2506         req->offset = offset->QuadPart;
2507         req->count  = count->QuadPart;
2508         status = wine_server_call( req );
2509     }
2510     SERVER_END_REQ;
2511     return status;
2512 }
2513
2514 /******************************************************************
2515  *              NtCreateNamedPipeFile    (NTDLL.@)
2516  *
2517  *
2518  */
2519 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
2520                                        POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
2521                                        ULONG sharing, ULONG dispo, ULONG options,
2522                                        ULONG pipe_type, ULONG read_mode, 
2523                                        ULONG completion_mode, ULONG max_inst,
2524                                        ULONG inbound_quota, ULONG outbound_quota,
2525                                        PLARGE_INTEGER timeout)
2526 {
2527     NTSTATUS    status;
2528
2529     TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n",
2530           handle, access, debugstr_w(attr->ObjectName->Buffer), iosb, sharing, dispo,
2531           options, pipe_type, read_mode, completion_mode, max_inst, inbound_quota,
2532           outbound_quota, timeout);
2533
2534     /* assume we only get relative timeout */
2535     if (timeout->QuadPart > 0)
2536         FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
2537
2538     SERVER_START_REQ( create_named_pipe )
2539     {
2540         req->access  = access;
2541         req->attributes = attr->Attributes;
2542         req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2543         req->options = options;
2544         req->flags = 
2545             (pipe_type) ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0 |
2546             (read_mode) ? NAMED_PIPE_MESSAGE_STREAM_READ  : 0 |
2547             (completion_mode) ? NAMED_PIPE_NONBLOCKING_MODE  : 0;
2548         req->maxinstances = max_inst;
2549         req->outsize = outbound_quota;
2550         req->insize  = inbound_quota;
2551         req->timeout = timeout->QuadPart;
2552         wine_server_add_data( req, attr->ObjectName->Buffer,
2553                               attr->ObjectName->Length );
2554         status = wine_server_call( req );
2555         if (!status) *handle = wine_server_ptr_handle( reply->handle );
2556     }
2557     SERVER_END_REQ;
2558     return status;
2559 }
2560
2561 /******************************************************************
2562  *              NtDeleteFile    (NTDLL.@)
2563  *
2564  *
2565  */
2566 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
2567 {
2568     NTSTATUS status;
2569     HANDLE hFile;
2570     IO_STATUS_BLOCK io;
2571
2572     TRACE("%p\n", ObjectAttributes);
2573     status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE | DELETE,
2574                            ObjectAttributes, &io, NULL, 0,
2575                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
2576                            FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
2577     if (status == STATUS_SUCCESS) status = NtClose(hFile);
2578     return status;
2579 }
2580
2581 /******************************************************************
2582  *              NtCancelIoFile    (NTDLL.@)
2583  *
2584  *
2585  */
2586 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
2587 {
2588     LARGE_INTEGER timeout;
2589
2590     TRACE("%p %p\n", hFile, io_status );
2591
2592     SERVER_START_REQ( cancel_async )
2593     {
2594         req->handle = wine_server_obj_handle( hFile );
2595         wine_server_call( req );
2596     }
2597     SERVER_END_REQ;
2598     /* Let some APC be run, so that we can run the remaining APCs on hFile
2599      * either the cancelation of the pending one, but also the execution
2600      * of the queued APC, but not yet run. This is needed to ensure proper
2601      * clean-up of allocated data.
2602      */
2603     timeout.u.LowPart = timeout.u.HighPart = 0;
2604     return io_status->u.Status = NtDelayExecution( TRUE, &timeout );
2605 }
2606
2607 /******************************************************************************
2608  *  NtCreateMailslotFile        [NTDLL.@]
2609  *  ZwCreateMailslotFile        [NTDLL.@]
2610  *
2611  * PARAMS
2612  *  pHandle          [O] pointer to receive the handle created
2613  *  DesiredAccess    [I] access mode (read, write, etc)
2614  *  ObjectAttributes [I] fully qualified NT path of the mailslot
2615  *  IoStatusBlock    [O] receives completion status and other info
2616  *  CreateOptions    [I]
2617  *  MailslotQuota    [I]
2618  *  MaxMessageSize   [I]
2619  *  TimeOut          [I]
2620  *
2621  * RETURNS
2622  *  An NT status code
2623  */
2624 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
2625      POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
2626      ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
2627      PLARGE_INTEGER TimeOut)
2628 {
2629     LARGE_INTEGER timeout;
2630     NTSTATUS ret;
2631
2632     TRACE("%p %08x %p %p %08x %08x %08x %p\n",
2633               pHandle, DesiredAccess, attr, IoStatusBlock,
2634               CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
2635
2636     if (!pHandle) return STATUS_ACCESS_VIOLATION;
2637     if (!attr) return STATUS_INVALID_PARAMETER;
2638     if (!attr->ObjectName) return STATUS_OBJECT_PATH_SYNTAX_BAD;
2639
2640     /*
2641      *  For a NULL TimeOut pointer set the default timeout value
2642      */
2643     if  (!TimeOut)
2644         timeout.QuadPart = -1;
2645     else
2646         timeout.QuadPart = TimeOut->QuadPart;
2647
2648     SERVER_START_REQ( create_mailslot )
2649     {
2650         req->access = DesiredAccess;
2651         req->attributes = attr->Attributes;
2652         req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2653         req->max_msgsize = MaxMessageSize;
2654         req->read_timeout = timeout.QuadPart;
2655         wine_server_add_data( req, attr->ObjectName->Buffer,
2656                               attr->ObjectName->Length );
2657         ret = wine_server_call( req );
2658         if( ret == STATUS_SUCCESS )
2659             *pHandle = wine_server_ptr_handle( reply->handle );
2660     }
2661     SERVER_END_REQ;
2662  
2663     return ret;
2664 }