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