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