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