widl: Print large enum constants in hex.
[wine] / dlls / ntdll / file.c
1 /*
2  * Copyright 1999, 2000 Juergen Schmied
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20 #include "wine/port.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <assert.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_LINUX_MAJOR_H
31 # include <linux/major.h>
32 #endif
33 #ifdef HAVE_SYS_STATVFS_H
34 # include <sys/statvfs.h>
35 #endif
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
39 #ifdef HAVE_SYS_TIME_H
40 # include <sys/time.h>
41 #endif
42 #ifdef HAVE_SYS_IOCTL_H
43 #include <sys/ioctl.h>
44 #endif
45 #ifdef HAVE_SYS_FILIO_H
46 # include <sys/filio.h>
47 #endif
48 #ifdef HAVE_POLL_H
49 #include <poll.h>
50 #endif
51 #ifdef HAVE_SYS_POLL_H
52 #include <sys/poll.h>
53 #endif
54 #ifdef HAVE_SYS_SOCKET_H
55 #include <sys/socket.h>
56 #endif
57 #ifdef HAVE_UTIME_H
58 # include <utime.h>
59 #endif
60 #ifdef HAVE_SYS_VFS_H
61 # include <sys/vfs.h>
62 #endif
63 #ifdef HAVE_SYS_MOUNT_H
64 # include <sys/mount.h>
65 #endif
66 #ifdef HAVE_SYS_STATFS_H
67 # include <sys/statfs.h>
68 #endif
69 #ifdef HAVE_VALGRIND_MEMCHECK_H
70 # include <valgrind/memcheck.h>
71 #endif
72
73 #define NONAMELESSUNION
74 #define NONAMELESSSTRUCT
75 #include "ntstatus.h"
76 #define WIN32_NO_STATUS
77 #include "wine/unicode.h"
78 #include "wine/debug.h"
79 #include "wine/server.h"
80 #include "ntdll_misc.h"
81
82 #include "winternl.h"
83 #include "winioctl.h"
84 #include "ddk/ntddser.h"
85
86 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
87 WINE_DECLARE_DEBUG_CHANNEL(winediag);
88
89 mode_t FILE_umask = 0;
90
91 #define SECSPERDAY         86400
92 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
93
94
95 /**************************************************************************
96  *                 FILE_CreateFile                    (internal)
97  * Open a file.
98  *
99  * Parameter set fully identical with NtCreateFile
100  */
101 static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
102                                  PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
103                                  ULONG attributes, ULONG sharing, ULONG disposition,
104                                  ULONG options, PVOID ea_buffer, ULONG ea_length )
105 {
106     ANSI_STRING unix_name;
107     int created = FALSE;
108
109     TRACE("handle=%p access=%08x name=%s objattr=%08x root=%p sec=%p io=%p alloc_size=%p "
110           "attr=%08x sharing=%08x disp=%d options=%08x ea=%p.0x%08x\n",
111           handle, access, debugstr_us(attr->ObjectName), attr->Attributes,
112           attr->RootDirectory, attr->SecurityDescriptor, io, alloc_size,
113           attributes, sharing, disposition, options, ea_buffer, ea_length );
114
115     if (!attr || !attr->ObjectName) return STATUS_INVALID_PARAMETER;
116
117     if (alloc_size) FIXME( "alloc_size not supported\n" );
118
119     if (options & FILE_OPEN_BY_FILE_ID)
120         io->u.Status = file_id_to_unix_file_name( attr, &unix_name );
121     else
122         io->u.Status = nt_to_unix_file_name_attr( attr, &unix_name, disposition );
123
124     if (io->u.Status == STATUS_BAD_DEVICE_TYPE)
125     {
126         SERVER_START_REQ( open_file_object )
127         {
128             req->access     = access;
129             req->attributes = attr->Attributes;
130             req->rootdir    = wine_server_obj_handle( attr->RootDirectory );
131             req->sharing    = sharing;
132             req->options    = options;
133             wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
134             io->u.Status = wine_server_call( req );
135             *handle = wine_server_ptr_handle( reply->handle );
136         }
137         SERVER_END_REQ;
138         if (io->u.Status == STATUS_SUCCESS) io->Information = FILE_OPENED;
139         return io->u.Status;
140     }
141
142     if (io->u.Status == STATUS_NO_SUCH_FILE &&
143         disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
144     {
145         created = TRUE;
146         io->u.Status = STATUS_SUCCESS;
147     }
148
149     if (io->u.Status == STATUS_SUCCESS)
150     {
151         struct security_descriptor *sd;
152         struct object_attributes objattr;
153
154         objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
155         objattr.name_len = 0;
156         io->u.Status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
157         if (io->u.Status != STATUS_SUCCESS)
158         {
159             RtlFreeAnsiString( &unix_name );
160             return io->u.Status;
161         }
162
163         SERVER_START_REQ( create_file )
164         {
165             req->access     = access;
166             req->attributes = attr->Attributes;
167             req->sharing    = sharing;
168             req->create     = disposition;
169             req->options    = options;
170             req->attrs      = attributes;
171             wine_server_add_data( req, &objattr, sizeof(objattr) );
172             if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
173             wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
174             io->u.Status = wine_server_call( req );
175             *handle = wine_server_ptr_handle( reply->handle );
176         }
177         SERVER_END_REQ;
178         NTDLL_free_struct_sd( sd );
179         RtlFreeAnsiString( &unix_name );
180     }
181     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
182
183     if (io->u.Status == STATUS_SUCCESS)
184     {
185         if (created) io->Information = FILE_CREATED;
186         else switch(disposition)
187         {
188         case FILE_SUPERSEDE:
189             io->Information = FILE_SUPERSEDED;
190             break;
191         case FILE_CREATE:
192             io->Information = FILE_CREATED;
193             break;
194         case FILE_OPEN:
195         case FILE_OPEN_IF:
196             io->Information = FILE_OPENED;
197             break;
198         case FILE_OVERWRITE:
199         case FILE_OVERWRITE_IF:
200             io->Information = FILE_OVERWRITTEN;
201             break;
202         }
203     }
204     else if (io->u.Status == STATUS_TOO_MANY_OPENED_FILES)
205     {
206         static int once;
207         if (!once++) ERR_(winediag)( "Too many open files, ulimit -n probably needs to be increased\n" );
208     }
209
210     return io->u.Status;
211 }
212
213 /**************************************************************************
214  *                 NtOpenFile                           [NTDLL.@]
215  *                 ZwOpenFile                           [NTDLL.@]
216  *
217  * Open a file.
218  *
219  * PARAMS
220  *  handle    [O] Variable that receives the file handle on return
221  *  access    [I] Access desired by the caller to the file
222  *  attr      [I] Structure describing the file to be opened
223  *  io        [O] Receives details about the result of the operation
224  *  sharing   [I] Type of shared access the caller requires
225  *  options   [I] Options for the file open
226  *
227  * RETURNS
228  *  Success: 0. FileHandle and IoStatusBlock are updated.
229  *  Failure: An NTSTATUS error code describing the error.
230  */
231 NTSTATUS WINAPI NtOpenFile( PHANDLE handle, ACCESS_MASK access,
232                             POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK io,
233                             ULONG sharing, ULONG options )
234 {
235     return FILE_CreateFile( handle, access, attr, io, NULL, 0,
236                             sharing, FILE_OPEN, options, NULL, 0 );
237 }
238
239 /**************************************************************************
240  *              NtCreateFile                            [NTDLL.@]
241  *              ZwCreateFile                            [NTDLL.@]
242  *
243  * Either create a new file or directory, or open an existing file, device,
244  * directory or volume.
245  *
246  * PARAMS
247  *      handle       [O] Points to a variable which receives the file handle on return
248  *      access       [I] Desired access to the file
249  *      attr         [I] Structure describing the file
250  *      io           [O] Receives information about the operation on return
251  *      alloc_size   [I] Initial size of the file in bytes
252  *      attributes   [I] Attributes to create the file with
253  *      sharing      [I] Type of shared access the caller would like to the file
254  *      disposition  [I] Specifies what to do, depending on whether the file already exists
255  *      options      [I] Options for creating a new file
256  *      ea_buffer    [I] Pointer to an extended attributes buffer
257  *      ea_length    [I] Length of ea_buffer
258  *
259  * RETURNS
260  *  Success: 0. handle and io are updated.
261  *  Failure: An NTSTATUS error code describing the error.
262  */
263 NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
264                               PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
265                               ULONG attributes, ULONG sharing, ULONG disposition,
266                               ULONG options, PVOID ea_buffer, ULONG ea_length )
267 {
268     return FILE_CreateFile( handle, access, attr, io, alloc_size, attributes,
269                             sharing, disposition, options, ea_buffer, ea_length );
270 }
271
272 /***********************************************************************
273  *                  Asynchronous file I/O                              *
274  */
275
276 struct async_fileio
277 {
278     HANDLE              handle;
279     PIO_APC_ROUTINE     apc;
280     void               *apc_arg;
281 };
282
283 typedef struct
284 {
285     struct async_fileio io;
286     char*               buffer;
287     unsigned int        already;
288     unsigned int        count;
289     BOOL                avail_mode;
290 } async_fileio_read;
291
292 typedef struct
293 {
294     struct async_fileio io;
295     const char         *buffer;
296     unsigned int        already;
297     unsigned int        count;
298 } async_fileio_write;
299
300
301 /* callback for file I/O user APC */
302 static void WINAPI fileio_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved )
303 {
304     struct async_fileio *async = arg;
305     if (async->apc) async->apc( async->apc_arg, io, reserved );
306     RtlFreeHeap( GetProcessHeap(), 0, async );
307 }
308
309 /***********************************************************************
310  *           FILE_GetNtStatus(void)
311  *
312  * Retrieve the Nt Status code from errno.
313  * Try to be consistent with FILE_SetDosError().
314  */
315 NTSTATUS FILE_GetNtStatus(void)
316 {
317     int err = errno;
318
319     TRACE( "errno = %d\n", errno );
320     switch (err)
321     {
322     case EAGAIN:    return STATUS_SHARING_VIOLATION;
323     case EBADF:     return STATUS_INVALID_HANDLE;
324     case EBUSY:     return STATUS_DEVICE_BUSY;
325     case ENOSPC:    return STATUS_DISK_FULL;
326     case EPERM:
327     case EROFS:
328     case EACCES:    return STATUS_ACCESS_DENIED;
329     case ENOTDIR:   return STATUS_OBJECT_PATH_NOT_FOUND;
330     case ENOENT:    return STATUS_OBJECT_NAME_NOT_FOUND;
331     case EISDIR:    return STATUS_FILE_IS_A_DIRECTORY;
332     case EMFILE:
333     case ENFILE:    return STATUS_TOO_MANY_OPENED_FILES;
334     case EINVAL:    return STATUS_INVALID_PARAMETER;
335     case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
336     case EPIPE:     return STATUS_PIPE_DISCONNECTED;
337     case EIO:       return STATUS_DEVICE_NOT_READY;
338 #ifdef ENOMEDIUM
339     case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE;
340 #endif
341     case ENXIO:     return STATUS_NO_SUCH_DEVICE;
342     case ENOTTY:
343     case EOPNOTSUPP:return STATUS_NOT_SUPPORTED;
344     case ECONNRESET:return STATUS_PIPE_DISCONNECTED;
345     case EFAULT:    return STATUS_ACCESS_VIOLATION;
346     case ESPIPE:    return STATUS_ILLEGAL_FUNCTION;
347 #ifdef ETIME /* Missing on FreeBSD */
348     case ETIME:     return STATUS_IO_TIMEOUT;
349 #endif
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 (FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1) < FIELD_OFFSET(t, f2)) \
1294             if ((size) >= FIELD_OFFSET(t, f2)) \
1295                 VALGRIND_MAKE_MEM_DEFINED( \
1296                     (const char *)(buf) + FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1), \
1297                     FIELD_OFFSET(t, f2) - FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1)); \
1298     } while (0)
1299
1300     switch (code)
1301     {
1302     case FSCTL_PIPE_WAIT:
1303         IGNORE_STRUCT_HOLE(in_buffer, in_size, FILE_PIPE_WAIT_FOR_BUFFER, TimeoutSpecified, Name);
1304         break;
1305     }
1306 #endif
1307 }
1308
1309
1310 /**************************************************************************
1311  *              NtDeviceIoControlFile                   [NTDLL.@]
1312  *              ZwDeviceIoControlFile                   [NTDLL.@]
1313  *
1314  * Perform an I/O control operation on an open file handle.
1315  *
1316  * PARAMS
1317  *  handle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1318  *  event          [I] Event to signal upon completion (or NULL)
1319  *  apc            [I] Callback to call upon completion (or NULL)
1320  *  apc_context    [I] Context for ApcRoutine (or NULL)
1321  *  io             [O] Receives information about the operation on return
1322  *  code           [I] Control code for the operation to perform
1323  *  in_buffer      [I] Source for any input data required (or NULL)
1324  *  in_size        [I] Size of InputBuffer
1325  *  out_buffer     [O] Source for any output data returned (or NULL)
1326  *  out_size       [I] Size of OutputBuffer
1327  *
1328  * RETURNS
1329  *  Success: 0. IoStatusBlock is updated.
1330  *  Failure: An NTSTATUS error code describing the error.
1331  */
1332 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
1333                                       PIO_APC_ROUTINE apc, PVOID apc_context,
1334                                       PIO_STATUS_BLOCK io, ULONG code,
1335                                       PVOID in_buffer, ULONG in_size,
1336                                       PVOID out_buffer, ULONG out_size)
1337 {
1338     ULONG device = (code >> 16);
1339     NTSTATUS status = STATUS_NOT_SUPPORTED;
1340
1341     TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1342           handle, event, apc, apc_context, io, code,
1343           in_buffer, in_size, out_buffer, out_size);
1344
1345     switch(device)
1346     {
1347     case FILE_DEVICE_DISK:
1348     case FILE_DEVICE_CD_ROM:
1349     case FILE_DEVICE_DVD:
1350     case FILE_DEVICE_CONTROLLER:
1351     case FILE_DEVICE_MASS_STORAGE:
1352         status = CDROM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1353                                        in_buffer, in_size, out_buffer, out_size);
1354         break;
1355     case FILE_DEVICE_SERIAL_PORT:
1356         status = COMM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1357                                       in_buffer, in_size, out_buffer, out_size);
1358         break;
1359     case FILE_DEVICE_TAPE:
1360         status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
1361                                       in_buffer, in_size, out_buffer, out_size);
1362         break;
1363     }
1364
1365     if (status == STATUS_NOT_SUPPORTED || status == STATUS_BAD_DEVICE_TYPE)
1366         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1367                                     in_buffer, in_size, out_buffer, out_size );
1368
1369     if (status != STATUS_PENDING) io->u.Status = status;
1370     return status;
1371 }
1372
1373
1374 /**************************************************************************
1375  *              NtFsControlFile                 [NTDLL.@]
1376  *              ZwFsControlFile                 [NTDLL.@]
1377  *
1378  * Perform a file system control operation on an open file handle.
1379  *
1380  * PARAMS
1381  *  handle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1382  *  event          [I] Event to signal upon completion (or NULL)
1383  *  apc            [I] Callback to call upon completion (or NULL)
1384  *  apc_context    [I] Context for ApcRoutine (or NULL)
1385  *  io             [O] Receives information about the operation on return
1386  *  code           [I] Control code for the operation to perform
1387  *  in_buffer      [I] Source for any input data required (or NULL)
1388  *  in_size        [I] Size of InputBuffer
1389  *  out_buffer     [O] Source for any output data returned (or NULL)
1390  *  out_size       [I] Size of OutputBuffer
1391  *
1392  * RETURNS
1393  *  Success: 0. IoStatusBlock is updated.
1394  *  Failure: An NTSTATUS error code describing the error.
1395  */
1396 NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
1397                                 PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code,
1398                                 PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size)
1399 {
1400     NTSTATUS status;
1401
1402     TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1403           handle, event, apc, apc_context, io, code,
1404           in_buffer, in_size, out_buffer, out_size);
1405
1406     if (!io) return STATUS_INVALID_PARAMETER;
1407
1408     ignore_server_ioctl_struct_holes( code, in_buffer, in_size );
1409
1410     switch(code)
1411     {
1412     case FSCTL_DISMOUNT_VOLUME:
1413         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1414                                     in_buffer, in_size, out_buffer, out_size );
1415         if (!status) status = DIR_unmount_device( handle );
1416         break;
1417
1418     case FSCTL_PIPE_PEEK:
1419         {
1420             FILE_PIPE_PEEK_BUFFER *buffer = out_buffer;
1421             int avail = 0, fd, needs_close;
1422
1423             if (out_size < FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ))
1424             {
1425                 status = STATUS_INFO_LENGTH_MISMATCH;
1426                 break;
1427             }
1428
1429             if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )))
1430                 break;
1431
1432 #ifdef FIONREAD
1433             if (ioctl( fd, FIONREAD, &avail ) != 0)
1434             {
1435                 TRACE("FIONREAD failed reason: %s\n",strerror(errno));
1436                 if (needs_close) close( fd );
1437                 status = FILE_GetNtStatus();
1438                 break;
1439             }
1440 #endif
1441             if (!avail)  /* check for closed pipe */
1442             {
1443                 struct pollfd pollfd;
1444                 int ret;
1445
1446                 pollfd.fd = fd;
1447                 pollfd.events = POLLIN;
1448                 pollfd.revents = 0;
1449                 ret = poll( &pollfd, 1, 0 );
1450                 if (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR))))
1451                 {
1452                     if (needs_close) close( fd );
1453                     status = STATUS_PIPE_BROKEN;
1454                     break;
1455                 }
1456             }
1457             buffer->NamedPipeState    = 0;  /* FIXME */
1458             buffer->ReadDataAvailable = avail;
1459             buffer->NumberOfMessages  = 0;  /* FIXME */
1460             buffer->MessageLength     = 0;  /* FIXME */
1461             io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1462             status = STATUS_SUCCESS;
1463             if (avail)
1464             {
1465                 ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1466                 if (data_size)
1467                 {
1468                     int res = recv( fd, buffer->Data, data_size, MSG_PEEK );
1469                     if (res >= 0) io->Information += res;
1470                 }
1471             }
1472             if (needs_close) close( fd );
1473         }
1474         break;
1475
1476     case FSCTL_PIPE_DISCONNECT:
1477         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1478                                     in_buffer, in_size, out_buffer, out_size );
1479         if (!status)
1480         {
1481             int fd = server_remove_fd_from_cache( handle );
1482             if (fd != -1) close( fd );
1483         }
1484         break;
1485
1486     case FSCTL_PIPE_IMPERSONATE:
1487         FIXME("FSCTL_PIPE_IMPERSONATE: impersonating self\n");
1488         status = RtlImpersonateSelf( SecurityImpersonation );
1489         break;
1490
1491     case FSCTL_LOCK_VOLUME:
1492     case FSCTL_UNLOCK_VOLUME:
1493         FIXME("stub! return success - Unsupported fsctl %x (device=%x access=%x func=%x method=%x)\n",
1494               code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1495         status = STATUS_SUCCESS;
1496         break;
1497
1498     case FSCTL_GET_RETRIEVAL_POINTERS:
1499     {
1500         RETRIEVAL_POINTERS_BUFFER *buffer = (RETRIEVAL_POINTERS_BUFFER *)out_buffer;
1501
1502         FIXME("stub: FSCTL_GET_RETRIEVAL_POINTERS\n");
1503
1504         if (out_size >= sizeof(RETRIEVAL_POINTERS_BUFFER))
1505         {
1506             buffer->ExtentCount                 = 1;
1507             buffer->StartingVcn.QuadPart        = 1;
1508             buffer->Extents[0].NextVcn.QuadPart = 0;
1509             buffer->Extents[0].Lcn.QuadPart     = 0;
1510             io->Information = sizeof(RETRIEVAL_POINTERS_BUFFER);
1511             status = STATUS_SUCCESS;
1512         }
1513         else
1514         {
1515             io->Information = 0;
1516             status = STATUS_BUFFER_TOO_SMALL;
1517         }
1518         break;
1519     }
1520     case FSCTL_PIPE_LISTEN:
1521     case FSCTL_PIPE_WAIT:
1522     default:
1523         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1524                                     in_buffer, in_size, out_buffer, out_size );
1525         break;
1526     }
1527
1528     if (status != STATUS_PENDING) io->u.Status = status;
1529     return status;
1530 }
1531
1532 /******************************************************************************
1533  *  NtSetVolumeInformationFile          [NTDLL.@]
1534  *  ZwSetVolumeInformationFile          [NTDLL.@]
1535  *
1536  * Set volume information for an open file handle.
1537  *
1538  * PARAMS
1539  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1540  *  IoStatusBlock      [O] Receives information about the operation on return
1541  *  FsInformation      [I] Source for volume information
1542  *  Length             [I] Size of FsInformation
1543  *  FsInformationClass [I] Type of volume information to set
1544  *
1545  * RETURNS
1546  *  Success: 0. IoStatusBlock is updated.
1547  *  Failure: An NTSTATUS error code describing the error.
1548  */
1549 NTSTATUS WINAPI NtSetVolumeInformationFile(
1550         IN HANDLE FileHandle,
1551         PIO_STATUS_BLOCK IoStatusBlock,
1552         PVOID FsInformation,
1553         ULONG Length,
1554         FS_INFORMATION_CLASS FsInformationClass)
1555 {
1556         FIXME("(%p,%p,%p,0x%08x,0x%08x) stub\n",
1557         FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
1558         return 0;
1559 }
1560
1561 static NTSTATUS set_file_times( int fd, const LARGE_INTEGER *mtime, const LARGE_INTEGER *atime )
1562 {
1563     NTSTATUS status = STATUS_SUCCESS;
1564
1565 #ifdef HAVE_FUTIMENS
1566     struct timespec tv[2];
1567
1568     tv[0].tv_sec = tv[1].tv_sec = 0;
1569     tv[0].tv_nsec = tv[1].tv_nsec = UTIME_OMIT;
1570     if (atime->QuadPart)
1571     {
1572         tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
1573         tv[0].tv_nsec = (atime->QuadPart % 10000000) * 100;
1574     }
1575     if (mtime->QuadPart)
1576     {
1577         tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
1578         tv[1].tv_nsec = (mtime->QuadPart % 10000000) * 100;
1579     }
1580     if (futimens( fd, tv ) == -1) status = FILE_GetNtStatus();
1581
1582 #elif defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
1583     struct timeval tv[2];
1584     struct stat st;
1585
1586     if (!atime->QuadPart || !mtime->QuadPart)
1587     {
1588
1589         tv[0].tv_sec = tv[0].tv_usec = 0;
1590         tv[1].tv_sec = tv[1].tv_usec = 0;
1591         if (!fstat( fd, &st ))
1592         {
1593             tv[0].tv_sec = st.st_atime;
1594             tv[1].tv_sec = st.st_mtime;
1595 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1596             tv[0].tv_usec = st.st_atim.tv_nsec / 1000;
1597 #endif
1598 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1599             tv[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1600 #endif
1601         }
1602     }
1603     if (atime->QuadPart)
1604     {
1605         tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
1606         tv[0].tv_usec = (atime->QuadPart % 10000000) / 10;
1607     }
1608     if (mtime->QuadPart)
1609     {
1610         tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
1611         tv[1].tv_usec = (mtime->QuadPart % 10000000) / 10;
1612     }
1613 #ifdef HAVE_FUTIMES
1614     if (futimes( fd, tv ) == -1) status = FILE_GetNtStatus();
1615 #elif defined(HAVE_FUTIMESAT)
1616     if (futimesat( fd, NULL, tv ) == -1) status = FILE_GetNtStatus();
1617 #endif
1618
1619 #else  /* HAVE_FUTIMES || HAVE_FUTIMESAT */
1620     FIXME( "setting file times not supported\n" );
1621     status = STATUS_NOT_IMPLEMENTED;
1622 #endif
1623     return status;
1624 }
1625
1626 static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, LARGE_INTEGER *ctime,
1627                                    LARGE_INTEGER *atime, LARGE_INTEGER *creation )
1628 {
1629     RtlSecondsSince1970ToTime( st->st_mtime, mtime );
1630     RtlSecondsSince1970ToTime( st->st_ctime, ctime );
1631     RtlSecondsSince1970ToTime( st->st_atime, atime );
1632 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1633     mtime->QuadPart += st->st_mtim.tv_nsec / 100;
1634 #endif
1635 #ifdef HAVE_STRUCT_STAT_ST_CTIM
1636     ctime->QuadPart += st->st_ctim.tv_nsec / 100;
1637 #endif
1638 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1639     atime->QuadPart += st->st_atim.tv_nsec / 100;
1640 #endif
1641     *creation = *mtime;
1642 }
1643
1644 /* fill in the file information that depends on the stat info */
1645 NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLASS class )
1646 {
1647     switch (class)
1648     {
1649     case FileBasicInformation:
1650         {
1651             FILE_BASIC_INFORMATION *info = ptr;
1652
1653             get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
1654                             &info->LastAccessTime, &info->CreationTime );
1655             if (S_ISDIR(st->st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1656             else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1657             if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1658                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1659         }
1660         break;
1661     case FileStandardInformation:
1662         {
1663             FILE_STANDARD_INFORMATION *info = ptr;
1664
1665             if ((info->Directory = S_ISDIR(st->st_mode)))
1666             {
1667                 info->AllocationSize.QuadPart = 0;
1668                 info->EndOfFile.QuadPart      = 0;
1669                 info->NumberOfLinks           = 1;
1670             }
1671             else
1672             {
1673                 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
1674                 info->EndOfFile.QuadPart      = st->st_size;
1675                 info->NumberOfLinks           = st->st_nlink;
1676             }
1677         }
1678         break;
1679     case FileInternalInformation:
1680         {
1681             FILE_INTERNAL_INFORMATION *info = ptr;
1682             info->IndexNumber.QuadPart = st->st_ino;
1683         }
1684         break;
1685     case FileEndOfFileInformation:
1686         {
1687             FILE_END_OF_FILE_INFORMATION *info = ptr;
1688             info->EndOfFile.QuadPart = S_ISDIR(st->st_mode) ? 0 : st->st_size;
1689         }
1690         break;
1691     case FileAllInformation:
1692         {
1693             FILE_ALL_INFORMATION *info = ptr;
1694             fill_stat_info( st, &info->BasicInformation, FileBasicInformation );
1695             fill_stat_info( st, &info->StandardInformation, FileStandardInformation );
1696             fill_stat_info( st, &info->InternalInformation, FileInternalInformation );
1697         }
1698         break;
1699     /* all directory structures start with the FileDirectoryInformation layout */
1700     case FileBothDirectoryInformation:
1701     case FileFullDirectoryInformation:
1702     case FileDirectoryInformation:
1703         {
1704             FILE_DIRECTORY_INFORMATION *info = ptr;
1705
1706             get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
1707                             &info->LastAccessTime, &info->CreationTime );
1708             if (S_ISDIR(st->st_mode))
1709             {
1710                 info->AllocationSize.QuadPart = 0;
1711                 info->EndOfFile.QuadPart      = 0;
1712                 info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1713             }
1714             else
1715             {
1716                 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
1717                 info->EndOfFile.QuadPart      = st->st_size;
1718                 info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1719             }
1720             if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1721                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1722         }
1723         break;
1724     case FileIdFullDirectoryInformation:
1725         {
1726             FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr;
1727             info->FileId.QuadPart = st->st_ino;
1728             fill_stat_info( st, info, FileDirectoryInformation );
1729         }
1730         break;
1731     case FileIdBothDirectoryInformation:
1732         {
1733             FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr;
1734             info->FileId.QuadPart = st->st_ino;
1735             fill_stat_info( st, info, FileDirectoryInformation );
1736         }
1737         break;
1738
1739     default:
1740         return STATUS_INVALID_INFO_CLASS;
1741     }
1742     return STATUS_SUCCESS;
1743 }
1744
1745 NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name )
1746 {
1747     data_size_t size = 1024;
1748     NTSTATUS ret;
1749     char *name;
1750
1751     for (;;)
1752     {
1753         name = RtlAllocateHeap( GetProcessHeap(), 0, size + 1 );
1754         if (!name) return STATUS_NO_MEMORY;
1755         unix_name->MaximumLength = size + 1;
1756
1757         SERVER_START_REQ( get_handle_unix_name )
1758         {
1759             req->handle = wine_server_obj_handle( handle );
1760             wine_server_set_reply( req, name, size );
1761             ret = wine_server_call( req );
1762             size = reply->name_len;
1763         }
1764         SERVER_END_REQ;
1765
1766         if (!ret)
1767         {
1768             name[size] = 0;
1769             unix_name->Buffer = name;
1770             unix_name->Length = size;
1771             break;
1772         }
1773         RtlFreeHeap( GetProcessHeap(), 0, name );
1774         if (ret != STATUS_BUFFER_OVERFLOW) break;
1775     }
1776     return ret;
1777 }
1778
1779 static NTSTATUS fill_name_info( const ANSI_STRING *unix_name, FILE_NAME_INFORMATION *info, LONG *name_len )
1780 {
1781     UNICODE_STRING nt_name;
1782     NTSTATUS status;
1783
1784     if (!(status = wine_unix_to_nt_file_name( unix_name, &nt_name )))
1785     {
1786         const WCHAR *ptr = nt_name.Buffer;
1787         const WCHAR *end = ptr + (nt_name.Length / sizeof(WCHAR));
1788
1789         /* Skip the volume mount point. */
1790         while (ptr != end && *ptr == '\\') ++ptr;
1791         while (ptr != end && *ptr != '\\') ++ptr;
1792         while (ptr != end && *ptr == '\\') ++ptr;
1793         while (ptr != end && *ptr != '\\') ++ptr;
1794
1795         info->FileNameLength = (end - ptr) * sizeof(WCHAR);
1796         if (*name_len < info->FileNameLength) status = STATUS_BUFFER_OVERFLOW;
1797         else *name_len = info->FileNameLength;
1798
1799         memcpy( info->FileName, ptr, *name_len );
1800         RtlFreeUnicodeString( &nt_name );
1801     }
1802
1803     return status;
1804 }
1805
1806 /******************************************************************************
1807  *  NtQueryInformationFile              [NTDLL.@]
1808  *  ZwQueryInformationFile              [NTDLL.@]
1809  *
1810  * Get information about an open file handle.
1811  *
1812  * PARAMS
1813  *  hFile    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1814  *  io       [O] Receives information about the operation on return
1815  *  ptr      [O] Destination for file information
1816  *  len      [I] Size of FileInformation
1817  *  class    [I] Type of file information to get
1818  *
1819  * RETURNS
1820  *  Success: 0. IoStatusBlock and FileInformation are updated.
1821  *  Failure: An NTSTATUS error code describing the error.
1822  */
1823 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
1824                                         PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
1825 {
1826     static const size_t info_sizes[] =
1827     {
1828         0,
1829         sizeof(FILE_DIRECTORY_INFORMATION),            /* FileDirectoryInformation */
1830         sizeof(FILE_FULL_DIRECTORY_INFORMATION),       /* FileFullDirectoryInformation */
1831         sizeof(FILE_BOTH_DIRECTORY_INFORMATION),       /* FileBothDirectoryInformation */
1832         sizeof(FILE_BASIC_INFORMATION),                /* FileBasicInformation */
1833         sizeof(FILE_STANDARD_INFORMATION),             /* FileStandardInformation */
1834         sizeof(FILE_INTERNAL_INFORMATION),             /* FileInternalInformation */
1835         sizeof(FILE_EA_INFORMATION),                   /* FileEaInformation */
1836         sizeof(FILE_ACCESS_INFORMATION),               /* FileAccessInformation */
1837         sizeof(FILE_NAME_INFORMATION),                 /* FileNameInformation */
1838         sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
1839         0,                                             /* FileLinkInformation */
1840         sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR),  /* FileNamesInformation */
1841         sizeof(FILE_DISPOSITION_INFORMATION),          /* FileDispositionInformation */
1842         sizeof(FILE_POSITION_INFORMATION),             /* FilePositionInformation */
1843         sizeof(FILE_FULL_EA_INFORMATION),              /* FileFullEaInformation */
1844         sizeof(FILE_MODE_INFORMATION),                 /* FileModeInformation */
1845         sizeof(FILE_ALIGNMENT_INFORMATION),            /* FileAlignmentInformation */
1846         sizeof(FILE_ALL_INFORMATION),                  /* FileAllInformation */
1847         sizeof(FILE_ALLOCATION_INFORMATION),           /* FileAllocationInformation */
1848         sizeof(FILE_END_OF_FILE_INFORMATION),          /* FileEndOfFileInformation */
1849         0,                                             /* FileAlternateNameInformation */
1850         sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
1851         0,                                             /* FilePipeInformation */
1852         sizeof(FILE_PIPE_LOCAL_INFORMATION),           /* FilePipeLocalInformation */
1853         0,                                             /* FilePipeRemoteInformation */
1854         sizeof(FILE_MAILSLOT_QUERY_INFORMATION),       /* FileMailslotQueryInformation */
1855         0,                                             /* FileMailslotSetInformation */
1856         0,                                             /* FileCompressionInformation */
1857         0,                                             /* FileObjectIdInformation */
1858         0,                                             /* FileCompletionInformation */
1859         0,                                             /* FileMoveClusterInformation */
1860         0,                                             /* FileQuotaInformation */
1861         0,                                             /* FileReparsePointInformation */
1862         0,                                             /* FileNetworkOpenInformation */
1863         0,                                             /* FileAttributeTagInformation */
1864         0,                                             /* FileTrackingInformation */
1865         0,                                             /* FileIdBothDirectoryInformation */
1866         0,                                             /* FileIdFullDirectoryInformation */
1867         0,                                             /* FileValidDataLengthInformation */
1868         0,                                             /* FileShortNameInformation */
1869         0,
1870         0,
1871         0,
1872         0,                                             /* FileSfioReserveInformation */
1873         0,                                             /* FileSfioVolumeInformation */
1874         0,                                             /* FileHardLinkInformation */
1875         0,
1876         0,                                             /* FileNormalizedNameInformation */
1877         0,
1878         0,                                             /* FileIdGlobalTxDirectoryInformation */
1879         0,
1880         0,
1881         0,
1882         0                                              /* FileStandardLinkInformation */
1883     };
1884
1885     struct stat st;
1886     int fd, needs_close = FALSE;
1887
1888     TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
1889
1890     io->Information = 0;
1891
1892     if (class <= 0 || class >= FileMaximumInformation)
1893         return io->u.Status = STATUS_INVALID_INFO_CLASS;
1894     if (!info_sizes[class])
1895     {
1896         FIXME("Unsupported class (%d)\n", class);
1897         return io->u.Status = STATUS_NOT_IMPLEMENTED;
1898     }
1899     if (len < info_sizes[class])
1900         return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
1901
1902     if (class != FilePipeLocalInformation)
1903     {
1904         if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, NULL )))
1905             return io->u.Status;
1906     }
1907
1908     switch (class)
1909     {
1910     case FileBasicInformation:
1911         if (fstat( fd, &st ) == -1)
1912             io->u.Status = FILE_GetNtStatus();
1913         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1914             io->u.Status = STATUS_INVALID_INFO_CLASS;
1915         else
1916             fill_stat_info( &st, ptr, class );
1917         break;
1918     case FileStandardInformation:
1919         {
1920             FILE_STANDARD_INFORMATION *info = ptr;
1921
1922             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1923             else
1924             {
1925                 fill_stat_info( &st, info, class );
1926                 info->DeletePending = FALSE; /* FIXME */
1927             }
1928         }
1929         break;
1930     case FilePositionInformation:
1931         {
1932             FILE_POSITION_INFORMATION *info = ptr;
1933             off_t res = lseek( fd, 0, SEEK_CUR );
1934             if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
1935             else info->CurrentByteOffset.QuadPart = res;
1936         }
1937         break;
1938     case FileInternalInformation:
1939         if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1940         else fill_stat_info( &st, ptr, class );
1941         break;
1942     case FileEaInformation:
1943         {
1944             FILE_EA_INFORMATION *info = ptr;
1945             info->EaSize = 0;
1946         }
1947         break;
1948     case FileEndOfFileInformation:
1949         if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1950         else fill_stat_info( &st, ptr, class );
1951         break;
1952     case FileAllInformation:
1953         {
1954             FILE_ALL_INFORMATION *info = ptr;
1955             ANSI_STRING unix_name;
1956
1957             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1958             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1959                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1960             else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
1961             {
1962                 LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
1963
1964                 fill_stat_info( &st, info, FileAllInformation );
1965                 info->StandardInformation.DeletePending = FALSE; /* FIXME */
1966                 info->EaInformation.EaSize = 0;
1967                 info->AccessInformation.AccessFlags = 0;  /* FIXME */
1968                 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
1969                 info->ModeInformation.Mode = 0;  /* FIXME */
1970                 info->AlignmentInformation.AlignmentRequirement = 1;  /* FIXME */
1971
1972                 io->u.Status = fill_name_info( &unix_name, &info->NameInformation, &name_len );
1973                 RtlFreeAnsiString( &unix_name );
1974                 io->Information = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + name_len;
1975             }
1976         }
1977         break;
1978     case FileMailslotQueryInformation:
1979         {
1980             FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
1981
1982             SERVER_START_REQ( set_mailslot_info )
1983             {
1984                 req->handle = wine_server_obj_handle( hFile );
1985                 req->flags = 0;
1986                 io->u.Status = wine_server_call( req );
1987                 if( io->u.Status == STATUS_SUCCESS )
1988                 {
1989                     info->MaximumMessageSize = reply->max_msgsize;
1990                     info->MailslotQuota = 0;
1991                     info->NextMessageSize = 0;
1992                     info->MessagesAvailable = 0;
1993                     info->ReadTimeout.QuadPart = reply->read_timeout;
1994                 }
1995             }
1996             SERVER_END_REQ;
1997             if (!io->u.Status)
1998             {
1999                 char *tmpbuf;
2000                 ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000;
2001                 if (size > 0x10000) size = 0x10000;
2002                 if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2003                 {
2004                     int fd, needs_close;
2005                     if (!server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
2006                     {
2007                         int res = recv( fd, tmpbuf, size, MSG_PEEK );
2008                         info->MessagesAvailable = (res > 0);
2009                         info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE;
2010                         if (needs_close) close( fd );
2011                     }
2012                     RtlFreeHeap( GetProcessHeap(), 0, tmpbuf );
2013                 }
2014             }
2015         }
2016         break;
2017     case FilePipeLocalInformation:
2018         {
2019             FILE_PIPE_LOCAL_INFORMATION* pli = ptr;
2020
2021             SERVER_START_REQ( get_named_pipe_info )
2022             {
2023                 req->handle = wine_server_obj_handle( hFile );
2024                 if (!(io->u.Status = wine_server_call( req )))
2025                 {
2026                     pli->NamedPipeType = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ? 
2027                         FILE_PIPE_TYPE_MESSAGE : FILE_PIPE_TYPE_BYTE;
2028                     switch (reply->sharing)
2029                     {
2030                         case FILE_SHARE_READ:
2031                             pli->NamedPipeConfiguration = FILE_PIPE_OUTBOUND;
2032                             break;
2033                         case FILE_SHARE_WRITE:
2034                             pli->NamedPipeConfiguration = FILE_PIPE_INBOUND;
2035                             break;
2036                         case FILE_SHARE_READ | FILE_SHARE_WRITE:
2037                             pli->NamedPipeConfiguration = FILE_PIPE_FULL_DUPLEX;
2038                             break;
2039                     }
2040                     pli->MaximumInstances = reply->maxinstances;
2041                     pli->CurrentInstances = reply->instances;
2042                     pli->InboundQuota = reply->insize;
2043                     pli->ReadDataAvailable = 0; /* FIXME */
2044                     pli->OutboundQuota = reply->outsize;
2045                     pli->WriteQuotaAvailable = 0; /* FIXME */
2046                     pli->NamedPipeState = 0; /* FIXME */
2047                     pli->NamedPipeEnd = (reply->flags & NAMED_PIPE_SERVER_END) ?
2048                         FILE_PIPE_SERVER_END : FILE_PIPE_CLIENT_END;
2049                 }
2050             }
2051             SERVER_END_REQ;
2052         }
2053         break;
2054     case FileNameInformation:
2055         {
2056             FILE_NAME_INFORMATION *info = ptr;
2057             ANSI_STRING unix_name;
2058
2059             if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2060             {
2061                 LONG name_len = len - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2062                 io->u.Status = fill_name_info( &unix_name, info, &name_len );
2063                 RtlFreeAnsiString( &unix_name );
2064                 io->Information = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + name_len;
2065             }
2066         }
2067         break;
2068     default:
2069         FIXME("Unsupported class (%d)\n", class);
2070         io->u.Status = STATUS_NOT_IMPLEMENTED;
2071         break;
2072     }
2073     if (needs_close) close( fd );
2074     if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
2075     return io->u.Status;
2076 }
2077
2078 /******************************************************************************
2079  *  NtSetInformationFile                [NTDLL.@]
2080  *  ZwSetInformationFile                [NTDLL.@]
2081  *
2082  * Set information about an open file handle.
2083  *
2084  * PARAMS
2085  *  handle  [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2086  *  io      [O] Receives information about the operation on return
2087  *  ptr     [I] Source for file information
2088  *  len     [I] Size of FileInformation
2089  *  class   [I] Type of file information to set
2090  *
2091  * RETURNS
2092  *  Success: 0. io is updated.
2093  *  Failure: An NTSTATUS error code describing the error.
2094  */
2095 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
2096                                      PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
2097 {
2098     int fd, needs_close;
2099
2100     TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", handle, io, ptr, len, class);
2101
2102     io->u.Status = STATUS_SUCCESS;
2103     switch (class)
2104     {
2105     case FileBasicInformation:
2106         if (len >= sizeof(FILE_BASIC_INFORMATION))
2107         {
2108             struct stat st;
2109             const FILE_BASIC_INFORMATION *info = ptr;
2110
2111             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2112                 return io->u.Status;
2113
2114             if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
2115                 io->u.Status = set_file_times( fd, &info->LastWriteTime, &info->LastAccessTime );
2116
2117             if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
2118             {
2119                 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2120                 else
2121                 {
2122                     if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
2123                     {
2124                         if (S_ISDIR( st.st_mode))
2125                             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
2126                         else
2127                             st.st_mode &= ~0222; /* clear write permission bits */
2128                     }
2129                     else
2130                     {
2131                         /* add write permission only where we already have read permission */
2132                         st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
2133                     }
2134                     if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
2135                 }
2136             }
2137
2138             if (needs_close) close( fd );
2139         }
2140         else io->u.Status = STATUS_INVALID_PARAMETER_3;
2141         break;
2142
2143     case FilePositionInformation:
2144         if (len >= sizeof(FILE_POSITION_INFORMATION))
2145         {
2146             const FILE_POSITION_INFORMATION *info = ptr;
2147
2148             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2149                 return io->u.Status;
2150
2151             if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
2152                 io->u.Status = FILE_GetNtStatus();
2153
2154             if (needs_close) close( fd );
2155         }
2156         else io->u.Status = STATUS_INVALID_PARAMETER_3;
2157         break;
2158
2159     case FileEndOfFileInformation:
2160         if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
2161         {
2162             struct stat st;
2163             const FILE_END_OF_FILE_INFORMATION *info = ptr;
2164
2165             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2166                 return io->u.Status;
2167
2168             /* first try normal truncate */
2169             if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2170
2171             /* now check for the need to extend the file */
2172             if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
2173             {
2174                 static const char zero;
2175
2176                 /* extend the file one byte beyond the requested size and then truncate it */
2177                 /* this should work around ftruncate implementations that can't extend files */
2178                 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
2179                     ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2180             }
2181             io->u.Status = FILE_GetNtStatus();
2182
2183             if (needs_close) close( fd );
2184         }
2185         else io->u.Status = STATUS_INVALID_PARAMETER_3;
2186         break;
2187
2188     case FileMailslotSetInformation:
2189         {
2190             FILE_MAILSLOT_SET_INFORMATION *info = ptr;
2191
2192             SERVER_START_REQ( set_mailslot_info )
2193             {
2194                 req->handle = wine_server_obj_handle( handle );
2195                 req->flags = MAILSLOT_SET_READ_TIMEOUT;
2196                 req->read_timeout = info->ReadTimeout.QuadPart;
2197                 io->u.Status = wine_server_call( req );
2198             }
2199             SERVER_END_REQ;
2200         }
2201         break;
2202
2203     case FileCompletionInformation:
2204         if (len >= sizeof(FILE_COMPLETION_INFORMATION))
2205         {
2206             FILE_COMPLETION_INFORMATION *info = ptr;
2207
2208             SERVER_START_REQ( set_completion_info )
2209             {
2210                 req->handle   = wine_server_obj_handle( handle );
2211                 req->chandle  = wine_server_obj_handle( info->CompletionPort );
2212                 req->ckey     = info->CompletionKey;
2213                 io->u.Status  = wine_server_call( req );
2214             }
2215             SERVER_END_REQ;
2216         } else
2217             io->u.Status = STATUS_INVALID_PARAMETER_3;
2218         break;
2219
2220     case FileAllInformation:
2221         io->u.Status = STATUS_INVALID_INFO_CLASS;
2222         break;
2223
2224     default:
2225         FIXME("Unsupported class (%d)\n", class);
2226         io->u.Status = STATUS_NOT_IMPLEMENTED;
2227         break;
2228     }
2229     io->Information = 0;
2230     return io->u.Status;
2231 }
2232
2233
2234 /******************************************************************************
2235  *              NtQueryFullAttributesFile   (NTDLL.@)
2236  */
2237 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
2238                                            FILE_NETWORK_OPEN_INFORMATION *info )
2239 {
2240     ANSI_STRING unix_name;
2241     NTSTATUS status;
2242
2243     if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2244     {
2245         struct stat st;
2246
2247         if (stat( unix_name.Buffer, &st ) == -1)
2248             status = FILE_GetNtStatus();
2249         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2250             status = STATUS_INVALID_INFO_CLASS;
2251         else
2252         {
2253             FILE_BASIC_INFORMATION basic;
2254             FILE_STANDARD_INFORMATION std;
2255
2256             fill_stat_info( &st, &basic, FileBasicInformation );
2257             fill_stat_info( &st, &std, FileStandardInformation );
2258
2259             info->CreationTime   = basic.CreationTime;
2260             info->LastAccessTime = basic.LastAccessTime;
2261             info->LastWriteTime  = basic.LastWriteTime;
2262             info->ChangeTime     = basic.ChangeTime;
2263             info->AllocationSize = std.AllocationSize;
2264             info->EndOfFile      = std.EndOfFile;
2265             info->FileAttributes = basic.FileAttributes;
2266             if (DIR_is_hidden_file( attr->ObjectName ))
2267                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2268         }
2269         RtlFreeAnsiString( &unix_name );
2270     }
2271     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2272     return status;
2273 }
2274
2275
2276 /******************************************************************************
2277  *              NtQueryAttributesFile   (NTDLL.@)
2278  *              ZwQueryAttributesFile   (NTDLL.@)
2279  */
2280 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
2281 {
2282     ANSI_STRING unix_name;
2283     NTSTATUS status;
2284
2285     if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2286     {
2287         struct stat st;
2288
2289         if (stat( unix_name.Buffer, &st ) == -1)
2290             status = FILE_GetNtStatus();
2291         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2292             status = STATUS_INVALID_INFO_CLASS;
2293         else
2294         {
2295             status = fill_stat_info( &st, info, FileBasicInformation );
2296             if (DIR_is_hidden_file( attr->ObjectName ))
2297                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2298         }
2299         RtlFreeAnsiString( &unix_name );
2300     }
2301     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2302     return status;
2303 }
2304
2305
2306 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2307 /* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */
2308 static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename,
2309                                             unsigned int flags )
2310 {
2311     if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename))
2312     {
2313         info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2314         /* Don't assume read-only, let the mount options set it below */
2315         info->Characteristics |= FILE_REMOVABLE_MEDIA;
2316     }
2317     else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) ||
2318              !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename))
2319     {
2320         info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2321         info->Characteristics |= FILE_REMOTE_DEVICE;
2322     }
2323     else if (!strcmp("procfs", fstypename))
2324         info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2325     else
2326         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2327
2328     if (flags & MNT_RDONLY)
2329         info->Characteristics |= FILE_READ_ONLY_DEVICE;
2330
2331     if (!(flags & MNT_LOCAL))
2332     {
2333         info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2334         info->Characteristics |= FILE_REMOTE_DEVICE;
2335     }
2336 }
2337 #endif
2338
2339 static inline int is_device_placeholder( int fd )
2340 {
2341     static const char wine_placeholder[] = "Wine device placeholder";
2342     char buffer[sizeof(wine_placeholder)-1];
2343
2344     if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
2345         return 0;
2346     return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
2347 }
2348
2349 /******************************************************************************
2350  *              get_device_info
2351  *
2352  * Implementation of the FileFsDeviceInformation query for NtQueryVolumeInformationFile.
2353  */
2354 static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
2355 {
2356     struct stat st;
2357
2358     info->Characteristics = 0;
2359     if (fstat( fd, &st ) < 0) return FILE_GetNtStatus();
2360     if (S_ISCHR( st.st_mode ))
2361     {
2362         info->DeviceType = FILE_DEVICE_UNKNOWN;
2363 #ifdef linux
2364         switch(major(st.st_rdev))
2365         {
2366         case MEM_MAJOR:
2367             info->DeviceType = FILE_DEVICE_NULL;
2368             break;
2369         case TTY_MAJOR:
2370             info->DeviceType = FILE_DEVICE_SERIAL_PORT;
2371             break;
2372         case LP_MAJOR:
2373             info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
2374             break;
2375         case SCSI_TAPE_MAJOR:
2376             info->DeviceType = FILE_DEVICE_TAPE;
2377             break;
2378         }
2379 #endif
2380     }
2381     else if (S_ISBLK( st.st_mode ))
2382     {
2383         info->DeviceType = FILE_DEVICE_DISK;
2384     }
2385     else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
2386     {
2387         info->DeviceType = FILE_DEVICE_NAMED_PIPE;
2388     }
2389     else if (is_device_placeholder( fd ))
2390     {
2391         info->DeviceType = FILE_DEVICE_DISK;
2392     }
2393     else  /* regular file or directory */
2394     {
2395 #if defined(linux) && defined(HAVE_FSTATFS)
2396         struct statfs stfs;
2397
2398         /* check for floppy disk */
2399         if (major(st.st_dev) == FLOPPY_MAJOR)
2400             info->Characteristics |= FILE_REMOVABLE_MEDIA;
2401
2402         if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
2403         switch (stfs.f_type)
2404         {
2405         case 0x9660:      /* iso9660 */
2406         case 0x9fa1:      /* supermount */
2407         case 0x15013346:  /* udf */
2408             info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2409             info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2410             break;
2411         case 0x6969:  /* nfs */
2412         case 0x517B:  /* smbfs */
2413         case 0x564c:  /* ncpfs */
2414             info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2415             info->Characteristics |= FILE_REMOTE_DEVICE;
2416             break;
2417         case 0x01021994:  /* tmpfs */
2418         case 0x28cd3d45:  /* cramfs */
2419         case 0x1373:      /* devfs */
2420         case 0x9fa0:      /* procfs */
2421             info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2422             break;
2423         default:
2424             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2425             break;
2426         }
2427 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2428         struct statfs stfs;
2429
2430         if (fstatfs( fd, &stfs ) < 0)
2431             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2432         else
2433             get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags );
2434 #elif defined(__NetBSD__)
2435         struct statvfs stfs;
2436
2437         if (fstatvfs( fd, &stfs) < 0)
2438             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2439         else
2440             get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag );
2441 #elif defined(sun)
2442         /* Use dkio to work out device types */
2443         {
2444 # include <sys/dkio.h>
2445 # include <sys/vtoc.h>
2446             struct dk_cinfo dkinf;
2447             int retval = ioctl(fd, DKIOCINFO, &dkinf);
2448             if(retval==-1){
2449                 WARN("Unable to get disk device type information - assuming a disk like device\n");
2450                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2451             }
2452             switch (dkinf.dki_ctype)
2453             {
2454             case DKC_CDROM:
2455                 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2456                 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2457                 break;
2458             case DKC_NCRFLOPPY:
2459             case DKC_SMSFLOPPY:
2460             case DKC_INTEL82072:
2461             case DKC_INTEL82077:
2462                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2463                 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2464                 break;
2465             case DKC_MD:
2466                 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2467                 break;
2468             default:
2469                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2470             }
2471         }
2472 #else
2473         static int warned;
2474         if (!warned++) FIXME( "device info not properly supported on this platform\n" );
2475         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2476 #endif
2477         info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
2478     }
2479     return STATUS_SUCCESS;
2480 }
2481
2482
2483 /******************************************************************************
2484  *  NtQueryVolumeInformationFile                [NTDLL.@]
2485  *  ZwQueryVolumeInformationFile                [NTDLL.@]
2486  *
2487  * Get volume information for an open file handle.
2488  *
2489  * PARAMS
2490  *  handle      [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2491  *  io          [O] Receives information about the operation on return
2492  *  buffer      [O] Destination for volume information
2493  *  length      [I] Size of FsInformation
2494  *  info_class  [I] Type of volume information to set
2495  *
2496  * RETURNS
2497  *  Success: 0. io and buffer are updated.
2498  *  Failure: An NTSTATUS error code describing the error.
2499  */
2500 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
2501                                               PVOID buffer, ULONG length,
2502                                               FS_INFORMATION_CLASS info_class )
2503 {
2504     int fd, needs_close;
2505     struct stat st;
2506     static int once;
2507
2508     if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
2509         return io->u.Status;
2510
2511     io->u.Status = STATUS_NOT_IMPLEMENTED;
2512     io->Information = 0;
2513
2514     switch( info_class )
2515     {
2516     case FileFsVolumeInformation:
2517         if (!once++) FIXME( "%p: volume info not supported\n", handle );
2518         break;
2519     case FileFsLabelInformation:
2520         FIXME( "%p: label info not supported\n", handle );
2521         break;
2522     case FileFsSizeInformation:
2523         if (length < sizeof(FILE_FS_SIZE_INFORMATION))
2524             io->u.Status = STATUS_BUFFER_TOO_SMALL;
2525         else
2526         {
2527             FILE_FS_SIZE_INFORMATION *info = buffer;
2528
2529             if (fstat( fd, &st ) < 0)
2530             {
2531                 io->u.Status = FILE_GetNtStatus();
2532                 break;
2533             }
2534             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2535             {
2536                 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
2537             }
2538             else
2539             {
2540                 ULONGLONG bsize;
2541                 /* Linux's fstatvfs is buggy */
2542 #if !defined(linux) || !defined(HAVE_FSTATFS)
2543                 struct statvfs stfs;
2544
2545                 if (fstatvfs( fd, &stfs ) < 0)
2546                 {
2547                     io->u.Status = FILE_GetNtStatus();
2548                     break;
2549                 }
2550                 bsize = stfs.f_frsize;
2551 #else
2552                 struct statfs stfs;
2553                 if (fstatfs( fd, &stfs ) < 0)
2554                 {
2555                     io->u.Status = FILE_GetNtStatus();
2556                     break;
2557                 }
2558                 bsize = stfs.f_bsize;
2559 #endif
2560                 if (bsize == 2048)  /* assume CD-ROM */
2561                 {
2562                     info->BytesPerSector = 2048;
2563                     info->SectorsPerAllocationUnit = 1;
2564                 }
2565                 else
2566                 {
2567                     info->BytesPerSector = 512;
2568                     info->SectorsPerAllocationUnit = 8;
2569                 }
2570                 info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2571                 info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2572                 io->Information = sizeof(*info);
2573                 io->u.Status = STATUS_SUCCESS;
2574             }
2575         }
2576         break;
2577     case FileFsDeviceInformation:
2578         if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
2579             io->u.Status = STATUS_BUFFER_TOO_SMALL;
2580         else
2581         {
2582             FILE_FS_DEVICE_INFORMATION *info = buffer;
2583
2584             if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS)
2585                 io->Information = sizeof(*info);
2586         }
2587         break;
2588     case FileFsAttributeInformation:
2589         FIXME( "%p: attribute info not supported\n", handle );
2590         break;
2591     case FileFsControlInformation:
2592         FIXME( "%p: control info not supported\n", handle );
2593         break;
2594     case FileFsFullSizeInformation:
2595         FIXME( "%p: full size info not supported\n", handle );
2596         break;
2597     case FileFsObjectIdInformation:
2598         FIXME( "%p: object id info not supported\n", handle );
2599         break;
2600     case FileFsMaximumInformation:
2601         FIXME( "%p: maximum info not supported\n", handle );
2602         break;
2603     default:
2604         io->u.Status = STATUS_INVALID_PARAMETER;
2605         break;
2606     }
2607     if (needs_close) close( fd );
2608     return io->u.Status;
2609 }
2610
2611
2612 /******************************************************************
2613  *              NtQueryEaFile  (NTDLL.@)
2614  *
2615  * Read extended attributes from NTFS files.
2616  *
2617  * PARAMS
2618  *  hFile         [I] File handle, must be opened with FILE_READ_EA access
2619  *  iosb          [O] Receives information about the operation on return
2620  *  buffer        [O] Output buffer
2621  *  length        [I] Length of output buffer
2622  *  single_entry  [I] Only read and return one entry
2623  *  ea_list       [I] Optional list with names of EAs to return
2624  *  ea_list_len   [I] Length of ea_list in bytes
2625  *  ea_index      [I] Optional pointer to 1-based index of attribute to return
2626  *  restart       [I] restart EA scan
2627  *
2628  * RETURNS
2629  *  Success: 0. Atrributes read into buffer
2630  *  Failure: An NTSTATUS error code describing the error.
2631  */
2632 NTSTATUS WINAPI NtQueryEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length,
2633                                BOOLEAN single_entry, PVOID ea_list, ULONG ea_list_len,
2634                                PULONG ea_index, BOOLEAN restart )
2635 {
2636     FIXME("(%p,%p,%p,%d,%d,%p,%d,%p,%d) stub\n",
2637             hFile, iosb, buffer, length, single_entry, ea_list,
2638             ea_list_len, ea_index, restart);
2639     return STATUS_ACCESS_DENIED;
2640 }
2641
2642
2643 /******************************************************************
2644  *              NtSetEaFile  (NTDLL.@)
2645  *
2646  * Update extended attributes for NTFS files.
2647  *
2648  * PARAMS
2649  *  hFile         [I] File handle, must be opened with FILE_READ_EA access
2650  *  iosb          [O] Receives information about the operation on return
2651  *  buffer        [I] Buffer with EA information
2652  *  length        [I] Length of buffer
2653  *
2654  * RETURNS
2655  *  Success: 0. Attributes are updated
2656  *  Failure: An NTSTATUS error code describing the error.
2657  */
2658 NTSTATUS WINAPI NtSetEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length )
2659 {
2660     FIXME("(%p,%p,%p,%d) stub\n", hFile, iosb, buffer, length);
2661     return STATUS_ACCESS_DENIED;
2662 }
2663
2664
2665 /******************************************************************
2666  *              NtFlushBuffersFile  (NTDLL.@)
2667  *
2668  * Flush any buffered data on an open file handle.
2669  *
2670  * PARAMS
2671  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2672  *  IoStatusBlock      [O] Receives information about the operation on return
2673  *
2674  * RETURNS
2675  *  Success: 0. IoStatusBlock is updated.
2676  *  Failure: An NTSTATUS error code describing the error.
2677  */
2678 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
2679 {
2680     NTSTATUS ret;
2681     HANDLE hEvent = NULL;
2682
2683     SERVER_START_REQ( flush_file )
2684     {
2685         req->handle = wine_server_obj_handle( hFile );
2686         ret = wine_server_call( req );
2687         hEvent = wine_server_ptr_handle( reply->event );
2688     }
2689     SERVER_END_REQ;
2690     if (!ret && hEvent)
2691     {
2692         ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
2693         NtClose( hEvent );
2694     }
2695     return ret;
2696 }
2697
2698 /******************************************************************
2699  *              NtLockFile       (NTDLL.@)
2700  *
2701  *
2702  */
2703 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
2704                             PIO_APC_ROUTINE apc, void* apc_user,
2705                             PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
2706                             PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
2707                             BOOLEAN exclusive )
2708 {
2709     NTSTATUS    ret;
2710     HANDLE      handle;
2711     BOOLEAN     async;
2712     static BOOLEAN     warn = TRUE;
2713
2714     if (apc || io_status || key)
2715     {
2716         FIXME("Unimplemented yet parameter\n");
2717         return STATUS_NOT_IMPLEMENTED;
2718     }
2719
2720     if (apc_user && warn)
2721     {
2722         FIXME("I/O completion on lock not implemented yet\n");
2723         warn = FALSE;
2724     }
2725
2726     for (;;)
2727     {
2728         SERVER_START_REQ( lock_file )
2729         {
2730             req->handle      = wine_server_obj_handle( hFile );
2731             req->offset      = offset->QuadPart;
2732             req->count       = count->QuadPart;
2733             req->shared      = !exclusive;
2734             req->wait        = !dont_wait;
2735             ret = wine_server_call( req );
2736             handle = wine_server_ptr_handle( reply->handle );
2737             async  = reply->overlapped;
2738         }
2739         SERVER_END_REQ;
2740         if (ret != STATUS_PENDING)
2741         {
2742             if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
2743             return ret;
2744         }
2745
2746         if (async)
2747         {
2748             FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
2749             if (handle) NtClose( handle );
2750             return STATUS_PENDING;
2751         }
2752         if (handle)
2753         {
2754             NtWaitForSingleObject( handle, FALSE, NULL );
2755             NtClose( handle );
2756         }
2757         else
2758         {
2759             LARGE_INTEGER time;
2760     
2761             /* Unix lock conflict, sleep a bit and retry */
2762             time.QuadPart = 100 * (ULONGLONG)10000;
2763             time.QuadPart = -time.QuadPart;
2764             NtDelayExecution( FALSE, &time );
2765         }
2766     }
2767 }
2768
2769
2770 /******************************************************************
2771  *              NtUnlockFile    (NTDLL.@)
2772  *
2773  *
2774  */
2775 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
2776                               PLARGE_INTEGER offset, PLARGE_INTEGER count,
2777                               PULONG key )
2778 {
2779     NTSTATUS status;
2780
2781     TRACE( "%p %x%08x %x%08x\n",
2782            hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
2783
2784     if (io_status || key)
2785     {
2786         FIXME("Unimplemented yet parameter\n");
2787         return STATUS_NOT_IMPLEMENTED;
2788     }
2789
2790     SERVER_START_REQ( unlock_file )
2791     {
2792         req->handle = wine_server_obj_handle( hFile );
2793         req->offset = offset->QuadPart;
2794         req->count  = count->QuadPart;
2795         status = wine_server_call( req );
2796     }
2797     SERVER_END_REQ;
2798     return status;
2799 }
2800
2801 /******************************************************************
2802  *              NtCreateNamedPipeFile    (NTDLL.@)
2803  *
2804  *
2805  */
2806 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
2807                                        POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
2808                                        ULONG sharing, ULONG dispo, ULONG options,
2809                                        ULONG pipe_type, ULONG read_mode, 
2810                                        ULONG completion_mode, ULONG max_inst,
2811                                        ULONG inbound_quota, ULONG outbound_quota,
2812                                        PLARGE_INTEGER timeout)
2813 {
2814     NTSTATUS    status;
2815
2816     TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n",
2817           handle, access, debugstr_w(attr->ObjectName->Buffer), iosb, sharing, dispo,
2818           options, pipe_type, read_mode, completion_mode, max_inst, inbound_quota,
2819           outbound_quota, timeout);
2820
2821     /* assume we only get relative timeout */
2822     if (timeout->QuadPart > 0)
2823         FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
2824
2825     SERVER_START_REQ( create_named_pipe )
2826     {
2827         req->access  = access;
2828         req->attributes = attr->Attributes;
2829         req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2830         req->options = options;
2831         req->sharing = sharing;
2832         req->flags = 
2833             (pipe_type ? NAMED_PIPE_MESSAGE_STREAM_WRITE   : 0) |
2834             (read_mode ? NAMED_PIPE_MESSAGE_STREAM_READ    : 0) |
2835             (completion_mode ? NAMED_PIPE_NONBLOCKING_MODE : 0);
2836         req->maxinstances = max_inst;
2837         req->outsize = outbound_quota;
2838         req->insize  = inbound_quota;
2839         req->timeout = timeout->QuadPart;
2840         wine_server_add_data( req, attr->ObjectName->Buffer,
2841                               attr->ObjectName->Length );
2842         status = wine_server_call( req );
2843         if (!status) *handle = wine_server_ptr_handle( reply->handle );
2844     }
2845     SERVER_END_REQ;
2846     return status;
2847 }
2848
2849 /******************************************************************
2850  *              NtDeleteFile    (NTDLL.@)
2851  *
2852  *
2853  */
2854 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
2855 {
2856     NTSTATUS status;
2857     HANDLE hFile;
2858     IO_STATUS_BLOCK io;
2859
2860     TRACE("%p\n", ObjectAttributes);
2861     status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE | DELETE,
2862                            ObjectAttributes, &io, NULL, 0,
2863                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
2864                            FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
2865     if (status == STATUS_SUCCESS) status = NtClose(hFile);
2866     return status;
2867 }
2868
2869 /******************************************************************
2870  *              NtCancelIoFileEx    (NTDLL.@)
2871  *
2872  *
2873  */
2874 NTSTATUS WINAPI NtCancelIoFileEx( HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status )
2875 {
2876     LARGE_INTEGER timeout;
2877
2878     TRACE("%p %p %p\n", hFile, iosb, io_status );
2879
2880     SERVER_START_REQ( cancel_async )
2881     {
2882         req->handle      = wine_server_obj_handle( hFile );
2883         req->iosb        = wine_server_client_ptr( iosb );
2884         req->only_thread = FALSE;
2885         io_status->u.Status = wine_server_call( req );
2886     }
2887     SERVER_END_REQ;
2888     if (io_status->u.Status)
2889         return io_status->u.Status;
2890
2891     /* Let some APC be run, so that we can run the remaining APCs on hFile
2892      * either the cancelation of the pending one, but also the execution
2893      * of the queued APC, but not yet run. This is needed to ensure proper
2894      * clean-up of allocated data.
2895      */
2896     timeout.QuadPart = 0;
2897     NtDelayExecution( TRUE, &timeout );
2898     return io_status->u.Status;
2899 }
2900
2901 /******************************************************************
2902  *              NtCancelIoFile    (NTDLL.@)
2903  *
2904  *
2905  */
2906 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
2907 {
2908     LARGE_INTEGER timeout;
2909
2910     TRACE("%p %p\n", hFile, io_status );
2911
2912     SERVER_START_REQ( cancel_async )
2913     {
2914         req->handle      = wine_server_obj_handle( hFile );
2915         req->iosb        = 0;
2916         req->only_thread = TRUE;
2917         io_status->u.Status = wine_server_call( req );
2918     }
2919     SERVER_END_REQ;
2920     if (io_status->u.Status)
2921         return io_status->u.Status;
2922
2923     /* Let some APC be run, so that we can run the remaining APCs on hFile
2924      * either the cancelation of the pending one, but also the execution
2925      * of the queued APC, but not yet run. This is needed to ensure proper
2926      * clean-up of allocated data.
2927      */
2928     timeout.QuadPart = 0;
2929     NtDelayExecution( TRUE, &timeout );
2930     return io_status->u.Status;
2931 }
2932
2933 /******************************************************************************
2934  *  NtCreateMailslotFile        [NTDLL.@]
2935  *  ZwCreateMailslotFile        [NTDLL.@]
2936  *
2937  * PARAMS
2938  *  pHandle          [O] pointer to receive the handle created
2939  *  DesiredAccess    [I] access mode (read, write, etc)
2940  *  ObjectAttributes [I] fully qualified NT path of the mailslot
2941  *  IoStatusBlock    [O] receives completion status and other info
2942  *  CreateOptions    [I]
2943  *  MailslotQuota    [I]
2944  *  MaxMessageSize   [I]
2945  *  TimeOut          [I]
2946  *
2947  * RETURNS
2948  *  An NT status code
2949  */
2950 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
2951      POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
2952      ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
2953      PLARGE_INTEGER TimeOut)
2954 {
2955     LARGE_INTEGER timeout;
2956     NTSTATUS ret;
2957
2958     TRACE("%p %08x %p %p %08x %08x %08x %p\n",
2959               pHandle, DesiredAccess, attr, IoStatusBlock,
2960               CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
2961
2962     if (!pHandle) return STATUS_ACCESS_VIOLATION;
2963     if (!attr) return STATUS_INVALID_PARAMETER;
2964     if (!attr->ObjectName) return STATUS_OBJECT_PATH_SYNTAX_BAD;
2965
2966     /*
2967      *  For a NULL TimeOut pointer set the default timeout value
2968      */
2969     if  (!TimeOut)
2970         timeout.QuadPart = -1;
2971     else
2972         timeout.QuadPart = TimeOut->QuadPart;
2973
2974     SERVER_START_REQ( create_mailslot )
2975     {
2976         req->access = DesiredAccess;
2977         req->attributes = attr->Attributes;
2978         req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2979         req->max_msgsize = MaxMessageSize;
2980         req->read_timeout = timeout.QuadPart;
2981         wine_server_add_data( req, attr->ObjectName->Buffer,
2982                               attr->ObjectName->Length );
2983         ret = wine_server_call( req );
2984         if( ret == STATUS_SUCCESS )
2985             *pHandle = wine_server_ptr_handle( reply->handle );
2986     }
2987     SERVER_END_REQ;
2988  
2989     return ret;
2990 }