ntdll: Check for ARMv7 architecture dynamically when loading a PE.
[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 inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, LARGE_INTEGER *ctime,
1562                                    LARGE_INTEGER *atime, LARGE_INTEGER *creation )
1563 {
1564     RtlSecondsSince1970ToTime( st->st_mtime, mtime );
1565     RtlSecondsSince1970ToTime( st->st_ctime, ctime );
1566     RtlSecondsSince1970ToTime( st->st_atime, atime );
1567 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1568     mtime->QuadPart += st->st_mtim.tv_nsec / 100;
1569 #endif
1570 #ifdef HAVE_STRUCT_STAT_ST_CTIM
1571     ctime->QuadPart += st->st_ctim.tv_nsec / 100;
1572 #endif
1573 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1574     atime->QuadPart += st->st_atim.tv_nsec / 100;
1575 #endif
1576     *creation = *mtime;
1577 }
1578
1579 /* fill in the file information that depends on the stat info */
1580 NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLASS class )
1581 {
1582     switch (class)
1583     {
1584     case FileBasicInformation:
1585         {
1586             FILE_BASIC_INFORMATION *info = ptr;
1587
1588             get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
1589                             &info->LastAccessTime, &info->CreationTime );
1590             if (S_ISDIR(st->st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1591             else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1592             if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1593                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1594         }
1595         break;
1596     case FileStandardInformation:
1597         {
1598             FILE_STANDARD_INFORMATION *info = ptr;
1599
1600             if ((info->Directory = S_ISDIR(st->st_mode)))
1601             {
1602                 info->AllocationSize.QuadPart = 0;
1603                 info->EndOfFile.QuadPart      = 0;
1604                 info->NumberOfLinks           = 1;
1605             }
1606             else
1607             {
1608                 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
1609                 info->EndOfFile.QuadPart      = st->st_size;
1610                 info->NumberOfLinks           = st->st_nlink;
1611             }
1612         }
1613         break;
1614     case FileInternalInformation:
1615         {
1616             FILE_INTERNAL_INFORMATION *info = ptr;
1617             info->IndexNumber.QuadPart = st->st_ino;
1618         }
1619         break;
1620     case FileEndOfFileInformation:
1621         {
1622             FILE_END_OF_FILE_INFORMATION *info = ptr;
1623             info->EndOfFile.QuadPart = S_ISDIR(st->st_mode) ? 0 : st->st_size;
1624         }
1625         break;
1626     case FileAllInformation:
1627         {
1628             FILE_ALL_INFORMATION *info = ptr;
1629             fill_stat_info( st, &info->BasicInformation, FileBasicInformation );
1630             fill_stat_info( st, &info->StandardInformation, FileStandardInformation );
1631             fill_stat_info( st, &info->InternalInformation, FileInternalInformation );
1632         }
1633         break;
1634     /* all directory structures start with the FileDirectoryInformation layout */
1635     case FileBothDirectoryInformation:
1636     case FileFullDirectoryInformation:
1637     case FileDirectoryInformation:
1638         {
1639             FILE_DIRECTORY_INFORMATION *info = ptr;
1640
1641             get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
1642                             &info->LastAccessTime, &info->CreationTime );
1643             if (S_ISDIR(st->st_mode))
1644             {
1645                 info->AllocationSize.QuadPart = 0;
1646                 info->EndOfFile.QuadPart      = 0;
1647                 info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1648             }
1649             else
1650             {
1651                 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
1652                 info->EndOfFile.QuadPart      = st->st_size;
1653                 info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1654             }
1655             if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1656                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1657         }
1658         break;
1659     case FileIdFullDirectoryInformation:
1660         {
1661             FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr;
1662             info->FileId.QuadPart = st->st_ino;
1663             fill_stat_info( st, info, FileDirectoryInformation );
1664         }
1665         break;
1666     case FileIdBothDirectoryInformation:
1667         {
1668             FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr;
1669             info->FileId.QuadPart = st->st_ino;
1670             fill_stat_info( st, info, FileDirectoryInformation );
1671         }
1672         break;
1673
1674     default:
1675         return STATUS_INVALID_INFO_CLASS;
1676     }
1677     return STATUS_SUCCESS;
1678 }
1679
1680 NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name )
1681 {
1682     data_size_t size = 1024;
1683     NTSTATUS ret;
1684     char *name;
1685
1686     for (;;)
1687     {
1688         name = RtlAllocateHeap( GetProcessHeap(), 0, size + 1 );
1689         if (!name) return STATUS_NO_MEMORY;
1690         unix_name->MaximumLength = size + 1;
1691
1692         SERVER_START_REQ( get_handle_unix_name )
1693         {
1694             req->handle = wine_server_obj_handle( handle );
1695             wine_server_set_reply( req, name, size );
1696             ret = wine_server_call( req );
1697             size = reply->name_len;
1698         }
1699         SERVER_END_REQ;
1700
1701         if (!ret)
1702         {
1703             name[size] = 0;
1704             unix_name->Buffer = name;
1705             unix_name->Length = size;
1706             break;
1707         }
1708         RtlFreeHeap( GetProcessHeap(), 0, name );
1709         if (ret != STATUS_BUFFER_OVERFLOW) break;
1710     }
1711     return ret;
1712 }
1713
1714 static NTSTATUS fill_name_info( const ANSI_STRING *unix_name, FILE_NAME_INFORMATION *info, LONG *name_len )
1715 {
1716     UNICODE_STRING nt_name;
1717     NTSTATUS status;
1718
1719     if (!(status = wine_unix_to_nt_file_name( unix_name, &nt_name )))
1720     {
1721         const WCHAR *ptr = nt_name.Buffer;
1722         const WCHAR *end = ptr + (nt_name.Length / sizeof(WCHAR));
1723
1724         /* Skip the volume mount point. */
1725         while (ptr != end && *ptr == '\\') ++ptr;
1726         while (ptr != end && *ptr != '\\') ++ptr;
1727         while (ptr != end && *ptr == '\\') ++ptr;
1728         while (ptr != end && *ptr != '\\') ++ptr;
1729
1730         info->FileNameLength = (end - ptr) * sizeof(WCHAR);
1731         if (*name_len < info->FileNameLength) status = STATUS_BUFFER_OVERFLOW;
1732         else *name_len = info->FileNameLength;
1733
1734         memcpy( info->FileName, ptr, *name_len );
1735         RtlFreeUnicodeString( &nt_name );
1736     }
1737
1738     return status;
1739 }
1740
1741 /******************************************************************************
1742  *  NtQueryInformationFile              [NTDLL.@]
1743  *  ZwQueryInformationFile              [NTDLL.@]
1744  *
1745  * Get information about an open file handle.
1746  *
1747  * PARAMS
1748  *  hFile    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1749  *  io       [O] Receives information about the operation on return
1750  *  ptr      [O] Destination for file information
1751  *  len      [I] Size of FileInformation
1752  *  class    [I] Type of file information to get
1753  *
1754  * RETURNS
1755  *  Success: 0. IoStatusBlock and FileInformation are updated.
1756  *  Failure: An NTSTATUS error code describing the error.
1757  */
1758 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
1759                                         PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
1760 {
1761     static const size_t info_sizes[] =
1762     {
1763         0,
1764         sizeof(FILE_DIRECTORY_INFORMATION),            /* FileDirectoryInformation */
1765         sizeof(FILE_FULL_DIRECTORY_INFORMATION),       /* FileFullDirectoryInformation */
1766         sizeof(FILE_BOTH_DIRECTORY_INFORMATION),       /* FileBothDirectoryInformation */
1767         sizeof(FILE_BASIC_INFORMATION),                /* FileBasicInformation */
1768         sizeof(FILE_STANDARD_INFORMATION),             /* FileStandardInformation */
1769         sizeof(FILE_INTERNAL_INFORMATION),             /* FileInternalInformation */
1770         sizeof(FILE_EA_INFORMATION),                   /* FileEaInformation */
1771         sizeof(FILE_ACCESS_INFORMATION),               /* FileAccessInformation */
1772         sizeof(FILE_NAME_INFORMATION),                 /* FileNameInformation */
1773         sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
1774         0,                                             /* FileLinkInformation */
1775         sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR),  /* FileNamesInformation */
1776         sizeof(FILE_DISPOSITION_INFORMATION),          /* FileDispositionInformation */
1777         sizeof(FILE_POSITION_INFORMATION),             /* FilePositionInformation */
1778         sizeof(FILE_FULL_EA_INFORMATION),              /* FileFullEaInformation */
1779         sizeof(FILE_MODE_INFORMATION),                 /* FileModeInformation */
1780         sizeof(FILE_ALIGNMENT_INFORMATION),            /* FileAlignmentInformation */
1781         sizeof(FILE_ALL_INFORMATION),                  /* FileAllInformation */
1782         sizeof(FILE_ALLOCATION_INFORMATION),           /* FileAllocationInformation */
1783         sizeof(FILE_END_OF_FILE_INFORMATION),          /* FileEndOfFileInformation */
1784         0,                                             /* FileAlternateNameInformation */
1785         sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
1786         0,                                             /* FilePipeInformation */
1787         sizeof(FILE_PIPE_LOCAL_INFORMATION),           /* FilePipeLocalInformation */
1788         0,                                             /* FilePipeRemoteInformation */
1789         sizeof(FILE_MAILSLOT_QUERY_INFORMATION),       /* FileMailslotQueryInformation */
1790         0,                                             /* FileMailslotSetInformation */
1791         0,                                             /* FileCompressionInformation */
1792         0,                                             /* FileObjectIdInformation */
1793         0,                                             /* FileCompletionInformation */
1794         0,                                             /* FileMoveClusterInformation */
1795         0,                                             /* FileQuotaInformation */
1796         0,                                             /* FileReparsePointInformation */
1797         0,                                             /* FileNetworkOpenInformation */
1798         0,                                             /* FileAttributeTagInformation */
1799         0,                                             /* FileTrackingInformation */
1800         0,                                             /* FileIdBothDirectoryInformation */
1801         0,                                             /* FileIdFullDirectoryInformation */
1802         0,                                             /* FileValidDataLengthInformation */
1803         0,                                             /* FileShortNameInformation */
1804         0,
1805         0,
1806         0,
1807         0,                                             /* FileSfioReserveInformation */
1808         0,                                             /* FileSfioVolumeInformation */
1809         0,                                             /* FileHardLinkInformation */
1810         0,
1811         0,                                             /* FileNormalizedNameInformation */
1812         0,
1813         0,                                             /* FileIdGlobalTxDirectoryInformation */
1814         0,
1815         0,
1816         0,
1817         0                                              /* FileStandardLinkInformation */
1818     };
1819
1820     struct stat st;
1821     int fd, needs_close = FALSE;
1822
1823     TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
1824
1825     io->Information = 0;
1826
1827     if (class <= 0 || class >= FileMaximumInformation)
1828         return io->u.Status = STATUS_INVALID_INFO_CLASS;
1829     if (!info_sizes[class])
1830     {
1831         FIXME("Unsupported class (%d)\n", class);
1832         return io->u.Status = STATUS_NOT_IMPLEMENTED;
1833     }
1834     if (len < info_sizes[class])
1835         return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
1836
1837     if (class != FilePipeLocalInformation)
1838     {
1839         if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, NULL )))
1840             return io->u.Status;
1841     }
1842
1843     switch (class)
1844     {
1845     case FileBasicInformation:
1846         if (fstat( fd, &st ) == -1)
1847             io->u.Status = FILE_GetNtStatus();
1848         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1849             io->u.Status = STATUS_INVALID_INFO_CLASS;
1850         else
1851             fill_stat_info( &st, ptr, class );
1852         break;
1853     case FileStandardInformation:
1854         {
1855             FILE_STANDARD_INFORMATION *info = ptr;
1856
1857             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1858             else
1859             {
1860                 fill_stat_info( &st, info, class );
1861                 info->DeletePending = FALSE; /* FIXME */
1862             }
1863         }
1864         break;
1865     case FilePositionInformation:
1866         {
1867             FILE_POSITION_INFORMATION *info = ptr;
1868             off_t res = lseek( fd, 0, SEEK_CUR );
1869             if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
1870             else info->CurrentByteOffset.QuadPart = res;
1871         }
1872         break;
1873     case FileInternalInformation:
1874         if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1875         else fill_stat_info( &st, ptr, class );
1876         break;
1877     case FileEaInformation:
1878         {
1879             FILE_EA_INFORMATION *info = ptr;
1880             info->EaSize = 0;
1881         }
1882         break;
1883     case FileEndOfFileInformation:
1884         if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1885         else fill_stat_info( &st, ptr, class );
1886         break;
1887     case FileAllInformation:
1888         {
1889             FILE_ALL_INFORMATION *info = ptr;
1890             ANSI_STRING unix_name;
1891
1892             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1893             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1894                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1895             else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
1896             {
1897                 LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
1898
1899                 fill_stat_info( &st, info, FileAllInformation );
1900                 info->StandardInformation.DeletePending = FALSE; /* FIXME */
1901                 info->EaInformation.EaSize = 0;
1902                 info->AccessInformation.AccessFlags = 0;  /* FIXME */
1903                 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
1904                 info->ModeInformation.Mode = 0;  /* FIXME */
1905                 info->AlignmentInformation.AlignmentRequirement = 1;  /* FIXME */
1906
1907                 io->u.Status = fill_name_info( &unix_name, &info->NameInformation, &name_len );
1908                 RtlFreeAnsiString( &unix_name );
1909                 io->Information = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + name_len;
1910             }
1911         }
1912         break;
1913     case FileMailslotQueryInformation:
1914         {
1915             FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
1916
1917             SERVER_START_REQ( set_mailslot_info )
1918             {
1919                 req->handle = wine_server_obj_handle( hFile );
1920                 req->flags = 0;
1921                 io->u.Status = wine_server_call( req );
1922                 if( io->u.Status == STATUS_SUCCESS )
1923                 {
1924                     info->MaximumMessageSize = reply->max_msgsize;
1925                     info->MailslotQuota = 0;
1926                     info->NextMessageSize = 0;
1927                     info->MessagesAvailable = 0;
1928                     info->ReadTimeout.QuadPart = reply->read_timeout;
1929                 }
1930             }
1931             SERVER_END_REQ;
1932             if (!io->u.Status)
1933             {
1934                 char *tmpbuf;
1935                 ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000;
1936                 if (size > 0x10000) size = 0x10000;
1937                 if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
1938                 {
1939                     int fd, needs_close;
1940                     if (!server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
1941                     {
1942                         int res = recv( fd, tmpbuf, size, MSG_PEEK );
1943                         info->MessagesAvailable = (res > 0);
1944                         info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE;
1945                         if (needs_close) close( fd );
1946                     }
1947                     RtlFreeHeap( GetProcessHeap(), 0, tmpbuf );
1948                 }
1949             }
1950         }
1951         break;
1952     case FilePipeLocalInformation:
1953         {
1954             FILE_PIPE_LOCAL_INFORMATION* pli = ptr;
1955
1956             SERVER_START_REQ( get_named_pipe_info )
1957             {
1958                 req->handle = wine_server_obj_handle( hFile );
1959                 if (!(io->u.Status = wine_server_call( req )))
1960                 {
1961                     pli->NamedPipeType = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ? 
1962                         FILE_PIPE_TYPE_MESSAGE : FILE_PIPE_TYPE_BYTE;
1963                     switch (reply->sharing)
1964                     {
1965                         case FILE_SHARE_READ:
1966                             pli->NamedPipeConfiguration = FILE_PIPE_OUTBOUND;
1967                             break;
1968                         case FILE_SHARE_WRITE:
1969                             pli->NamedPipeConfiguration = FILE_PIPE_INBOUND;
1970                             break;
1971                         case FILE_SHARE_READ | FILE_SHARE_WRITE:
1972                             pli->NamedPipeConfiguration = FILE_PIPE_FULL_DUPLEX;
1973                             break;
1974                     }
1975                     pli->MaximumInstances = reply->maxinstances;
1976                     pli->CurrentInstances = reply->instances;
1977                     pli->InboundQuota = reply->insize;
1978                     pli->ReadDataAvailable = 0; /* FIXME */
1979                     pli->OutboundQuota = reply->outsize;
1980                     pli->WriteQuotaAvailable = 0; /* FIXME */
1981                     pli->NamedPipeState = 0; /* FIXME */
1982                     pli->NamedPipeEnd = (reply->flags & NAMED_PIPE_SERVER_END) ?
1983                         FILE_PIPE_SERVER_END : FILE_PIPE_CLIENT_END;
1984                 }
1985             }
1986             SERVER_END_REQ;
1987         }
1988         break;
1989     case FileNameInformation:
1990         {
1991             FILE_NAME_INFORMATION *info = ptr;
1992             ANSI_STRING unix_name;
1993
1994             if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
1995             {
1996                 LONG name_len = len - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
1997                 io->u.Status = fill_name_info( &unix_name, info, &name_len );
1998                 RtlFreeAnsiString( &unix_name );
1999                 io->Information = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + name_len;
2000             }
2001         }
2002         break;
2003     default:
2004         FIXME("Unsupported class (%d)\n", class);
2005         io->u.Status = STATUS_NOT_IMPLEMENTED;
2006         break;
2007     }
2008     if (needs_close) close( fd );
2009     if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
2010     return io->u.Status;
2011 }
2012
2013 /******************************************************************************
2014  *  NtSetInformationFile                [NTDLL.@]
2015  *  ZwSetInformationFile                [NTDLL.@]
2016  *
2017  * Set information about an open file handle.
2018  *
2019  * PARAMS
2020  *  handle  [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2021  *  io      [O] Receives information about the operation on return
2022  *  ptr     [I] Source for file information
2023  *  len     [I] Size of FileInformation
2024  *  class   [I] Type of file information to set
2025  *
2026  * RETURNS
2027  *  Success: 0. io is updated.
2028  *  Failure: An NTSTATUS error code describing the error.
2029  */
2030 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
2031                                      PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
2032 {
2033     int fd, needs_close;
2034
2035     TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", handle, io, ptr, len, class);
2036
2037     io->u.Status = STATUS_SUCCESS;
2038     switch (class)
2039     {
2040     case FileBasicInformation:
2041         if (len >= sizeof(FILE_BASIC_INFORMATION))
2042         {
2043             struct stat st;
2044             const FILE_BASIC_INFORMATION *info = ptr;
2045
2046             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2047                 return io->u.Status;
2048
2049             if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
2050             {
2051                 struct timeval tv[2];
2052
2053                 if (!info->LastAccessTime.QuadPart || !info->LastWriteTime.QuadPart)
2054                 {
2055
2056                     tv[0].tv_sec = tv[0].tv_usec = 0;
2057                     tv[1].tv_sec = tv[1].tv_usec = 0;
2058                     if (!fstat( fd, &st ))
2059                     {
2060                         tv[0].tv_sec = st.st_atime;
2061                         tv[1].tv_sec = st.st_mtime;
2062                     }
2063                 }
2064                 if (info->LastAccessTime.QuadPart)
2065                 {
2066                     ULONGLONG sec = info->LastAccessTime.QuadPart / 10000000;
2067                     UINT nsec = info->LastAccessTime.QuadPart % 10000000;
2068                     tv[0].tv_sec = sec - SECS_1601_TO_1970;
2069                     tv[0].tv_usec = nsec / 10;
2070                 }
2071                 if (info->LastWriteTime.QuadPart)
2072                 {
2073                     ULONGLONG sec = info->LastWriteTime.QuadPart / 10000000;
2074                     UINT nsec = info->LastWriteTime.QuadPart % 10000000;
2075                     tv[1].tv_sec = sec - SECS_1601_TO_1970;
2076                     tv[1].tv_usec = nsec / 10;
2077                 }
2078                 if (futimes( fd, tv ) == -1) io->u.Status = FILE_GetNtStatus();
2079             }
2080
2081             if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
2082             {
2083                 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2084                 else
2085                 {
2086                     if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
2087                     {
2088                         if (S_ISDIR( st.st_mode))
2089                             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
2090                         else
2091                             st.st_mode &= ~0222; /* clear write permission bits */
2092                     }
2093                     else
2094                     {
2095                         /* add write permission only where we already have read permission */
2096                         st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
2097                     }
2098                     if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
2099                 }
2100             }
2101
2102             if (needs_close) close( fd );
2103         }
2104         else io->u.Status = STATUS_INVALID_PARAMETER_3;
2105         break;
2106
2107     case FilePositionInformation:
2108         if (len >= sizeof(FILE_POSITION_INFORMATION))
2109         {
2110             const FILE_POSITION_INFORMATION *info = ptr;
2111
2112             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2113                 return io->u.Status;
2114
2115             if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
2116                 io->u.Status = FILE_GetNtStatus();
2117
2118             if (needs_close) close( fd );
2119         }
2120         else io->u.Status = STATUS_INVALID_PARAMETER_3;
2121         break;
2122
2123     case FileEndOfFileInformation:
2124         if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
2125         {
2126             struct stat st;
2127             const FILE_END_OF_FILE_INFORMATION *info = ptr;
2128
2129             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2130                 return io->u.Status;
2131
2132             /* first try normal truncate */
2133             if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2134
2135             /* now check for the need to extend the file */
2136             if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
2137             {
2138                 static const char zero;
2139
2140                 /* extend the file one byte beyond the requested size and then truncate it */
2141                 /* this should work around ftruncate implementations that can't extend files */
2142                 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
2143                     ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2144             }
2145             io->u.Status = FILE_GetNtStatus();
2146
2147             if (needs_close) close( fd );
2148         }
2149         else io->u.Status = STATUS_INVALID_PARAMETER_3;
2150         break;
2151
2152     case FileMailslotSetInformation:
2153         {
2154             FILE_MAILSLOT_SET_INFORMATION *info = ptr;
2155
2156             SERVER_START_REQ( set_mailslot_info )
2157             {
2158                 req->handle = wine_server_obj_handle( handle );
2159                 req->flags = MAILSLOT_SET_READ_TIMEOUT;
2160                 req->read_timeout = info->ReadTimeout.QuadPart;
2161                 io->u.Status = wine_server_call( req );
2162             }
2163             SERVER_END_REQ;
2164         }
2165         break;
2166
2167     case FileCompletionInformation:
2168         if (len >= sizeof(FILE_COMPLETION_INFORMATION))
2169         {
2170             FILE_COMPLETION_INFORMATION *info = ptr;
2171
2172             SERVER_START_REQ( set_completion_info )
2173             {
2174                 req->handle   = wine_server_obj_handle( handle );
2175                 req->chandle  = wine_server_obj_handle( info->CompletionPort );
2176                 req->ckey     = info->CompletionKey;
2177                 io->u.Status  = wine_server_call( req );
2178             }
2179             SERVER_END_REQ;
2180         } else
2181             io->u.Status = STATUS_INVALID_PARAMETER_3;
2182         break;
2183
2184     case FileAllInformation:
2185         io->u.Status = STATUS_INVALID_INFO_CLASS;
2186         break;
2187
2188     default:
2189         FIXME("Unsupported class (%d)\n", class);
2190         io->u.Status = STATUS_NOT_IMPLEMENTED;
2191         break;
2192     }
2193     io->Information = 0;
2194     return io->u.Status;
2195 }
2196
2197
2198 /******************************************************************************
2199  *              NtQueryFullAttributesFile   (NTDLL.@)
2200  */
2201 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
2202                                            FILE_NETWORK_OPEN_INFORMATION *info )
2203 {
2204     ANSI_STRING unix_name;
2205     NTSTATUS status;
2206
2207     if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2208     {
2209         struct stat st;
2210
2211         if (stat( unix_name.Buffer, &st ) == -1)
2212             status = FILE_GetNtStatus();
2213         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2214             status = STATUS_INVALID_INFO_CLASS;
2215         else
2216         {
2217             FILE_BASIC_INFORMATION basic;
2218             FILE_STANDARD_INFORMATION std;
2219
2220             fill_stat_info( &st, &basic, FileBasicInformation );
2221             fill_stat_info( &st, &std, FileStandardInformation );
2222
2223             info->CreationTime   = basic.CreationTime;
2224             info->LastAccessTime = basic.LastAccessTime;
2225             info->LastWriteTime  = basic.LastWriteTime;
2226             info->ChangeTime     = basic.ChangeTime;
2227             info->AllocationSize = std.AllocationSize;
2228             info->EndOfFile      = std.EndOfFile;
2229             info->FileAttributes = basic.FileAttributes;
2230             if (DIR_is_hidden_file( attr->ObjectName ))
2231                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2232         }
2233         RtlFreeAnsiString( &unix_name );
2234     }
2235     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2236     return status;
2237 }
2238
2239
2240 /******************************************************************************
2241  *              NtQueryAttributesFile   (NTDLL.@)
2242  *              ZwQueryAttributesFile   (NTDLL.@)
2243  */
2244 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
2245 {
2246     ANSI_STRING unix_name;
2247     NTSTATUS status;
2248
2249     if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2250     {
2251         struct stat st;
2252
2253         if (stat( unix_name.Buffer, &st ) == -1)
2254             status = FILE_GetNtStatus();
2255         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2256             status = STATUS_INVALID_INFO_CLASS;
2257         else
2258         {
2259             status = fill_stat_info( &st, info, FileBasicInformation );
2260             if (DIR_is_hidden_file( attr->ObjectName ))
2261                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2262         }
2263         RtlFreeAnsiString( &unix_name );
2264     }
2265     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2266     return status;
2267 }
2268
2269
2270 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2271 /* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */
2272 static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename,
2273                                             unsigned int flags )
2274 {
2275     if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename))
2276     {
2277         info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2278         /* Don't assume read-only, let the mount options set it below */
2279         info->Characteristics |= FILE_REMOVABLE_MEDIA;
2280     }
2281     else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) ||
2282              !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename))
2283     {
2284         info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2285         info->Characteristics |= FILE_REMOTE_DEVICE;
2286     }
2287     else if (!strcmp("procfs", fstypename))
2288         info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2289     else
2290         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2291
2292     if (flags & MNT_RDONLY)
2293         info->Characteristics |= FILE_READ_ONLY_DEVICE;
2294
2295     if (!(flags & MNT_LOCAL))
2296     {
2297         info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2298         info->Characteristics |= FILE_REMOTE_DEVICE;
2299     }
2300 }
2301 #endif
2302
2303 static inline int is_device_placeholder( int fd )
2304 {
2305     static const char wine_placeholder[] = "Wine device placeholder";
2306     char buffer[sizeof(wine_placeholder)-1];
2307
2308     if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
2309         return 0;
2310     return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
2311 }
2312
2313 /******************************************************************************
2314  *              get_device_info
2315  *
2316  * Implementation of the FileFsDeviceInformation query for NtQueryVolumeInformationFile.
2317  */
2318 static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
2319 {
2320     struct stat st;
2321
2322     info->Characteristics = 0;
2323     if (fstat( fd, &st ) < 0) return FILE_GetNtStatus();
2324     if (S_ISCHR( st.st_mode ))
2325     {
2326         info->DeviceType = FILE_DEVICE_UNKNOWN;
2327 #ifdef linux
2328         switch(major(st.st_rdev))
2329         {
2330         case MEM_MAJOR:
2331             info->DeviceType = FILE_DEVICE_NULL;
2332             break;
2333         case TTY_MAJOR:
2334             info->DeviceType = FILE_DEVICE_SERIAL_PORT;
2335             break;
2336         case LP_MAJOR:
2337             info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
2338             break;
2339         case SCSI_TAPE_MAJOR:
2340             info->DeviceType = FILE_DEVICE_TAPE;
2341             break;
2342         }
2343 #endif
2344     }
2345     else if (S_ISBLK( st.st_mode ))
2346     {
2347         info->DeviceType = FILE_DEVICE_DISK;
2348     }
2349     else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
2350     {
2351         info->DeviceType = FILE_DEVICE_NAMED_PIPE;
2352     }
2353     else if (is_device_placeholder( fd ))
2354     {
2355         info->DeviceType = FILE_DEVICE_DISK;
2356     }
2357     else  /* regular file or directory */
2358     {
2359 #if defined(linux) && defined(HAVE_FSTATFS)
2360         struct statfs stfs;
2361
2362         /* check for floppy disk */
2363         if (major(st.st_dev) == FLOPPY_MAJOR)
2364             info->Characteristics |= FILE_REMOVABLE_MEDIA;
2365
2366         if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
2367         switch (stfs.f_type)
2368         {
2369         case 0x9660:      /* iso9660 */
2370         case 0x9fa1:      /* supermount */
2371         case 0x15013346:  /* udf */
2372             info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2373             info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2374             break;
2375         case 0x6969:  /* nfs */
2376         case 0x517B:  /* smbfs */
2377         case 0x564c:  /* ncpfs */
2378             info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2379             info->Characteristics |= FILE_REMOTE_DEVICE;
2380             break;
2381         case 0x01021994:  /* tmpfs */
2382         case 0x28cd3d45:  /* cramfs */
2383         case 0x1373:      /* devfs */
2384         case 0x9fa0:      /* procfs */
2385             info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2386             break;
2387         default:
2388             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2389             break;
2390         }
2391 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2392         struct statfs stfs;
2393
2394         if (fstatfs( fd, &stfs ) < 0)
2395             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2396         else
2397             get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags );
2398 #elif defined(__NetBSD__)
2399         struct statvfs stfs;
2400
2401         if (fstatvfs( fd, &stfs) < 0)
2402             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2403         else
2404             get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag );
2405 #elif defined(sun)
2406         /* Use dkio to work out device types */
2407         {
2408 # include <sys/dkio.h>
2409 # include <sys/vtoc.h>
2410             struct dk_cinfo dkinf;
2411             int retval = ioctl(fd, DKIOCINFO, &dkinf);
2412             if(retval==-1){
2413                 WARN("Unable to get disk device type information - assuming a disk like device\n");
2414                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2415             }
2416             switch (dkinf.dki_ctype)
2417             {
2418             case DKC_CDROM:
2419                 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2420                 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2421                 break;
2422             case DKC_NCRFLOPPY:
2423             case DKC_SMSFLOPPY:
2424             case DKC_INTEL82072:
2425             case DKC_INTEL82077:
2426                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2427                 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2428                 break;
2429             case DKC_MD:
2430                 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2431                 break;
2432             default:
2433                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2434             }
2435         }
2436 #else
2437         static int warned;
2438         if (!warned++) FIXME( "device info not properly supported on this platform\n" );
2439         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2440 #endif
2441         info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
2442     }
2443     return STATUS_SUCCESS;
2444 }
2445
2446
2447 /******************************************************************************
2448  *  NtQueryVolumeInformationFile                [NTDLL.@]
2449  *  ZwQueryVolumeInformationFile                [NTDLL.@]
2450  *
2451  * Get volume information for an open file handle.
2452  *
2453  * PARAMS
2454  *  handle      [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2455  *  io          [O] Receives information about the operation on return
2456  *  buffer      [O] Destination for volume information
2457  *  length      [I] Size of FsInformation
2458  *  info_class  [I] Type of volume information to set
2459  *
2460  * RETURNS
2461  *  Success: 0. io and buffer are updated.
2462  *  Failure: An NTSTATUS error code describing the error.
2463  */
2464 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
2465                                               PVOID buffer, ULONG length,
2466                                               FS_INFORMATION_CLASS info_class )
2467 {
2468     int fd, needs_close;
2469     struct stat st;
2470     static int once;
2471
2472     if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
2473         return io->u.Status;
2474
2475     io->u.Status = STATUS_NOT_IMPLEMENTED;
2476     io->Information = 0;
2477
2478     switch( info_class )
2479     {
2480     case FileFsVolumeInformation:
2481         if (!once++) FIXME( "%p: volume info not supported\n", handle );
2482         break;
2483     case FileFsLabelInformation:
2484         FIXME( "%p: label info not supported\n", handle );
2485         break;
2486     case FileFsSizeInformation:
2487         if (length < sizeof(FILE_FS_SIZE_INFORMATION))
2488             io->u.Status = STATUS_BUFFER_TOO_SMALL;
2489         else
2490         {
2491             FILE_FS_SIZE_INFORMATION *info = buffer;
2492
2493             if (fstat( fd, &st ) < 0)
2494             {
2495                 io->u.Status = FILE_GetNtStatus();
2496                 break;
2497             }
2498             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2499             {
2500                 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
2501             }
2502             else
2503             {
2504                 ULONGLONG bsize;
2505                 /* Linux's fstatvfs is buggy */
2506 #if !defined(linux) || !defined(HAVE_FSTATFS)
2507                 struct statvfs stfs;
2508
2509                 if (fstatvfs( fd, &stfs ) < 0)
2510                 {
2511                     io->u.Status = FILE_GetNtStatus();
2512                     break;
2513                 }
2514                 bsize = stfs.f_frsize;
2515 #else
2516                 struct statfs stfs;
2517                 if (fstatfs( fd, &stfs ) < 0)
2518                 {
2519                     io->u.Status = FILE_GetNtStatus();
2520                     break;
2521                 }
2522                 bsize = stfs.f_bsize;
2523 #endif
2524                 if (bsize == 2048)  /* assume CD-ROM */
2525                 {
2526                     info->BytesPerSector = 2048;
2527                     info->SectorsPerAllocationUnit = 1;
2528                 }
2529                 else
2530                 {
2531                     info->BytesPerSector = 512;
2532                     info->SectorsPerAllocationUnit = 8;
2533                 }
2534                 info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2535                 info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2536                 io->Information = sizeof(*info);
2537                 io->u.Status = STATUS_SUCCESS;
2538             }
2539         }
2540         break;
2541     case FileFsDeviceInformation:
2542         if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
2543             io->u.Status = STATUS_BUFFER_TOO_SMALL;
2544         else
2545         {
2546             FILE_FS_DEVICE_INFORMATION *info = buffer;
2547
2548             if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS)
2549                 io->Information = sizeof(*info);
2550         }
2551         break;
2552     case FileFsAttributeInformation:
2553         FIXME( "%p: attribute info not supported\n", handle );
2554         break;
2555     case FileFsControlInformation:
2556         FIXME( "%p: control info not supported\n", handle );
2557         break;
2558     case FileFsFullSizeInformation:
2559         FIXME( "%p: full size info not supported\n", handle );
2560         break;
2561     case FileFsObjectIdInformation:
2562         FIXME( "%p: object id info not supported\n", handle );
2563         break;
2564     case FileFsMaximumInformation:
2565         FIXME( "%p: maximum info not supported\n", handle );
2566         break;
2567     default:
2568         io->u.Status = STATUS_INVALID_PARAMETER;
2569         break;
2570     }
2571     if (needs_close) close( fd );
2572     return io->u.Status;
2573 }
2574
2575
2576 /******************************************************************
2577  *              NtQueryEaFile  (NTDLL.@)
2578  *
2579  * Read extended attributes from NTFS files.
2580  *
2581  * PARAMS
2582  *  hFile         [I] File handle, must be opened with FILE_READ_EA access
2583  *  iosb          [O] Receives information about the operation on return
2584  *  buffer        [O] Output buffer
2585  *  length        [I] Length of output buffer
2586  *  single_entry  [I] Only read and return one entry
2587  *  ea_list       [I] Optional list with names of EAs to return
2588  *  ea_list_len   [I] Length of ea_list in bytes
2589  *  ea_index      [I] Optional pointer to 1-based index of attribute to return
2590  *  restart       [I] restart EA scan
2591  *
2592  * RETURNS
2593  *  Success: 0. Atrributes read into buffer
2594  *  Failure: An NTSTATUS error code describing the error.
2595  */
2596 NTSTATUS WINAPI NtQueryEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length,
2597                                BOOLEAN single_entry, PVOID ea_list, ULONG ea_list_len,
2598                                PULONG ea_index, BOOLEAN restart )
2599 {
2600     FIXME("(%p,%p,%p,%d,%d,%p,%d,%p,%d) stub\n",
2601             hFile, iosb, buffer, length, single_entry, ea_list,
2602             ea_list_len, ea_index, restart);
2603     return STATUS_ACCESS_DENIED;
2604 }
2605
2606
2607 /******************************************************************
2608  *              NtSetEaFile  (NTDLL.@)
2609  *
2610  * Update extended attributes for NTFS files.
2611  *
2612  * PARAMS
2613  *  hFile         [I] File handle, must be opened with FILE_READ_EA access
2614  *  iosb          [O] Receives information about the operation on return
2615  *  buffer        [I] Buffer with EA information
2616  *  length        [I] Length of buffer
2617  *
2618  * RETURNS
2619  *  Success: 0. Attributes are updated
2620  *  Failure: An NTSTATUS error code describing the error.
2621  */
2622 NTSTATUS WINAPI NtSetEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length )
2623 {
2624     FIXME("(%p,%p,%p,%d) stub\n", hFile, iosb, buffer, length);
2625     return STATUS_ACCESS_DENIED;
2626 }
2627
2628
2629 /******************************************************************
2630  *              NtFlushBuffersFile  (NTDLL.@)
2631  *
2632  * Flush any buffered data on an open file handle.
2633  *
2634  * PARAMS
2635  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2636  *  IoStatusBlock      [O] Receives information about the operation on return
2637  *
2638  * RETURNS
2639  *  Success: 0. IoStatusBlock is updated.
2640  *  Failure: An NTSTATUS error code describing the error.
2641  */
2642 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
2643 {
2644     NTSTATUS ret;
2645     HANDLE hEvent = NULL;
2646
2647     SERVER_START_REQ( flush_file )
2648     {
2649         req->handle = wine_server_obj_handle( hFile );
2650         ret = wine_server_call( req );
2651         hEvent = wine_server_ptr_handle( reply->event );
2652     }
2653     SERVER_END_REQ;
2654     if (!ret && hEvent)
2655     {
2656         ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
2657         NtClose( hEvent );
2658     }
2659     return ret;
2660 }
2661
2662 /******************************************************************
2663  *              NtLockFile       (NTDLL.@)
2664  *
2665  *
2666  */
2667 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
2668                             PIO_APC_ROUTINE apc, void* apc_user,
2669                             PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
2670                             PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
2671                             BOOLEAN exclusive )
2672 {
2673     NTSTATUS    ret;
2674     HANDLE      handle;
2675     BOOLEAN     async;
2676     static BOOLEAN     warn = TRUE;
2677
2678     if (apc || io_status || key)
2679     {
2680         FIXME("Unimplemented yet parameter\n");
2681         return STATUS_NOT_IMPLEMENTED;
2682     }
2683
2684     if (apc_user && warn)
2685     {
2686         FIXME("I/O completion on lock not implemented yet\n");
2687         warn = FALSE;
2688     }
2689
2690     for (;;)
2691     {
2692         SERVER_START_REQ( lock_file )
2693         {
2694             req->handle      = wine_server_obj_handle( hFile );
2695             req->offset      = offset->QuadPart;
2696             req->count       = count->QuadPart;
2697             req->shared      = !exclusive;
2698             req->wait        = !dont_wait;
2699             ret = wine_server_call( req );
2700             handle = wine_server_ptr_handle( reply->handle );
2701             async  = reply->overlapped;
2702         }
2703         SERVER_END_REQ;
2704         if (ret != STATUS_PENDING)
2705         {
2706             if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
2707             return ret;
2708         }
2709
2710         if (async)
2711         {
2712             FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
2713             if (handle) NtClose( handle );
2714             return STATUS_PENDING;
2715         }
2716         if (handle)
2717         {
2718             NtWaitForSingleObject( handle, FALSE, NULL );
2719             NtClose( handle );
2720         }
2721         else
2722         {
2723             LARGE_INTEGER time;
2724     
2725             /* Unix lock conflict, sleep a bit and retry */
2726             time.QuadPart = 100 * (ULONGLONG)10000;
2727             time.QuadPart = -time.QuadPart;
2728             NtDelayExecution( FALSE, &time );
2729         }
2730     }
2731 }
2732
2733
2734 /******************************************************************
2735  *              NtUnlockFile    (NTDLL.@)
2736  *
2737  *
2738  */
2739 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
2740                               PLARGE_INTEGER offset, PLARGE_INTEGER count,
2741                               PULONG key )
2742 {
2743     NTSTATUS status;
2744
2745     TRACE( "%p %x%08x %x%08x\n",
2746            hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
2747
2748     if (io_status || key)
2749     {
2750         FIXME("Unimplemented yet parameter\n");
2751         return STATUS_NOT_IMPLEMENTED;
2752     }
2753
2754     SERVER_START_REQ( unlock_file )
2755     {
2756         req->handle = wine_server_obj_handle( hFile );
2757         req->offset = offset->QuadPart;
2758         req->count  = count->QuadPart;
2759         status = wine_server_call( req );
2760     }
2761     SERVER_END_REQ;
2762     return status;
2763 }
2764
2765 /******************************************************************
2766  *              NtCreateNamedPipeFile    (NTDLL.@)
2767  *
2768  *
2769  */
2770 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
2771                                        POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
2772                                        ULONG sharing, ULONG dispo, ULONG options,
2773                                        ULONG pipe_type, ULONG read_mode, 
2774                                        ULONG completion_mode, ULONG max_inst,
2775                                        ULONG inbound_quota, ULONG outbound_quota,
2776                                        PLARGE_INTEGER timeout)
2777 {
2778     NTSTATUS    status;
2779
2780     TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n",
2781           handle, access, debugstr_w(attr->ObjectName->Buffer), iosb, sharing, dispo,
2782           options, pipe_type, read_mode, completion_mode, max_inst, inbound_quota,
2783           outbound_quota, timeout);
2784
2785     /* assume we only get relative timeout */
2786     if (timeout->QuadPart > 0)
2787         FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
2788
2789     SERVER_START_REQ( create_named_pipe )
2790     {
2791         req->access  = access;
2792         req->attributes = attr->Attributes;
2793         req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2794         req->options = options;
2795         req->sharing = sharing;
2796         req->flags = 
2797             (pipe_type ? NAMED_PIPE_MESSAGE_STREAM_WRITE   : 0) |
2798             (read_mode ? NAMED_PIPE_MESSAGE_STREAM_READ    : 0) |
2799             (completion_mode ? NAMED_PIPE_NONBLOCKING_MODE : 0);
2800         req->maxinstances = max_inst;
2801         req->outsize = outbound_quota;
2802         req->insize  = inbound_quota;
2803         req->timeout = timeout->QuadPart;
2804         wine_server_add_data( req, attr->ObjectName->Buffer,
2805                               attr->ObjectName->Length );
2806         status = wine_server_call( req );
2807         if (!status) *handle = wine_server_ptr_handle( reply->handle );
2808     }
2809     SERVER_END_REQ;
2810     return status;
2811 }
2812
2813 /******************************************************************
2814  *              NtDeleteFile    (NTDLL.@)
2815  *
2816  *
2817  */
2818 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
2819 {
2820     NTSTATUS status;
2821     HANDLE hFile;
2822     IO_STATUS_BLOCK io;
2823
2824     TRACE("%p\n", ObjectAttributes);
2825     status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE | DELETE,
2826                            ObjectAttributes, &io, NULL, 0,
2827                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
2828                            FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
2829     if (status == STATUS_SUCCESS) status = NtClose(hFile);
2830     return status;
2831 }
2832
2833 /******************************************************************
2834  *              NtCancelIoFileEx    (NTDLL.@)
2835  *
2836  *
2837  */
2838 NTSTATUS WINAPI NtCancelIoFileEx( HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status )
2839 {
2840     LARGE_INTEGER timeout;
2841
2842     TRACE("%p %p %p\n", hFile, iosb, io_status );
2843
2844     SERVER_START_REQ( cancel_async )
2845     {
2846         req->handle      = wine_server_obj_handle( hFile );
2847         req->iosb        = wine_server_client_ptr( iosb );
2848         req->only_thread = FALSE;
2849         io_status->u.Status = wine_server_call( req );
2850     }
2851     SERVER_END_REQ;
2852     if (io_status->u.Status)
2853         return io_status->u.Status;
2854
2855     /* Let some APC be run, so that we can run the remaining APCs on hFile
2856      * either the cancelation of the pending one, but also the execution
2857      * of the queued APC, but not yet run. This is needed to ensure proper
2858      * clean-up of allocated data.
2859      */
2860     timeout.u.LowPart = timeout.u.HighPart = 0;
2861     NtDelayExecution( TRUE, &timeout );
2862     return io_status->u.Status;
2863 }
2864
2865 /******************************************************************
2866  *              NtCancelIoFile    (NTDLL.@)
2867  *
2868  *
2869  */
2870 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
2871 {
2872     LARGE_INTEGER timeout;
2873
2874     TRACE("%p %p\n", hFile, io_status );
2875
2876     SERVER_START_REQ( cancel_async )
2877     {
2878         req->handle      = wine_server_obj_handle( hFile );
2879         req->iosb        = 0;
2880         req->only_thread = TRUE;
2881         io_status->u.Status = wine_server_call( req );
2882     }
2883     SERVER_END_REQ;
2884     if (io_status->u.Status)
2885         return io_status->u.Status;
2886
2887     /* Let some APC be run, so that we can run the remaining APCs on hFile
2888      * either the cancelation of the pending one, but also the execution
2889      * of the queued APC, but not yet run. This is needed to ensure proper
2890      * clean-up of allocated data.
2891      */
2892     timeout.u.LowPart = timeout.u.HighPart = 0;
2893     NtDelayExecution( TRUE, &timeout );
2894     return io_status->u.Status;
2895 }
2896
2897 /******************************************************************************
2898  *  NtCreateMailslotFile        [NTDLL.@]
2899  *  ZwCreateMailslotFile        [NTDLL.@]
2900  *
2901  * PARAMS
2902  *  pHandle          [O] pointer to receive the handle created
2903  *  DesiredAccess    [I] access mode (read, write, etc)
2904  *  ObjectAttributes [I] fully qualified NT path of the mailslot
2905  *  IoStatusBlock    [O] receives completion status and other info
2906  *  CreateOptions    [I]
2907  *  MailslotQuota    [I]
2908  *  MaxMessageSize   [I]
2909  *  TimeOut          [I]
2910  *
2911  * RETURNS
2912  *  An NT status code
2913  */
2914 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
2915      POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
2916      ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
2917      PLARGE_INTEGER TimeOut)
2918 {
2919     LARGE_INTEGER timeout;
2920     NTSTATUS ret;
2921
2922     TRACE("%p %08x %p %p %08x %08x %08x %p\n",
2923               pHandle, DesiredAccess, attr, IoStatusBlock,
2924               CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
2925
2926     if (!pHandle) return STATUS_ACCESS_VIOLATION;
2927     if (!attr) return STATUS_INVALID_PARAMETER;
2928     if (!attr->ObjectName) return STATUS_OBJECT_PATH_SYNTAX_BAD;
2929
2930     /*
2931      *  For a NULL TimeOut pointer set the default timeout value
2932      */
2933     if  (!TimeOut)
2934         timeout.QuadPart = -1;
2935     else
2936         timeout.QuadPart = TimeOut->QuadPart;
2937
2938     SERVER_START_REQ( create_mailslot )
2939     {
2940         req->access = DesiredAccess;
2941         req->attributes = attr->Attributes;
2942         req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2943         req->max_msgsize = MaxMessageSize;
2944         req->read_timeout = timeout.QuadPart;
2945         wine_server_add_data( req, attr->ObjectName->Buffer,
2946                               attr->ObjectName->Length );
2947         ret = wine_server_call( req );
2948         if( ret == STATUS_SUCCESS )
2949             *pHandle = wine_server_ptr_handle( reply->handle );
2950     }
2951     SERVER_END_REQ;
2952  
2953     return ret;
2954 }