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