server: Specify the user APC to call only once the system APC has executed.
[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 (type == FD_TYPE_FILE && offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */ )
572     {
573         /* async I/O doesn't make sense on regular files */
574         while ((result = pread( unix_handle, buffer, length, offset->QuadPart )) == -1)
575         {
576             if (errno != EINTR)
577             {
578                 status = FILE_GetNtStatus();
579                 goto done;
580             }
581         }
582         if (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
583             /* update file pointer position */
584             lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
585
586         total = result;
587         status = total ? STATUS_SUCCESS : STATUS_END_OF_FILE;
588         goto done;
589     }
590
591     for (;;)
592     {
593         if ((result = read( unix_handle, (char *)buffer + total, length - total )) >= 0)
594         {
595             total += result;
596             if (!result || total == length)
597             {
598                 if (total)
599                 {
600                     status = STATUS_SUCCESS;
601                     goto done;
602                 }
603                 switch (type)
604                 {
605                 case FD_TYPE_FILE:
606                 case FD_TYPE_CHAR:
607                     status = STATUS_END_OF_FILE;
608                     goto done;
609                 case FD_TYPE_SERIAL:
610                     break;
611                 default:
612                     status = STATUS_PIPE_BROKEN;
613                     goto done;
614                 }
615             }
616             else if (type == FD_TYPE_FILE) continue;  /* no async I/O on regular files */
617         }
618         else
619         {
620             if (errno == EINTR) continue;
621             if (errno != EAGAIN)
622             {
623                 status = FILE_GetNtStatus();
624                 goto done;
625             }
626         }
627
628         if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
629         {
630             async_fileio_read *fileio;
631             BOOL avail_mode;
632
633             if ((status = get_io_avail_mode( hFile, type, &avail_mode )))
634                 goto err;
635             if (total && avail_mode)
636             {
637                 status = STATUS_SUCCESS;
638                 goto done;
639             }
640
641             if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio))))
642             {
643                 status = STATUS_NO_MEMORY;
644                 goto err;
645             }
646             fileio->io.handle  = hFile;
647             fileio->io.apc     = apc;
648             fileio->io.apc_arg = apc_user;
649             fileio->already = total;
650             fileio->count = length;
651             fileio->buffer = buffer;
652             fileio->avail_mode = avail_mode;
653
654             SERVER_START_REQ( register_async )
655             {
656                 req->type   = ASYNC_TYPE_READ;
657                 req->count  = length;
658                 req->async.handle   = wine_server_obj_handle( hFile );
659                 req->async.event    = wine_server_obj_handle( hEvent );
660                 req->async.callback = FILE_AsyncReadService;
661                 req->async.iosb     = io_status;
662                 req->async.arg      = fileio;
663                 req->async.cvalue   = cvalue;
664                 status = wine_server_call( req );
665             }
666             SERVER_END_REQ;
667
668             if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
669             goto err;
670         }
671         else  /* synchronous read, wait for the fd to become ready */
672         {
673             struct pollfd pfd;
674             int ret, timeout;
675
676             if (!timeout_init_done)
677             {
678                 timeout_init_done = 1;
679                 if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts )))
680                     goto err;
681                 if (hEvent) NtResetEvent( hEvent, NULL );
682             }
683             timeout = get_next_io_timeout( &timeouts, total );
684
685             pfd.fd = unix_handle;
686             pfd.events = POLLIN;
687
688             if (!timeout || !(ret = poll( &pfd, 1, timeout )))
689             {
690                 if (total)  /* return with what we got so far */
691                     status = STATUS_SUCCESS;
692                 else
693                     status = (type == FD_TYPE_MAILSLOT) ? STATUS_IO_TIMEOUT : STATUS_TIMEOUT;
694                 goto done;
695             }
696             if (ret == -1 && errno != EINTR)
697             {
698                 status = FILE_GetNtStatus();
699                 goto done;
700             }
701             /* will now restart the read */
702         }
703     }
704
705 done:
706     if (cvalue) NTDLL_AddCompletion( hFile, cvalue, status, total );
707
708 err:
709     if (needs_close) close( unix_handle );
710     if (status == STATUS_SUCCESS)
711     {
712         io_status->u.Status = status;
713         io_status->Information = total;
714         TRACE("= SUCCESS (%u)\n", total);
715         if (hEvent) NtSetEvent( hEvent, NULL );
716         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
717                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
718     }
719     else
720     {
721         TRACE("= 0x%08x\n", status);
722         if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
723     }
724     return status;
725 }
726
727
728 /******************************************************************************
729  *  NtReadFileScatter   [NTDLL.@]
730  *  ZwReadFileScatter   [NTDLL.@]
731  */
732 NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
733                                    PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
734                                    ULONG length, PLARGE_INTEGER offset, PULONG key )
735 {
736     size_t page_size = getpagesize();
737     int result, unix_handle, needs_close;
738     unsigned int options;
739     NTSTATUS status;
740     ULONG pos = 0, total = 0;
741     enum server_fd_type type;
742     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
743
744     TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
745            file, event, apc, apc_user, io_status, segments, length, offset, key);
746
747     if (length % page_size) return STATUS_INVALID_PARAMETER;
748     if (!io_status) return STATUS_ACCESS_VIOLATION;
749
750     status = server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
751                                  &needs_close, &type, &options );
752     if (status) return status;
753
754     if ((type != FD_TYPE_FILE) ||
755         (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
756         !(options & FILE_NO_INTERMEDIATE_BUFFERING))
757     {
758         status = STATUS_INVALID_PARAMETER;
759         goto error;
760     }
761
762     while (length)
763     {
764         if (offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */)
765             result = pread( unix_handle, (char *)segments->Buffer + pos,
766                             page_size - pos, offset->QuadPart + total );
767         else
768             result = read( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
769
770         if (result == -1)
771         {
772             if (errno == EINTR) continue;
773             status = FILE_GetNtStatus();
774             break;
775         }
776         if (!result)
777         {
778             status = STATUS_END_OF_FILE;
779             break;
780         }
781         total += result;
782         length -= result;
783         if ((pos += result) == page_size)
784         {
785             pos = 0;
786             segments++;
787         }
788     }
789
790     if (cvalue) NTDLL_AddCompletion( file, cvalue, status, total );
791
792  error:
793     if (needs_close) close( unix_handle );
794     if (status == STATUS_SUCCESS)
795     {
796         io_status->u.Status = status;
797         io_status->Information = total;
798         TRACE("= SUCCESS (%u)\n", total);
799         if (event) NtSetEvent( event, NULL );
800         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
801                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
802     }
803     else
804     {
805         TRACE("= 0x%08x\n", status);
806         if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
807     }
808     return status;
809 }
810
811
812 /***********************************************************************
813  *             FILE_AsyncWriteService      (INTERNAL)
814  */
815 static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status, void **apc)
816 {
817     async_fileio_write *fileio = user;
818     int result, fd, needs_close;
819     enum server_fd_type type;
820
821     switch (status)
822     {
823     case STATUS_ALERTED:
824         /* write some data (non-blocking) */
825         if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
826                                           &needs_close, &type, NULL )))
827             break;
828
829         if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
830             result = send( fd, fileio->buffer, 0, 0 );
831         else
832             result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already );
833
834         if (needs_close) close( fd );
835
836         if (result < 0)
837         {
838             if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING;
839             else status = FILE_GetNtStatus();
840         }
841         else
842         {
843             fileio->already += result;
844             status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
845         }
846         break;
847
848     case STATUS_TIMEOUT:
849     case STATUS_IO_TIMEOUT:
850         if (fileio->already) status = STATUS_SUCCESS;
851         break;
852     }
853     if (status != STATUS_PENDING)
854     {
855         iosb->u.Status = status;
856         iosb->Information = fileio->already;
857         *apc = fileio_apc;
858     }
859     return status;
860 }
861
862 /******************************************************************************
863  *  NtWriteFile                                 [NTDLL.@]
864  *  ZwWriteFile                                 [NTDLL.@]
865  *
866  * Write to an open file handle.
867  *
868  * PARAMS
869  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
870  *  Event         [I] Event to signal upon completion (or NULL)
871  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
872  *  ApcContext    [I] Context for ApcRoutine (or NULL)
873  *  IoStatusBlock [O] Receives information about the operation on return
874  *  Buffer        [I] Source for the data to write
875  *  Length        [I] Size of Buffer
876  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
877  *  Key           [O] Function unknown (may be NULL)
878  *
879  * RETURNS
880  *  Success: 0. IoStatusBlock is updated, and the Information member contains
881  *           The number of bytes written.
882  *  Failure: An NTSTATUS error code describing the error.
883  */
884 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
885                             PIO_APC_ROUTINE apc, void* apc_user,
886                             PIO_STATUS_BLOCK io_status, 
887                             const void* buffer, ULONG length,
888                             PLARGE_INTEGER offset, PULONG key)
889 {
890     int result, unix_handle, needs_close, timeout_init_done = 0;
891     unsigned int options;
892     struct io_timeouts timeouts;
893     NTSTATUS status;
894     ULONG total = 0;
895     enum server_fd_type type;
896     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
897
898     TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)!\n",
899           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
900
901     if (!io_status) return STATUS_ACCESS_VIOLATION;
902
903     status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
904                                  &needs_close, &type, &options );
905     if (status) return status;
906
907     if (type == FD_TYPE_FILE && offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */ )
908     {
909         /* async I/O doesn't make sense on regular files */
910         while ((result = pwrite( unix_handle, buffer, length, offset->QuadPart )) == -1)
911         {
912             if (errno != EINTR)
913             {
914                 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
915                 else status = FILE_GetNtStatus();
916                 goto done;
917             }
918         }
919
920         if (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
921             /* update file pointer position */
922             lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
923
924         total = result;
925         status = STATUS_SUCCESS;
926         goto done;
927     }
928
929     for (;;)
930     {
931         /* zero-length writes on sockets may not work with plain write(2) */
932         if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
933             result = send( unix_handle, buffer, 0, 0 );
934         else
935             result = write( unix_handle, (const char *)buffer + total, length - total );
936
937         if (result >= 0)
938         {
939             total += result;
940             if (total == length)
941             {
942                 status = STATUS_SUCCESS;
943                 goto done;
944             }
945             if (type == FD_TYPE_FILE) continue;  /* no async I/O on regular files */
946         }
947         else
948         {
949             if (errno == EINTR) continue;
950             if (errno != EAGAIN)
951             {
952                 if (errno == EFAULT)
953                 {
954                     status = STATUS_INVALID_USER_BUFFER;
955                     goto err;
956                 }
957                 status = FILE_GetNtStatus();
958                 goto done;
959             }
960         }
961
962         if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
963         {
964             async_fileio_write *fileio;
965
966             if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio))))
967             {
968                 status = STATUS_NO_MEMORY;
969                 goto err;
970             }
971             fileio->io.handle  = hFile;
972             fileio->io.apc     = apc;
973             fileio->io.apc_arg = apc_user;
974             fileio->already = total;
975             fileio->count = length;
976             fileio->buffer = buffer;
977
978             SERVER_START_REQ( register_async )
979             {
980                 req->type   = ASYNC_TYPE_WRITE;
981                 req->count  = length;
982                 req->async.handle   = wine_server_obj_handle( hFile );
983                 req->async.event    = wine_server_obj_handle( hEvent );
984                 req->async.callback = FILE_AsyncWriteService;
985                 req->async.iosb     = io_status;
986                 req->async.arg      = fileio;
987                 req->async.cvalue   = cvalue;
988                 status = wine_server_call( req );
989             }
990             SERVER_END_REQ;
991
992             if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
993             goto err;
994         }
995         else  /* synchronous write, wait for the fd to become ready */
996         {
997             struct pollfd pfd;
998             int ret, timeout;
999
1000             if (!timeout_init_done)
1001             {
1002                 timeout_init_done = 1;
1003                 if ((status = get_io_timeouts( hFile, type, length, FALSE, &timeouts )))
1004                     goto err;
1005                 if (hEvent) NtResetEvent( hEvent, NULL );
1006             }
1007             timeout = get_next_io_timeout( &timeouts, total );
1008
1009             pfd.fd = unix_handle;
1010             pfd.events = POLLOUT;
1011
1012             if (!timeout || !(ret = poll( &pfd, 1, timeout )))
1013             {
1014                 /* return with what we got so far */
1015                 status = total ? STATUS_SUCCESS : STATUS_TIMEOUT;
1016                 goto done;
1017             }
1018             if (ret == -1 && errno != EINTR)
1019             {
1020                 status = FILE_GetNtStatus();
1021                 goto done;
1022             }
1023             /* will now restart the write */
1024         }
1025     }
1026
1027 done:
1028     if (cvalue) NTDLL_AddCompletion( hFile, cvalue, status, total );
1029
1030 err:
1031     if (needs_close) close( unix_handle );
1032     if (status == STATUS_SUCCESS)
1033     {
1034         io_status->u.Status = status;
1035         io_status->Information = total;
1036         TRACE("= SUCCESS (%u)\n", total);
1037         if (hEvent) NtSetEvent( hEvent, NULL );
1038         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1039                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1040     }
1041     else
1042     {
1043         TRACE("= 0x%08x\n", status);
1044         if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
1045     }
1046     return status;
1047 }
1048
1049
1050 /******************************************************************************
1051  *  NtWriteFileGather   [NTDLL.@]
1052  *  ZwWriteFileGather   [NTDLL.@]
1053  */
1054 NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1055                                    PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
1056                                    ULONG length, PLARGE_INTEGER offset, PULONG key )
1057 {
1058     size_t page_size = getpagesize();
1059     int result, unix_handle, needs_close;
1060     unsigned int options;
1061     NTSTATUS status;
1062     ULONG pos = 0, total = 0;
1063     enum server_fd_type type;
1064     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1065
1066     TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
1067            file, event, apc, apc_user, io_status, segments, length, offset, key);
1068
1069     if (length % page_size) return STATUS_INVALID_PARAMETER;
1070     if (!io_status) return STATUS_ACCESS_VIOLATION;
1071
1072     status = server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
1073                                  &needs_close, &type, &options );
1074     if (status) return status;
1075
1076     if ((type != FD_TYPE_FILE) ||
1077         (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
1078         !(options & FILE_NO_INTERMEDIATE_BUFFERING))
1079     {
1080         status = STATUS_INVALID_PARAMETER;
1081         goto error;
1082     }
1083
1084     while (length)
1085     {
1086         if (offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */)
1087             result = pwrite( unix_handle, (char *)segments->Buffer + pos,
1088                              page_size - pos, offset->QuadPart + total );
1089         else
1090             result = write( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
1091
1092         if (result == -1)
1093         {
1094             if (errno == EINTR) continue;
1095             if (errno == EFAULT)
1096             {
1097                 status = STATUS_INVALID_USER_BUFFER;
1098                 goto error;
1099             }
1100             status = FILE_GetNtStatus();
1101             break;
1102         }
1103         if (!result)
1104         {
1105             status = STATUS_DISK_FULL;
1106             break;
1107         }
1108         total += result;
1109         length -= result;
1110         if ((pos += result) == page_size)
1111         {
1112             pos = 0;
1113             segments++;
1114         }
1115     }
1116
1117     if (cvalue) NTDLL_AddCompletion( file, cvalue, status, total );
1118
1119  error:
1120     if (needs_close) close( unix_handle );
1121     if (status == STATUS_SUCCESS)
1122     {
1123         io_status->u.Status = status;
1124         io_status->Information = total;
1125         TRACE("= SUCCESS (%u)\n", total);
1126         if (event) NtSetEvent( event, NULL );
1127         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1128                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1129     }
1130     else
1131     {
1132         TRACE("= 0x%08x\n", status);
1133         if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
1134     }
1135     return status;
1136 }
1137
1138
1139 struct async_ioctl
1140 {
1141     HANDLE          handle;   /* handle to the device */
1142     HANDLE          event;    /* async event */
1143     void           *buffer;   /* buffer for output */
1144     ULONG           size;     /* size of buffer */
1145     PIO_APC_ROUTINE apc;      /* user apc params */
1146     void           *apc_arg;
1147 };
1148
1149 /* callback for ioctl user APC */
1150 static void WINAPI ioctl_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved )
1151 {
1152     struct async_ioctl *async = arg;
1153     if (async->apc) async->apc( async->apc_arg, io, reserved );
1154     RtlFreeHeap( GetProcessHeap(), 0, async );
1155 }
1156
1157 /* callback for ioctl async I/O completion */
1158 static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS status, void **apc )
1159 {
1160     struct async_ioctl *async = arg;
1161
1162     if (status == STATUS_ALERTED)
1163     {
1164         SERVER_START_REQ( get_ioctl_result )
1165         {
1166             req->handle   = wine_server_obj_handle( async->handle );
1167             req->user_arg = async;
1168             wine_server_set_reply( req, async->buffer, async->size );
1169             if (!(status = wine_server_call( req )))
1170                 io->Information = wine_server_reply_size( reply );
1171         }
1172         SERVER_END_REQ;
1173     }
1174     if (status != STATUS_PENDING)
1175     {
1176         io->u.Status = status;
1177         if (async->apc || async->event) *apc = ioctl_apc;
1178     }
1179     return status;
1180 }
1181
1182 /* do a ioctl call through the server */
1183 static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
1184                                    PIO_APC_ROUTINE apc, PVOID apc_context,
1185                                    IO_STATUS_BLOCK *io, ULONG code,
1186                                    const void *in_buffer, ULONG in_size,
1187                                    PVOID out_buffer, ULONG out_size )
1188 {
1189     struct async_ioctl *async;
1190     NTSTATUS status;
1191     HANDLE wait_handle;
1192     ULONG options;
1193     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
1194
1195     if (!(async = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*async) )))
1196         return STATUS_NO_MEMORY;
1197     async->handle  = handle;
1198     async->event   = event;
1199     async->buffer  = out_buffer;
1200     async->size    = out_size;
1201     async->apc     = apc;
1202     async->apc_arg = apc_context;
1203
1204     SERVER_START_REQ( ioctl )
1205     {
1206         req->code           = code;
1207         req->blocking       = !apc && !event;
1208         req->async.handle   = wine_server_obj_handle( handle );
1209         req->async.callback = ioctl_completion;
1210         req->async.iosb     = io;
1211         req->async.arg      = async;
1212         req->async.event    = wine_server_obj_handle( event );
1213         req->async.cvalue   = cvalue;
1214         wine_server_add_data( req, in_buffer, in_size );
1215         wine_server_set_reply( req, out_buffer, out_size );
1216         if (!(status = wine_server_call( req )))
1217             io->Information = wine_server_reply_size( reply );
1218         wait_handle = wine_server_ptr_handle( reply->wait );
1219         options     = reply->options;
1220     }
1221     SERVER_END_REQ;
1222
1223     if (status == STATUS_NOT_SUPPORTED)
1224         FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
1225               code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1226
1227     if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
1228
1229     if (wait_handle)
1230     {
1231         NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL );
1232         status = io->u.Status;
1233         NtClose( wait_handle );
1234         RtlFreeHeap( GetProcessHeap(), 0, async );
1235     }
1236
1237     return status;
1238 }
1239
1240
1241 /**************************************************************************
1242  *              NtDeviceIoControlFile                   [NTDLL.@]
1243  *              ZwDeviceIoControlFile                   [NTDLL.@]
1244  *
1245  * Perform an I/O control operation on an open file handle.
1246  *
1247  * PARAMS
1248  *  handle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1249  *  event          [I] Event to signal upon completion (or NULL)
1250  *  apc            [I] Callback to call upon completion (or NULL)
1251  *  apc_context    [I] Context for ApcRoutine (or NULL)
1252  *  io             [O] Receives information about the operation on return
1253  *  code           [I] Control code for the operation to perform
1254  *  in_buffer      [I] Source for any input data required (or NULL)
1255  *  in_size        [I] Size of InputBuffer
1256  *  out_buffer     [O] Source for any output data returned (or NULL)
1257  *  out_size       [I] Size of OutputBuffer
1258  *
1259  * RETURNS
1260  *  Success: 0. IoStatusBlock is updated.
1261  *  Failure: An NTSTATUS error code describing the error.
1262  */
1263 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
1264                                       PIO_APC_ROUTINE apc, PVOID apc_context,
1265                                       PIO_STATUS_BLOCK io, ULONG code,
1266                                       PVOID in_buffer, ULONG in_size,
1267                                       PVOID out_buffer, ULONG out_size)
1268 {
1269     ULONG device = (code >> 16);
1270     NTSTATUS status = STATUS_NOT_SUPPORTED;
1271
1272     TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1273           handle, event, apc, apc_context, io, code,
1274           in_buffer, in_size, out_buffer, out_size);
1275
1276     switch(device)
1277     {
1278     case FILE_DEVICE_DISK:
1279     case FILE_DEVICE_CD_ROM:
1280     case FILE_DEVICE_DVD:
1281     case FILE_DEVICE_CONTROLLER:
1282     case FILE_DEVICE_MASS_STORAGE:
1283         status = CDROM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1284                                        in_buffer, in_size, out_buffer, out_size);
1285         break;
1286     case FILE_DEVICE_SERIAL_PORT:
1287         status = COMM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1288                                       in_buffer, in_size, out_buffer, out_size);
1289         break;
1290     case FILE_DEVICE_TAPE:
1291         status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
1292                                       in_buffer, in_size, out_buffer, out_size);
1293         break;
1294     }
1295
1296     if (status == STATUS_NOT_SUPPORTED || status == STATUS_BAD_DEVICE_TYPE)
1297         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1298                                     in_buffer, in_size, out_buffer, out_size );
1299
1300     if (status != STATUS_PENDING) io->u.Status = status;
1301     return status;
1302 }
1303
1304
1305 /**************************************************************************
1306  *              NtFsControlFile                 [NTDLL.@]
1307  *              ZwFsControlFile                 [NTDLL.@]
1308  *
1309  * Perform a file system control operation on an open file handle.
1310  *
1311  * PARAMS
1312  *  handle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1313  *  event          [I] Event to signal upon completion (or NULL)
1314  *  apc            [I] Callback to call upon completion (or NULL)
1315  *  apc_context    [I] Context for ApcRoutine (or NULL)
1316  *  io             [O] Receives information about the operation on return
1317  *  code           [I] Control code for the operation to perform
1318  *  in_buffer      [I] Source for any input data required (or NULL)
1319  *  in_size        [I] Size of InputBuffer
1320  *  out_buffer     [O] Source for any output data returned (or NULL)
1321  *  out_size       [I] Size of OutputBuffer
1322  *
1323  * RETURNS
1324  *  Success: 0. IoStatusBlock is updated.
1325  *  Failure: An NTSTATUS error code describing the error.
1326  */
1327 NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
1328                                 PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code,
1329                                 PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size)
1330 {
1331     NTSTATUS status;
1332
1333     TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1334           handle, event, apc, apc_context, io, code,
1335           in_buffer, in_size, out_buffer, out_size);
1336
1337     if (!io) return STATUS_INVALID_PARAMETER;
1338
1339     switch(code)
1340     {
1341     case FSCTL_DISMOUNT_VOLUME:
1342         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1343                                     in_buffer, in_size, out_buffer, out_size );
1344         if (!status) status = DIR_unmount_device( handle );
1345         break;
1346
1347     case FSCTL_PIPE_PEEK:
1348         {
1349             FILE_PIPE_PEEK_BUFFER *buffer = out_buffer;
1350             int avail = 0, fd, needs_close;
1351
1352             if (out_size < FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ))
1353             {
1354                 status = STATUS_INFO_LENGTH_MISMATCH;
1355                 break;
1356             }
1357
1358             if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )))
1359                 break;
1360
1361 #ifdef FIONREAD
1362             if (ioctl( fd, FIONREAD, &avail ) != 0)
1363             {
1364                 TRACE("FIONREAD failed reason: %s\n",strerror(errno));
1365                 if (needs_close) close( fd );
1366                 status = FILE_GetNtStatus();
1367                 break;
1368             }
1369 #endif
1370             if (!avail)  /* check for closed pipe */
1371             {
1372                 struct pollfd pollfd;
1373                 int ret;
1374
1375                 pollfd.fd = fd;
1376                 pollfd.events = POLLIN;
1377                 pollfd.revents = 0;
1378                 ret = poll( &pollfd, 1, 0 );
1379                 if (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR))))
1380                 {
1381                     if (needs_close) close( fd );
1382                     status = STATUS_PIPE_BROKEN;
1383                     break;
1384                 }
1385             }
1386             buffer->NamedPipeState    = 0;  /* FIXME */
1387             buffer->ReadDataAvailable = avail;
1388             buffer->NumberOfMessages  = 0;  /* FIXME */
1389             buffer->MessageLength     = 0;  /* FIXME */
1390             io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1391             status = STATUS_SUCCESS;
1392             if (avail)
1393             {
1394                 ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1395                 if (data_size)
1396                 {
1397                     int res = recv( fd, buffer->Data, data_size, MSG_PEEK );
1398                     if (res >= 0) io->Information += res;
1399                 }
1400             }
1401             if (needs_close) close( fd );
1402         }
1403         break;
1404
1405     case FSCTL_PIPE_DISCONNECT:
1406         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1407                                     in_buffer, in_size, out_buffer, out_size );
1408         if (!status)
1409         {
1410             int fd = server_remove_fd_from_cache( handle );
1411             if (fd != -1) close( fd );
1412         }
1413         break;
1414
1415     case FSCTL_PIPE_IMPERSONATE:
1416         FIXME("FSCTL_PIPE_IMPERSONATE: impersonating self\n");
1417         status = RtlImpersonateSelf( SecurityImpersonation );
1418         break;
1419
1420     case FSCTL_LOCK_VOLUME:
1421     case FSCTL_UNLOCK_VOLUME:
1422         FIXME("stub! return success - Unsupported fsctl %x (device=%x access=%x func=%x method=%x)\n",
1423               code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1424         status = STATUS_SUCCESS;
1425         break;
1426
1427     case FSCTL_PIPE_LISTEN:
1428     case FSCTL_PIPE_WAIT:
1429     default:
1430         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1431                                     in_buffer, in_size, out_buffer, out_size );
1432         break;
1433     }
1434
1435     if (status != STATUS_PENDING) io->u.Status = status;
1436     return status;
1437 }
1438
1439 /******************************************************************************
1440  *  NtSetVolumeInformationFile          [NTDLL.@]
1441  *  ZwSetVolumeInformationFile          [NTDLL.@]
1442  *
1443  * Set volume information for an open file handle.
1444  *
1445  * PARAMS
1446  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1447  *  IoStatusBlock      [O] Receives information about the operation on return
1448  *  FsInformation      [I] Source for volume information
1449  *  Length             [I] Size of FsInformation
1450  *  FsInformationClass [I] Type of volume information to set
1451  *
1452  * RETURNS
1453  *  Success: 0. IoStatusBlock is updated.
1454  *  Failure: An NTSTATUS error code describing the error.
1455  */
1456 NTSTATUS WINAPI NtSetVolumeInformationFile(
1457         IN HANDLE FileHandle,
1458         PIO_STATUS_BLOCK IoStatusBlock,
1459         PVOID FsInformation,
1460         ULONG Length,
1461         FS_INFORMATION_CLASS FsInformationClass)
1462 {
1463         FIXME("(%p,%p,%p,0x%08x,0x%08x) stub\n",
1464         FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
1465         return 0;
1466 }
1467
1468 /******************************************************************************
1469  *  NtQueryInformationFile              [NTDLL.@]
1470  *  ZwQueryInformationFile              [NTDLL.@]
1471  *
1472  * Get information about an open file handle.
1473  *
1474  * PARAMS
1475  *  hFile    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1476  *  io       [O] Receives information about the operation on return
1477  *  ptr      [O] Destination for file information
1478  *  len      [I] Size of FileInformation
1479  *  class    [I] Type of file information to get
1480  *
1481  * RETURNS
1482  *  Success: 0. IoStatusBlock and FileInformation are updated.
1483  *  Failure: An NTSTATUS error code describing the error.
1484  */
1485 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
1486                                         PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
1487 {
1488     static const size_t info_sizes[] =
1489     {
1490         0,
1491         sizeof(FILE_DIRECTORY_INFORMATION),            /* FileDirectoryInformation */
1492         sizeof(FILE_FULL_DIRECTORY_INFORMATION),       /* FileFullDirectoryInformation */
1493         sizeof(FILE_BOTH_DIRECTORY_INFORMATION),       /* FileBothDirectoryInformation */
1494         sizeof(FILE_BASIC_INFORMATION),                /* FileBasicInformation */
1495         sizeof(FILE_STANDARD_INFORMATION),             /* FileStandardInformation */
1496         sizeof(FILE_INTERNAL_INFORMATION),             /* FileInternalInformation */
1497         sizeof(FILE_EA_INFORMATION),                   /* FileEaInformation */
1498         sizeof(FILE_ACCESS_INFORMATION),               /* FileAccessInformation */
1499         sizeof(FILE_NAME_INFORMATION)-sizeof(WCHAR),   /* FileNameInformation */
1500         sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
1501         0,                                             /* FileLinkInformation */
1502         sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR),  /* FileNamesInformation */
1503         sizeof(FILE_DISPOSITION_INFORMATION),          /* FileDispositionInformation */
1504         sizeof(FILE_POSITION_INFORMATION),             /* FilePositionInformation */
1505         sizeof(FILE_FULL_EA_INFORMATION),              /* FileFullEaInformation */
1506         sizeof(FILE_MODE_INFORMATION),                 /* FileModeInformation */
1507         sizeof(FILE_ALIGNMENT_INFORMATION),            /* FileAlignmentInformation */
1508         sizeof(FILE_ALL_INFORMATION)-sizeof(WCHAR),    /* FileAllInformation */
1509         sizeof(FILE_ALLOCATION_INFORMATION),           /* FileAllocationInformation */
1510         sizeof(FILE_END_OF_FILE_INFORMATION),          /* FileEndOfFileInformation */
1511         0,                                             /* FileAlternateNameInformation */
1512         sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
1513         0,                                             /* FilePipeInformation */
1514         sizeof(FILE_PIPE_LOCAL_INFORMATION),           /* FilePipeLocalInformation */
1515         0,                                             /* FilePipeRemoteInformation */
1516         sizeof(FILE_MAILSLOT_QUERY_INFORMATION),       /* FileMailslotQueryInformation */
1517         0,                                             /* FileMailslotSetInformation */
1518         0,                                             /* FileCompressionInformation */
1519         0,                                             /* FileObjectIdInformation */
1520         0,                                             /* FileCompletionInformation */
1521         0,                                             /* FileMoveClusterInformation */
1522         0,                                             /* FileQuotaInformation */
1523         0,                                             /* FileReparsePointInformation */
1524         0,                                             /* FileNetworkOpenInformation */
1525         0,                                             /* FileAttributeTagInformation */
1526         0                                              /* FileTrackingInformation */
1527     };
1528
1529     struct stat st;
1530     int fd, needs_close = FALSE;
1531
1532     TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
1533
1534     io->Information = 0;
1535
1536     if (class <= 0 || class >= FileMaximumInformation)
1537         return io->u.Status = STATUS_INVALID_INFO_CLASS;
1538     if (!info_sizes[class])
1539     {
1540         FIXME("Unsupported class (%d)\n", class);
1541         return io->u.Status = STATUS_NOT_IMPLEMENTED;
1542     }
1543     if (len < info_sizes[class])
1544         return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
1545
1546     if (class != FilePipeLocalInformation)
1547     {
1548         if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, NULL )))
1549             return io->u.Status;
1550     }
1551
1552     switch (class)
1553     {
1554     case FileBasicInformation:
1555         {
1556             FILE_BASIC_INFORMATION *info = ptr;
1557
1558             if (fstat( fd, &st ) == -1)
1559                 io->u.Status = FILE_GetNtStatus();
1560             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1561                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1562             else
1563             {
1564                 if (S_ISDIR(st.st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1565                 else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1566                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1567                     info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1568                 RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime);
1569                 RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime);
1570                 RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime);
1571                 RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime);
1572 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1573                 info->CreationTime.QuadPart += st.st_mtim.tv_nsec / 100;
1574                 info->LastWriteTime.QuadPart += st.st_mtim.tv_nsec / 100;
1575 #endif
1576 #ifdef HAVE_STRUCT_STAT_ST_CTIM
1577                 info->ChangeTime.QuadPart += st.st_ctim.tv_nsec / 100;
1578 #endif
1579 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1580                 info->LastAccessTime.QuadPart += st.st_atim.tv_nsec / 100;
1581 #endif
1582             }
1583         }
1584         break;
1585     case FileStandardInformation:
1586         {
1587             FILE_STANDARD_INFORMATION *info = ptr;
1588
1589             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1590             else
1591             {
1592                 if ((info->Directory = S_ISDIR(st.st_mode)))
1593                 {
1594                     info->AllocationSize.QuadPart = 0;
1595                     info->EndOfFile.QuadPart      = 0;
1596                     info->NumberOfLinks           = 1;
1597                     info->DeletePending           = FALSE;
1598                 }
1599                 else
1600                 {
1601                     info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1602                     info->EndOfFile.QuadPart      = st.st_size;
1603                     info->NumberOfLinks           = st.st_nlink;
1604                     info->DeletePending           = FALSE; /* FIXME */
1605                 }
1606             }
1607         }
1608         break;
1609     case FilePositionInformation:
1610         {
1611             FILE_POSITION_INFORMATION *info = ptr;
1612             off_t res = lseek( fd, 0, SEEK_CUR );
1613             if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
1614             else info->CurrentByteOffset.QuadPart = res;
1615         }
1616         break;
1617     case FileInternalInformation:
1618         {
1619             FILE_INTERNAL_INFORMATION *info = ptr;
1620
1621             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1622             else info->IndexNumber.QuadPart = st.st_ino;
1623         }
1624         break;
1625     case FileEaInformation:
1626         {
1627             FILE_EA_INFORMATION *info = ptr;
1628             info->EaSize = 0;
1629         }
1630         break;
1631     case FileEndOfFileInformation:
1632         {
1633             FILE_END_OF_FILE_INFORMATION *info = ptr;
1634
1635             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1636             else info->EndOfFile.QuadPart = S_ISDIR(st.st_mode) ? 0 : st.st_size;
1637         }
1638         break;
1639     case FileAllInformation:
1640         {
1641             FILE_ALL_INFORMATION *info = ptr;
1642
1643             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1644             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1645                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1646             else
1647             {
1648                 if ((info->StandardInformation.Directory = S_ISDIR(st.st_mode)))
1649                 {
1650                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1651                     info->StandardInformation.AllocationSize.QuadPart = 0;
1652                     info->StandardInformation.EndOfFile.QuadPart      = 0;
1653                     info->StandardInformation.NumberOfLinks           = 1;
1654                     info->StandardInformation.DeletePending           = FALSE;
1655                 }
1656                 else
1657                 {
1658                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1659                     info->StandardInformation.AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1660                     info->StandardInformation.EndOfFile.QuadPart      = st.st_size;
1661                     info->StandardInformation.NumberOfLinks           = st.st_nlink;
1662                     info->StandardInformation.DeletePending           = FALSE; /* FIXME */
1663                 }
1664                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1665                     info->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_READONLY;
1666                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.CreationTime);
1667                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.LastWriteTime);
1668                 RtlSecondsSince1970ToTime( st.st_ctime, &info->BasicInformation.ChangeTime);
1669                 RtlSecondsSince1970ToTime( st.st_atime, &info->BasicInformation.LastAccessTime);
1670 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1671                 info->BasicInformation.CreationTime.QuadPart += st.st_mtim.tv_nsec / 100;
1672                 info->BasicInformation.LastWriteTime.QuadPart += st.st_mtim.tv_nsec / 100;
1673 #endif
1674 #ifdef HAVE_STRUCT_STAT_ST_CTIM
1675                 info->BasicInformation.ChangeTime.QuadPart += st.st_ctim.tv_nsec / 100;
1676 #endif
1677 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1678                 info->BasicInformation.LastAccessTime.QuadPart += st.st_atim.tv_nsec / 100;
1679 #endif
1680                 info->InternalInformation.IndexNumber.QuadPart = st.st_ino;
1681                 info->EaInformation.EaSize = 0;
1682                 info->AccessInformation.AccessFlags = 0;  /* FIXME */
1683                 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
1684                 info->ModeInformation.Mode = 0;  /* FIXME */
1685                 info->AlignmentInformation.AlignmentRequirement = 1;  /* FIXME */
1686                 info->NameInformation.FileNameLength = 0;
1687                 io->Information = sizeof(*info) - sizeof(WCHAR);
1688             }
1689         }
1690         break;
1691     case FileMailslotQueryInformation:
1692         {
1693             FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
1694
1695             SERVER_START_REQ( set_mailslot_info )
1696             {
1697                 req->handle = wine_server_obj_handle( hFile );
1698                 req->flags = 0;
1699                 io->u.Status = wine_server_call( req );
1700                 if( io->u.Status == STATUS_SUCCESS )
1701                 {
1702                     info->MaximumMessageSize = reply->max_msgsize;
1703                     info->MailslotQuota = 0;
1704                     info->NextMessageSize = 0;
1705                     info->MessagesAvailable = 0;
1706                     info->ReadTimeout.QuadPart = reply->read_timeout;
1707                 }
1708             }
1709             SERVER_END_REQ;
1710             if (!io->u.Status)
1711             {
1712                 char *tmpbuf;
1713                 ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000;
1714                 if (size > 0x10000) size = 0x10000;
1715                 if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
1716                 {
1717                     int fd, needs_close;
1718                     if (!server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
1719                     {
1720                         int res = recv( fd, tmpbuf, size, MSG_PEEK );
1721                         info->MessagesAvailable = (res > 0);
1722                         info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE;
1723                         if (needs_close) close( fd );
1724                     }
1725                     RtlFreeHeap( GetProcessHeap(), 0, tmpbuf );
1726                 }
1727             }
1728         }
1729         break;
1730     case FilePipeLocalInformation:
1731         {
1732             FILE_PIPE_LOCAL_INFORMATION* pli = ptr;
1733
1734             SERVER_START_REQ( get_named_pipe_info )
1735             {
1736                 req->handle = wine_server_obj_handle( hFile );
1737                 if (!(io->u.Status = wine_server_call( req )))
1738                 {
1739                     pli->NamedPipeType = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ? 
1740                         FILE_PIPE_TYPE_MESSAGE : FILE_PIPE_TYPE_BYTE;
1741                     pli->NamedPipeConfiguration = 0; /* FIXME */
1742                     pli->MaximumInstances = reply->maxinstances;
1743                     pli->CurrentInstances = reply->instances;
1744                     pli->InboundQuota = reply->insize;
1745                     pli->ReadDataAvailable = 0; /* FIXME */
1746                     pli->OutboundQuota = reply->outsize;
1747                     pli->WriteQuotaAvailable = 0; /* FIXME */
1748                     pli->NamedPipeState = 0; /* FIXME */
1749                     pli->NamedPipeEnd = (reply->flags & NAMED_PIPE_SERVER_END) ?
1750                         FILE_PIPE_SERVER_END : FILE_PIPE_CLIENT_END;
1751                 }
1752             }
1753             SERVER_END_REQ;
1754         }
1755         break;
1756     default:
1757         FIXME("Unsupported class (%d)\n", class);
1758         io->u.Status = STATUS_NOT_IMPLEMENTED;
1759         break;
1760     }
1761     if (needs_close) close( fd );
1762     if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
1763     return io->u.Status;
1764 }
1765
1766 /******************************************************************************
1767  *  NtSetInformationFile                [NTDLL.@]
1768  *  ZwSetInformationFile                [NTDLL.@]
1769  *
1770  * Set information about an open file handle.
1771  *
1772  * PARAMS
1773  *  handle  [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1774  *  io      [O] Receives information about the operation on return
1775  *  ptr     [I] Source for file information
1776  *  len     [I] Size of FileInformation
1777  *  class   [I] Type of file information to set
1778  *
1779  * RETURNS
1780  *  Success: 0. io is updated.
1781  *  Failure: An NTSTATUS error code describing the error.
1782  */
1783 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
1784                                      PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
1785 {
1786     int fd, needs_close;
1787
1788     TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", handle, io, ptr, len, class);
1789
1790     io->u.Status = STATUS_SUCCESS;
1791     switch (class)
1792     {
1793     case FileBasicInformation:
1794         if (len >= sizeof(FILE_BASIC_INFORMATION))
1795         {
1796             struct stat st;
1797             const FILE_BASIC_INFORMATION *info = ptr;
1798
1799             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1800                 return io->u.Status;
1801
1802             if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
1803             {
1804                 ULONGLONG sec, nsec;
1805                 struct timeval tv[2];
1806
1807                 if (!info->LastAccessTime.QuadPart || !info->LastWriteTime.QuadPart)
1808                 {
1809
1810                     tv[0].tv_sec = tv[0].tv_usec = 0;
1811                     tv[1].tv_sec = tv[1].tv_usec = 0;
1812                     if (!fstat( fd, &st ))
1813                     {
1814                         tv[0].tv_sec = st.st_atime;
1815                         tv[1].tv_sec = st.st_mtime;
1816                     }
1817                 }
1818                 if (info->LastAccessTime.QuadPart)
1819                 {
1820                     sec = RtlLargeIntegerDivide( info->LastAccessTime.QuadPart, 10000000, &nsec );
1821                     tv[0].tv_sec = sec - SECS_1601_TO_1970;
1822                     tv[0].tv_usec = (UINT)nsec / 10;
1823                 }
1824                 if (info->LastWriteTime.QuadPart)
1825                 {
1826                     sec = RtlLargeIntegerDivide( info->LastWriteTime.QuadPart, 10000000, &nsec );
1827                     tv[1].tv_sec = sec - SECS_1601_TO_1970;
1828                     tv[1].tv_usec = (UINT)nsec / 10;
1829                 }
1830                 if (futimes( fd, tv ) == -1) io->u.Status = FILE_GetNtStatus();
1831             }
1832
1833             if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
1834             {
1835                 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1836                 else
1837                 {
1838                     if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
1839                     {
1840                         if (S_ISDIR( st.st_mode))
1841                             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
1842                         else
1843                             st.st_mode &= ~0222; /* clear write permission bits */
1844                     }
1845                     else
1846                     {
1847                         /* add write permission only where we already have read permission */
1848                         st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
1849                     }
1850                     if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
1851                 }
1852             }
1853
1854             if (needs_close) close( fd );
1855         }
1856         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1857         break;
1858
1859     case FilePositionInformation:
1860         if (len >= sizeof(FILE_POSITION_INFORMATION))
1861         {
1862             const FILE_POSITION_INFORMATION *info = ptr;
1863
1864             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1865                 return io->u.Status;
1866
1867             if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
1868                 io->u.Status = FILE_GetNtStatus();
1869
1870             if (needs_close) close( fd );
1871         }
1872         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1873         break;
1874
1875     case FileEndOfFileInformation:
1876         if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
1877         {
1878             struct stat st;
1879             const FILE_END_OF_FILE_INFORMATION *info = ptr;
1880
1881             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1882                 return io->u.Status;
1883
1884             /* first try normal truncate */
1885             if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1886
1887             /* now check for the need to extend the file */
1888             if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
1889             {
1890                 static const char zero;
1891
1892                 /* extend the file one byte beyond the requested size and then truncate it */
1893                 /* this should work around ftruncate implementations that can't extend files */
1894                 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
1895                     ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1896             }
1897             io->u.Status = FILE_GetNtStatus();
1898
1899             if (needs_close) close( fd );
1900         }
1901         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1902         break;
1903
1904     case FileMailslotSetInformation:
1905         {
1906             FILE_MAILSLOT_SET_INFORMATION *info = ptr;
1907
1908             SERVER_START_REQ( set_mailslot_info )
1909             {
1910                 req->handle = wine_server_obj_handle( handle );
1911                 req->flags = MAILSLOT_SET_READ_TIMEOUT;
1912                 req->read_timeout = info->ReadTimeout.QuadPart;
1913                 io->u.Status = wine_server_call( req );
1914             }
1915             SERVER_END_REQ;
1916         }
1917         break;
1918
1919     case FileCompletionInformation:
1920         if (len >= sizeof(FILE_COMPLETION_INFORMATION))
1921         {
1922             FILE_COMPLETION_INFORMATION *info = (FILE_COMPLETION_INFORMATION *)ptr;
1923
1924             SERVER_START_REQ( set_completion_info )
1925             {
1926                 req->handle   = wine_server_obj_handle( handle );
1927                 req->chandle  = wine_server_obj_handle( info->CompletionPort );
1928                 req->ckey     = info->CompletionKey;
1929                 io->u.Status  = wine_server_call( req );
1930             }
1931             SERVER_END_REQ;
1932         } else
1933             io->u.Status = STATUS_INVALID_PARAMETER_3;
1934         break;
1935
1936     default:
1937         FIXME("Unsupported class (%d)\n", class);
1938         io->u.Status = STATUS_NOT_IMPLEMENTED;
1939         break;
1940     }
1941     io->Information = 0;
1942     return io->u.Status;
1943 }
1944
1945
1946 /******************************************************************************
1947  *              NtQueryFullAttributesFile   (NTDLL.@)
1948  */
1949 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
1950                                            FILE_NETWORK_OPEN_INFORMATION *info )
1951 {
1952     ANSI_STRING unix_name;
1953     NTSTATUS status;
1954
1955     if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN,
1956                                               !(attr->Attributes & OBJ_CASE_INSENSITIVE) )))
1957     {
1958         struct stat st;
1959
1960         if (stat( unix_name.Buffer, &st ) == -1)
1961             status = FILE_GetNtStatus();
1962         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1963             status = STATUS_INVALID_INFO_CLASS;
1964         else
1965         {
1966             if (S_ISDIR(st.st_mode))
1967             {
1968                 info->FileAttributes          = FILE_ATTRIBUTE_DIRECTORY;
1969                 info->AllocationSize.QuadPart = 0;
1970                 info->EndOfFile.QuadPart      = 0;
1971             }
1972             else
1973             {
1974                 info->FileAttributes          = FILE_ATTRIBUTE_ARCHIVE;
1975                 info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1976                 info->EndOfFile.QuadPart      = st.st_size;
1977             }
1978             if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1979                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1980             RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime );
1981             RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime );
1982             RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime );
1983             RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime );
1984             if (DIR_is_hidden_file( attr->ObjectName ))
1985                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1986         }
1987         RtlFreeAnsiString( &unix_name );
1988     }
1989     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
1990     return status;
1991 }
1992
1993
1994 /******************************************************************************
1995  *              NtQueryAttributesFile   (NTDLL.@)
1996  *              ZwQueryAttributesFile   (NTDLL.@)
1997  */
1998 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
1999 {
2000     FILE_NETWORK_OPEN_INFORMATION full_info;
2001     NTSTATUS status;
2002
2003     if (!(status = NtQueryFullAttributesFile( attr, &full_info )))
2004     {
2005         info->CreationTime.QuadPart   = full_info.CreationTime.QuadPart;
2006         info->LastAccessTime.QuadPart = full_info.LastAccessTime.QuadPart;
2007         info->LastWriteTime.QuadPart  = full_info.LastWriteTime.QuadPart;
2008         info->ChangeTime.QuadPart     = full_info.ChangeTime.QuadPart;
2009         info->FileAttributes          = full_info.FileAttributes;
2010     }
2011     return status;
2012 }
2013
2014
2015 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__APPLE__)
2016 /* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */
2017 static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename,
2018                                             unsigned int flags )
2019 {
2020     if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename))
2021     {
2022         info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2023         /* Don't assume read-only, let the mount options set it below */
2024         info->Characteristics |= FILE_REMOVABLE_MEDIA;
2025     }
2026     else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) ||
2027              !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename))
2028     {
2029         info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2030         info->Characteristics |= FILE_REMOTE_DEVICE;
2031     }
2032     else if (!strcmp("procfs", fstypename))
2033         info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2034     else
2035         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2036
2037     if (flags & MNT_RDONLY)
2038         info->Characteristics |= FILE_READ_ONLY_DEVICE;
2039
2040     if (!(flags & MNT_LOCAL))
2041     {
2042         info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2043         info->Characteristics |= FILE_REMOTE_DEVICE;
2044     }
2045 }
2046 #endif
2047
2048 static inline int is_device_placeholder( int fd )
2049 {
2050     static const char wine_placeholder[] = "Wine device placeholder";
2051     char buffer[sizeof(wine_placeholder)-1];
2052
2053     if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
2054         return 0;
2055     return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
2056 }
2057
2058 /******************************************************************************
2059  *              get_device_info
2060  *
2061  * Implementation of the FileFsDeviceInformation query for NtQueryVolumeInformationFile.
2062  */
2063 static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
2064 {
2065     struct stat st;
2066
2067     info->Characteristics = 0;
2068     if (fstat( fd, &st ) < 0) return FILE_GetNtStatus();
2069     if (S_ISCHR( st.st_mode ))
2070     {
2071         info->DeviceType = FILE_DEVICE_UNKNOWN;
2072 #ifdef linux
2073         switch(major(st.st_rdev))
2074         {
2075         case MEM_MAJOR:
2076             info->DeviceType = FILE_DEVICE_NULL;
2077             break;
2078         case TTY_MAJOR:
2079             info->DeviceType = FILE_DEVICE_SERIAL_PORT;
2080             break;
2081         case LP_MAJOR:
2082             info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
2083             break;
2084         case SCSI_TAPE_MAJOR:
2085             info->DeviceType = FILE_DEVICE_TAPE;
2086             break;
2087         }
2088 #endif
2089     }
2090     else if (S_ISBLK( st.st_mode ))
2091     {
2092         info->DeviceType = FILE_DEVICE_DISK;
2093     }
2094     else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
2095     {
2096         info->DeviceType = FILE_DEVICE_NAMED_PIPE;
2097     }
2098     else if (is_device_placeholder( fd ))
2099     {
2100         info->DeviceType = FILE_DEVICE_DISK;
2101     }
2102     else  /* regular file or directory */
2103     {
2104 #if defined(linux) && defined(HAVE_FSTATFS)
2105         struct statfs stfs;
2106
2107         /* check for floppy disk */
2108         if (major(st.st_dev) == FLOPPY_MAJOR)
2109             info->Characteristics |= FILE_REMOVABLE_MEDIA;
2110
2111         if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
2112         switch (stfs.f_type)
2113         {
2114         case 0x9660:      /* iso9660 */
2115         case 0x9fa1:      /* supermount */
2116         case 0x15013346:  /* udf */
2117             info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2118             info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2119             break;
2120         case 0x6969:  /* nfs */
2121         case 0x517B:  /* smbfs */
2122         case 0x564c:  /* ncpfs */
2123             info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2124             info->Characteristics |= FILE_REMOTE_DEVICE;
2125             break;
2126         case 0x01021994:  /* tmpfs */
2127         case 0x28cd3d45:  /* cramfs */
2128         case 0x1373:      /* devfs */
2129         case 0x9fa0:      /* procfs */
2130             info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2131             break;
2132         default:
2133             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2134             break;
2135         }
2136 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
2137         struct statfs stfs;
2138
2139         if (fstatfs( fd, &stfs ) < 0)
2140             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2141         else
2142             get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags );
2143 #elif defined(__NetBSD__)
2144         struct statvfs stfs;
2145
2146         if (fstatvfs( fd, &stfs) < 0)
2147             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2148         else
2149             get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag );
2150 #elif defined(sun)
2151         /* Use dkio to work out device types */
2152         {
2153 # include <sys/dkio.h>
2154 # include <sys/vtoc.h>
2155             struct dk_cinfo dkinf;
2156             int retval = ioctl(fd, DKIOCINFO, &dkinf);
2157             if(retval==-1){
2158                 WARN("Unable to get disk device type information - assuming a disk like device\n");
2159                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2160             }
2161             switch (dkinf.dki_ctype)
2162             {
2163             case DKC_CDROM:
2164                 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2165                 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2166                 break;
2167             case DKC_NCRFLOPPY:
2168             case DKC_SMSFLOPPY:
2169             case DKC_INTEL82072:
2170             case DKC_INTEL82077:
2171                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2172                 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2173                 break;
2174             case DKC_MD:
2175                 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2176                 break;
2177             default:
2178                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2179             }
2180         }
2181 #else
2182         static int warned;
2183         if (!warned++) FIXME( "device info not properly supported on this platform\n" );
2184         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2185 #endif
2186         info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
2187     }
2188     return STATUS_SUCCESS;
2189 }
2190
2191
2192 /******************************************************************************
2193  *  NtQueryVolumeInformationFile                [NTDLL.@]
2194  *  ZwQueryVolumeInformationFile                [NTDLL.@]
2195  *
2196  * Get volume information for an open file handle.
2197  *
2198  * PARAMS
2199  *  handle      [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2200  *  io          [O] Receives information about the operation on return
2201  *  buffer      [O] Destination for volume information
2202  *  length      [I] Size of FsInformation
2203  *  info_class  [I] Type of volume information to set
2204  *
2205  * RETURNS
2206  *  Success: 0. io and buffer are updated.
2207  *  Failure: An NTSTATUS error code describing the error.
2208  */
2209 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
2210                                               PVOID buffer, ULONG length,
2211                                               FS_INFORMATION_CLASS info_class )
2212 {
2213     int fd, needs_close;
2214     struct stat st;
2215
2216     if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
2217         return io->u.Status;
2218
2219     io->u.Status = STATUS_NOT_IMPLEMENTED;
2220     io->Information = 0;
2221
2222     switch( info_class )
2223     {
2224     case FileFsVolumeInformation:
2225         FIXME( "%p: volume info not supported\n", handle );
2226         break;
2227     case FileFsLabelInformation:
2228         FIXME( "%p: label info not supported\n", handle );
2229         break;
2230     case FileFsSizeInformation:
2231         if (length < sizeof(FILE_FS_SIZE_INFORMATION))
2232             io->u.Status = STATUS_BUFFER_TOO_SMALL;
2233         else
2234         {
2235             FILE_FS_SIZE_INFORMATION *info = buffer;
2236
2237             if (fstat( fd, &st ) < 0)
2238             {
2239                 io->u.Status = FILE_GetNtStatus();
2240                 break;
2241             }
2242             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2243             {
2244                 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
2245             }
2246             else
2247             {
2248                 ULONGLONG bsize;
2249                 /* Linux's fstatvfs is buggy */
2250 #if !defined(linux) || !defined(HAVE_FSTATFS)
2251                 struct statvfs stfs;
2252
2253                 if (fstatvfs( fd, &stfs ) < 0)
2254                 {
2255                     io->u.Status = FILE_GetNtStatus();
2256                     break;
2257                 }
2258                 bsize = stfs.f_frsize;
2259 #else
2260                 struct statfs stfs;
2261                 if (fstatfs( fd, &stfs ) < 0)
2262                 {
2263                     io->u.Status = FILE_GetNtStatus();
2264                     break;
2265                 }
2266                 bsize = stfs.f_bsize;
2267 #endif
2268                 if (bsize == 2048)  /* assume CD-ROM */
2269                 {
2270                     info->BytesPerSector = 2048;
2271                     info->SectorsPerAllocationUnit = 1;
2272                 }
2273                 else
2274                 {
2275                     info->BytesPerSector = 512;
2276                     info->SectorsPerAllocationUnit = 8;
2277                 }
2278                 info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2279                 info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2280                 io->Information = sizeof(*info);
2281                 io->u.Status = STATUS_SUCCESS;
2282             }
2283         }
2284         break;
2285     case FileFsDeviceInformation:
2286         if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
2287             io->u.Status = STATUS_BUFFER_TOO_SMALL;
2288         else
2289         {
2290             FILE_FS_DEVICE_INFORMATION *info = buffer;
2291
2292             if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS)
2293                 io->Information = sizeof(*info);
2294         }
2295         break;
2296     case FileFsAttributeInformation:
2297         FIXME( "%p: attribute info not supported\n", handle );
2298         break;
2299     case FileFsControlInformation:
2300         FIXME( "%p: control info not supported\n", handle );
2301         break;
2302     case FileFsFullSizeInformation:
2303         FIXME( "%p: full size info not supported\n", handle );
2304         break;
2305     case FileFsObjectIdInformation:
2306         FIXME( "%p: object id info not supported\n", handle );
2307         break;
2308     case FileFsMaximumInformation:
2309         FIXME( "%p: maximum info not supported\n", handle );
2310         break;
2311     default:
2312         io->u.Status = STATUS_INVALID_PARAMETER;
2313         break;
2314     }
2315     if (needs_close) close( fd );
2316     return io->u.Status;
2317 }
2318
2319
2320 /******************************************************************
2321  *              NtQueryEaFile  (NTDLL.@)
2322  *
2323  * Read extended attributes from NTFS files.
2324  *
2325  * PARAMS
2326  *  hFile         [I] File handle, must be opened with FILE_READ_EA access
2327  *  iosb          [O] Receives information about the operation on return
2328  *  buffer        [O] Output buffer
2329  *  length        [I] Length of output buffer
2330  *  single_entry  [I] Only read and return one entry
2331  *  ea_list       [I] Optional list with names of EAs to return
2332  *  ea_list_len   [I] Length of ea_list in bytes
2333  *  ea_index      [I] Optional pointer to 1-based index of attribute to return
2334  *  restart       [I] restart EA scan
2335  *
2336  * RETURNS
2337  *  Success: 0. Atrributes read into buffer
2338  *  Failure: An NTSTATUS error code describing the error.
2339  */
2340 NTSTATUS WINAPI NtQueryEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length,
2341                                BOOLEAN single_entry, PVOID ea_list, ULONG ea_list_len,
2342                                PULONG ea_index, BOOLEAN restart )
2343 {
2344     FIXME("(%p,%p,%p,%d,%d,%p,%d,%p,%d) stub\n",
2345             hFile, iosb, buffer, length, single_entry, ea_list,
2346             ea_list_len, ea_index, restart);
2347     return STATUS_ACCESS_DENIED;
2348 }
2349
2350
2351 /******************************************************************
2352  *              NtSetEaFile  (NTDLL.@)
2353  *
2354  * Update extended attributes for NTFS files.
2355  *
2356  * PARAMS
2357  *  hFile         [I] File handle, must be opened with FILE_READ_EA access
2358  *  iosb          [O] Receives information about the operation on return
2359  *  buffer        [I] Buffer with EA information
2360  *  length        [I] Length of buffer
2361  *
2362  * RETURNS
2363  *  Success: 0. Attributes are updated
2364  *  Failure: An NTSTATUS error code describing the error.
2365  */
2366 NTSTATUS WINAPI NtSetEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length )
2367 {
2368     FIXME("(%p,%p,%p,%d) stub\n", hFile, iosb, buffer, length);
2369     return STATUS_ACCESS_DENIED;
2370 }
2371
2372
2373 /******************************************************************
2374  *              NtFlushBuffersFile  (NTDLL.@)
2375  *
2376  * Flush any buffered data on an open file handle.
2377  *
2378  * PARAMS
2379  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2380  *  IoStatusBlock      [O] Receives information about the operation on return
2381  *
2382  * RETURNS
2383  *  Success: 0. IoStatusBlock is updated.
2384  *  Failure: An NTSTATUS error code describing the error.
2385  */
2386 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
2387 {
2388     NTSTATUS ret;
2389     HANDLE hEvent = NULL;
2390
2391     SERVER_START_REQ( flush_file )
2392     {
2393         req->handle = wine_server_obj_handle( hFile );
2394         ret = wine_server_call( req );
2395         hEvent = wine_server_ptr_handle( reply->event );
2396     }
2397     SERVER_END_REQ;
2398     if (!ret && hEvent)
2399     {
2400         ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
2401         NtClose( hEvent );
2402     }
2403     return ret;
2404 }
2405
2406 /******************************************************************
2407  *              NtLockFile       (NTDLL.@)
2408  *
2409  *
2410  */
2411 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
2412                             PIO_APC_ROUTINE apc, void* apc_user,
2413                             PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
2414                             PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
2415                             BOOLEAN exclusive )
2416 {
2417     NTSTATUS    ret;
2418     HANDLE      handle;
2419     BOOLEAN     async;
2420     static BOOLEAN     warn = TRUE;
2421
2422     if (apc || io_status || key)
2423     {
2424         FIXME("Unimplemented yet parameter\n");
2425         return STATUS_NOT_IMPLEMENTED;
2426     }
2427
2428     if (apc_user && warn)
2429     {
2430         FIXME("I/O completion on lock not implemented yet\n");
2431         warn = FALSE;
2432     }
2433
2434     for (;;)
2435     {
2436         SERVER_START_REQ( lock_file )
2437         {
2438             req->handle      = wine_server_obj_handle( hFile );
2439             req->offset      = offset->QuadPart;
2440             req->count       = count->QuadPart;
2441             req->shared      = !exclusive;
2442             req->wait        = !dont_wait;
2443             ret = wine_server_call( req );
2444             handle = wine_server_ptr_handle( reply->handle );
2445             async  = reply->overlapped;
2446         }
2447         SERVER_END_REQ;
2448         if (ret != STATUS_PENDING)
2449         {
2450             if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
2451             return ret;
2452         }
2453
2454         if (async)
2455         {
2456             FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
2457             if (handle) NtClose( handle );
2458             return STATUS_PENDING;
2459         }
2460         if (handle)
2461         {
2462             NtWaitForSingleObject( handle, FALSE, NULL );
2463             NtClose( handle );
2464         }
2465         else
2466         {
2467             LARGE_INTEGER time;
2468     
2469             /* Unix lock conflict, sleep a bit and retry */
2470             time.QuadPart = 100 * (ULONGLONG)10000;
2471             time.QuadPart = -time.QuadPart;
2472             NtDelayExecution( FALSE, &time );
2473         }
2474     }
2475 }
2476
2477
2478 /******************************************************************
2479  *              NtUnlockFile    (NTDLL.@)
2480  *
2481  *
2482  */
2483 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
2484                               PLARGE_INTEGER offset, PLARGE_INTEGER count,
2485                               PULONG key )
2486 {
2487     NTSTATUS status;
2488
2489     TRACE( "%p %x%08x %x%08x\n",
2490            hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
2491
2492     if (io_status || key)
2493     {
2494         FIXME("Unimplemented yet parameter\n");
2495         return STATUS_NOT_IMPLEMENTED;
2496     }
2497
2498     SERVER_START_REQ( unlock_file )
2499     {
2500         req->handle = wine_server_obj_handle( hFile );
2501         req->offset = offset->QuadPart;
2502         req->count  = count->QuadPart;
2503         status = wine_server_call( req );
2504     }
2505     SERVER_END_REQ;
2506     return status;
2507 }
2508
2509 /******************************************************************
2510  *              NtCreateNamedPipeFile    (NTDLL.@)
2511  *
2512  *
2513  */
2514 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
2515                                        POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
2516                                        ULONG sharing, ULONG dispo, ULONG options,
2517                                        ULONG pipe_type, ULONG read_mode, 
2518                                        ULONG completion_mode, ULONG max_inst,
2519                                        ULONG inbound_quota, ULONG outbound_quota,
2520                                        PLARGE_INTEGER timeout)
2521 {
2522     NTSTATUS    status;
2523
2524     TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n",
2525           handle, access, debugstr_w(attr->ObjectName->Buffer), iosb, sharing, dispo,
2526           options, pipe_type, read_mode, completion_mode, max_inst, inbound_quota,
2527           outbound_quota, timeout);
2528
2529     /* assume we only get relative timeout */
2530     if (timeout->QuadPart > 0)
2531         FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
2532
2533     SERVER_START_REQ( create_named_pipe )
2534     {
2535         req->access  = access;
2536         req->attributes = attr->Attributes;
2537         req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2538         req->options = options;
2539         req->flags = 
2540             (pipe_type) ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0 |
2541             (read_mode) ? NAMED_PIPE_MESSAGE_STREAM_READ  : 0 |
2542             (completion_mode) ? NAMED_PIPE_NONBLOCKING_MODE  : 0;
2543         req->maxinstances = max_inst;
2544         req->outsize = outbound_quota;
2545         req->insize  = inbound_quota;
2546         req->timeout = timeout->QuadPart;
2547         wine_server_add_data( req, attr->ObjectName->Buffer,
2548                               attr->ObjectName->Length );
2549         status = wine_server_call( req );
2550         if (!status) *handle = wine_server_ptr_handle( reply->handle );
2551     }
2552     SERVER_END_REQ;
2553     return status;
2554 }
2555
2556 /******************************************************************
2557  *              NtDeleteFile    (NTDLL.@)
2558  *
2559  *
2560  */
2561 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
2562 {
2563     NTSTATUS status;
2564     HANDLE hFile;
2565     IO_STATUS_BLOCK io;
2566
2567     TRACE("%p\n", ObjectAttributes);
2568     status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE | DELETE,
2569                            ObjectAttributes, &io, NULL, 0,
2570                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
2571                            FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
2572     if (status == STATUS_SUCCESS) status = NtClose(hFile);
2573     return status;
2574 }
2575
2576 /******************************************************************
2577  *              NtCancelIoFile    (NTDLL.@)
2578  *
2579  *
2580  */
2581 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
2582 {
2583     LARGE_INTEGER timeout;
2584
2585     TRACE("%p %p\n", hFile, io_status );
2586
2587     SERVER_START_REQ( cancel_async )
2588     {
2589         req->handle = wine_server_obj_handle( hFile );
2590         wine_server_call( req );
2591     }
2592     SERVER_END_REQ;
2593     /* Let some APC be run, so that we can run the remaining APCs on hFile
2594      * either the cancelation of the pending one, but also the execution
2595      * of the queued APC, but not yet run. This is needed to ensure proper
2596      * clean-up of allocated data.
2597      */
2598     timeout.u.LowPart = timeout.u.HighPart = 0;
2599     return io_status->u.Status = NtDelayExecution( TRUE, &timeout );
2600 }
2601
2602 /******************************************************************************
2603  *  NtCreateMailslotFile        [NTDLL.@]
2604  *  ZwCreateMailslotFile        [NTDLL.@]
2605  *
2606  * PARAMS
2607  *  pHandle          [O] pointer to receive the handle created
2608  *  DesiredAccess    [I] access mode (read, write, etc)
2609  *  ObjectAttributes [I] fully qualified NT path of the mailslot
2610  *  IoStatusBlock    [O] receives completion status and other info
2611  *  CreateOptions    [I]
2612  *  MailslotQuota    [I]
2613  *  MaxMessageSize   [I]
2614  *  TimeOut          [I]
2615  *
2616  * RETURNS
2617  *  An NT status code
2618  */
2619 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
2620      POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
2621      ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
2622      PLARGE_INTEGER TimeOut)
2623 {
2624     LARGE_INTEGER timeout;
2625     NTSTATUS ret;
2626
2627     TRACE("%p %08x %p %p %08x %08x %08x %p\n",
2628               pHandle, DesiredAccess, attr, IoStatusBlock,
2629               CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
2630
2631     if (!pHandle) return STATUS_ACCESS_VIOLATION;
2632     if (!attr) return STATUS_INVALID_PARAMETER;
2633     if (!attr->ObjectName) return STATUS_OBJECT_PATH_SYNTAX_BAD;
2634
2635     /*
2636      *  For a NULL TimeOut pointer set the default timeout value
2637      */
2638     if  (!TimeOut)
2639         timeout.QuadPart = -1;
2640     else
2641         timeout.QuadPart = TimeOut->QuadPart;
2642
2643     SERVER_START_REQ( create_mailslot )
2644     {
2645         req->access = DesiredAccess;
2646         req->attributes = attr->Attributes;
2647         req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2648         req->max_msgsize = MaxMessageSize;
2649         req->read_timeout = timeout.QuadPart;
2650         wine_server_add_data( req, attr->ObjectName->Buffer,
2651                               attr->ObjectName->Length );
2652         ret = wine_server_call( req );
2653         if( ret == STATUS_SUCCESS )
2654             *pHandle = wine_server_ptr_handle( reply->handle );
2655     }
2656     SERVER_END_REQ;
2657  
2658     return ret;
2659 }