Fix segmentation fault caused by incorrect referencing of client audio
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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_UTIME_H
46 # include <utime.h>
47 #endif
48 #ifdef STATFS_DEFINED_BY_SYS_VFS
49 # include <sys/vfs.h>
50 #else
51 # ifdef STATFS_DEFINED_BY_SYS_MOUNT
52 #  include <sys/mount.h>
53 # else
54 #  ifdef STATFS_DEFINED_BY_SYS_STATFS
55 #   include <sys/statfs.h>
56 #  endif
57 # endif
58 #endif
59
60 #define NONAMELESSUNION
61 #define NONAMELESSSTRUCT
62 #include "wine/unicode.h"
63 #include "wine/debug.h"
64 #include "wine/server.h"
65 #include "ntdll_misc.h"
66
67 #include "winternl.h"
68 #include "winioctl.h"
69
70 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
71
72 mode_t FILE_umask = 0;
73
74 #define SECSPERDAY         86400
75 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
76
77 /**************************************************************************
78  *                 NtOpenFile                           [NTDLL.@]
79  *                 ZwOpenFile                           [NTDLL.@]
80  *
81  * Open a file.
82  *
83  * PARAMS
84  *  handle    [O] Variable that receives the file handle on return
85  *  access    [I] Access desired by the caller to the file
86  *  attr      [I] Structure describing the file to be opened
87  *  io        [O] Receives details about the result of the operation
88  *  sharing   [I] Type of shared access the caller requires
89  *  options   [I] Options for the file open
90  *
91  * RETURNS
92  *  Success: 0. FileHandle and IoStatusBlock are updated.
93  *  Failure: An NTSTATUS error code describing the error.
94  */
95 NTSTATUS WINAPI NtOpenFile( PHANDLE handle, ACCESS_MASK access,
96                             POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK io,
97                             ULONG sharing, ULONG options )
98 {
99     return NtCreateFile( handle, access, attr, io, NULL, 0,
100                          sharing, FILE_OPEN, options, NULL, 0 );
101 }
102
103 /**************************************************************************
104  *              NtCreateFile                            [NTDLL.@]
105  *              ZwCreateFile                            [NTDLL.@]
106  *
107  * Either create a new file or directory, or open an existing file, device,
108  * directory or volume.
109  *
110  * PARAMS
111  *      handle       [O] Points to a variable which receives the file handle on return
112  *      access       [I] Desired access to the file
113  *      attr         [I] Structure describing the file
114  *      io           [O] Receives information about the operation on return
115  *      alloc_size   [I] Initial size of the file in bytes
116  *      attributes   [I] Attributes to create the file with
117  *      sharing      [I] Type of shared access the caller would like to the file
118  *      disposition  [I] Specifies what to do, depending on whether the file already exists
119  *      options      [I] Options for creating a new file
120  *      ea_buffer    [I] Pointer to an extended attributes buffer
121  *      ea_length    [I] Length of ea_buffer
122  *
123  * RETURNS
124  *  Success: 0. handle and io are updated.
125  *  Failure: An NTSTATUS error code describing the error.
126  */
127 NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
128                               PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
129                               ULONG attributes, ULONG sharing, ULONG disposition,
130                               ULONG options, PVOID ea_buffer, ULONG ea_length )
131 {
132     static const WCHAR pipeW[] = {'\\','?','?','\\','p','i','p','e','\\'};
133     static const WCHAR mailslotW[] = {'\\','?','?','\\','M','A','I','L','S','L','O','T','\\'};
134     ANSI_STRING unix_name;
135     int created = FALSE;
136
137     TRACE("handle=%p access=%08lx name=%s objattr=%08lx root=%p sec=%p io=%p alloc_size=%p\n"
138           "attr=%08lx sharing=%08lx disp=%ld options=%08lx ea=%p.0x%08lx\n",
139           handle, access, debugstr_us(attr->ObjectName), attr->Attributes,
140           attr->RootDirectory, attr->SecurityDescriptor, io, alloc_size,
141           attributes, sharing, disposition, options, ea_buffer, ea_length );
142
143     if (!attr || !attr->ObjectName) return STATUS_INVALID_PARAMETER;
144
145     if (attr->RootDirectory)
146     {
147         FIXME( "RootDirectory %p not supported\n", attr->RootDirectory );
148         return STATUS_OBJECT_NAME_NOT_FOUND;
149     }
150     if (alloc_size) FIXME( "alloc_size not supported\n" );
151
152     /* check for named pipe */
153
154     if (attr->ObjectName->Length > sizeof(pipeW) &&
155         !memicmpW( attr->ObjectName->Buffer, pipeW, sizeof(pipeW)/sizeof(WCHAR) ))
156     {
157         SERVER_START_REQ( open_named_pipe )
158         {
159             req->access = access;
160             req->inherit = (attr->Attributes & OBJ_INHERIT) != 0;
161             wine_server_add_data( req, attr->ObjectName->Buffer + 4,
162                                   attr->ObjectName->Length - 4*sizeof(WCHAR) );
163             io->u.Status = wine_server_call( req );
164             *handle = reply->handle;
165         }
166         SERVER_END_REQ;
167         return io->u.Status;
168     }
169
170     /* check for mailslot */
171
172     if (attr->ObjectName->Length > sizeof(mailslotW) &&
173         !memicmpW( attr->ObjectName->Buffer, mailslotW, sizeof(mailslotW)/sizeof(WCHAR) ))
174     {
175         SERVER_START_REQ( open_mailslot )
176         {
177             req->access = access & GENERIC_WRITE;
178             req->sharing = sharing;
179             req->inherit = (attr->Attributes & OBJ_INHERIT) != 0;
180             wine_server_add_data( req, attr->ObjectName->Buffer + 4,
181                                   attr->ObjectName->Length - 4*sizeof(WCHAR) );
182             io->u.Status = wine_server_call( req );
183             *handle = reply->handle;
184         }
185         SERVER_END_REQ;
186         return io->u.Status;
187     }
188
189     io->u.Status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, disposition,
190                                               !(attr->Attributes & OBJ_CASE_INSENSITIVE) );
191
192     if (io->u.Status == STATUS_NO_SUCH_FILE &&
193         disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
194     {
195         created = TRUE;
196         io->u.Status = STATUS_SUCCESS;
197     }
198
199     if (io->u.Status == STATUS_SUCCESS)
200     {
201         SERVER_START_REQ( create_file )
202         {
203             req->access     = access;
204             req->inherit    = (attr->Attributes & OBJ_INHERIT) != 0;
205             req->sharing    = sharing;
206             req->create     = disposition;
207             req->options    = options;
208             req->attrs      = attributes;
209             wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
210             io->u.Status = wine_server_call( req );
211             *handle = reply->handle;
212         }
213         SERVER_END_REQ;
214         RtlFreeAnsiString( &unix_name );
215     }
216     else WARN("%s not found (%lx)\n", debugstr_us(attr->ObjectName), io->u.Status );
217
218     if (io->u.Status == STATUS_SUCCESS)
219     {
220         if (created) io->Information = FILE_CREATED;
221         else switch(disposition)
222         {
223         case FILE_SUPERSEDE:
224             io->Information = FILE_SUPERSEDED;
225             break;
226         case FILE_CREATE:
227             io->Information = FILE_CREATED;
228             break;
229         case FILE_OPEN:
230         case FILE_OPEN_IF:
231             io->Information = FILE_OPENED;
232             break;
233         case FILE_OVERWRITE:
234         case FILE_OVERWRITE_IF:
235             io->Information = FILE_OVERWRITTEN;
236             break;
237         }
238     }
239
240     return io->u.Status;
241 }
242
243 /***********************************************************************
244  *                  Asynchronous file I/O                              *
245  */
246 static void WINAPI FILE_AsyncReadService(void*, PIO_STATUS_BLOCK, ULONG);
247 static void WINAPI FILE_AsyncWriteService(void*, PIO_STATUS_BLOCK, ULONG);
248
249 typedef struct async_fileio
250 {
251     HANDLE              handle;
252     PIO_APC_ROUTINE     apc;
253     void*               apc_user;
254     char*               buffer;
255     unsigned int        count;
256     off_t               offset;
257     int                 queue_apc_on_error;
258     BOOL                avail_mode;
259     int                 fd;
260     HANDLE              event;
261 } async_fileio;
262
263 static void fileio_terminate(async_fileio *fileio, IO_STATUS_BLOCK* iosb)
264 {
265     TRACE("data: %p\n", fileio);
266
267     wine_server_release_fd( fileio->handle, fileio->fd );
268     if ( fileio->event != INVALID_HANDLE_VALUE )
269         NtSetEvent( fileio->event, NULL );
270
271     if (fileio->apc && 
272         (iosb->u.Status == STATUS_SUCCESS || fileio->queue_apc_on_error))
273         fileio->apc( fileio->apc_user, iosb, iosb->Information );
274
275     RtlFreeHeap( GetProcessHeap(), 0, fileio );
276 }
277
278
279 static ULONG fileio_queue_async(async_fileio* fileio, IO_STATUS_BLOCK* iosb, 
280                                 BOOL do_read)
281 {
282     PIO_APC_ROUTINE     apc = do_read ? FILE_AsyncReadService : FILE_AsyncWriteService;
283     NTSTATUS            status;
284
285     SERVER_START_REQ( register_async )
286     {
287         req->handle = fileio->handle;
288         req->io_apc = apc;
289         req->io_sb = iosb;
290         req->io_user = fileio;
291         req->type = do_read ? ASYNC_TYPE_READ : ASYNC_TYPE_WRITE;
292         req->count = (fileio->count < iosb->Information) ? 
293             0 : fileio->count - iosb->Information;
294         status = wine_server_call( req );
295     }
296     SERVER_END_REQ;
297
298     if ( status ) iosb->u.Status = status;
299     if ( iosb->u.Status != STATUS_PENDING )
300     {
301         (apc)( fileio, iosb, iosb->u.Status );
302         return iosb->u.Status;
303     }
304     NtCurrentTeb()->num_async_io++;
305     return STATUS_SUCCESS;
306 }
307
308 /***********************************************************************
309  *           FILE_GetNtStatus(void)
310  *
311  * Retrieve the Nt Status code from errno.
312  * Try to be consistent with FILE_SetDosError().
313  */
314 NTSTATUS FILE_GetNtStatus(void)
315 {
316     int err = errno;
317
318     TRACE( "errno = %d\n", errno );
319     switch (err)
320     {
321     case EAGAIN:    return STATUS_SHARING_VIOLATION;
322     case EBADF:     return STATUS_INVALID_HANDLE;
323     case ENOSPC:    return STATUS_DISK_FULL;
324     case EPERM:
325     case EROFS:
326     case EACCES:    return STATUS_ACCESS_DENIED;
327     case ENOTDIR:   return STATUS_OBJECT_PATH_NOT_FOUND;
328     case ENOENT:    return STATUS_OBJECT_NAME_NOT_FOUND;
329     case EISDIR:    return STATUS_FILE_IS_A_DIRECTORY;
330     case EMFILE:
331     case ENFILE:    return STATUS_TOO_MANY_OPENED_FILES;
332     case EINVAL:    return STATUS_INVALID_PARAMETER;
333     case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
334     case EPIPE:     return STATUS_PIPE_BROKEN;
335     case EIO:       return STATUS_DEVICE_NOT_READY;
336 #ifdef ENOMEDIUM
337     case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE;
338 #endif
339     case ENOTTY:
340     case EOPNOTSUPP:return STATUS_NOT_SUPPORTED;
341     case ECONNRESET:return STATUS_PIPE_DISCONNECTED;
342     case ENOEXEC:   /* ?? */
343     case ESPIPE:    /* ?? */
344     case EEXIST:    /* ?? */
345     default:
346         FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
347         return STATUS_UNSUCCESSFUL;
348     }
349 }
350
351 /***********************************************************************
352  *             FILE_AsyncReadService      (INTERNAL)
353  *
354  *  This function is called while the client is waiting on the
355  *  server, so we can't make any server calls here.
356  */
357 static void WINAPI FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, ULONG status)
358 {
359     async_fileio *fileio = (async_fileio*)user;
360     int result;
361     int already = iosb->Information;
362
363     TRACE("%p %p %lu\n", iosb, fileio->buffer, status);
364
365     switch (status)
366     {
367     case STATUS_ALERTED: /* got some new data */
368         if (iosb->u.Status != STATUS_PENDING) FIXME("unexpected status %08lx\n", iosb->u.Status);
369         /* check to see if the data is ready (non-blocking) */
370         if ( fileio->avail_mode )
371             result = read(fileio->fd, &fileio->buffer[already], 
372                           fileio->count - already);
373         else
374         {
375             result = pread(fileio->fd, &fileio->buffer[already],
376                            fileio->count - already,
377                            fileio->offset + already);
378             if ((result < 0) && (errno == ESPIPE))
379                 result = read(fileio->fd, &fileio->buffer[already], 
380                               fileio->count - already);
381         }
382
383         if (result < 0)
384         {
385             if (errno == EAGAIN || errno == EINTR)
386             {
387                 TRACE("Deferred read %d\n", errno);
388                 iosb->u.Status = STATUS_PENDING;
389             }
390             else /* check to see if the transfer is complete */
391                 iosb->u.Status = FILE_GetNtStatus();
392         }
393         else if (result == 0)
394         {
395             iosb->u.Status = iosb->Information ? STATUS_SUCCESS : STATUS_END_OF_FILE;
396         }
397         else
398         {
399             iosb->Information += result;
400             if (iosb->Information >= fileio->count || fileio->avail_mode)
401                 iosb->u.Status = STATUS_SUCCESS;
402             else
403             {
404                 /* if we only have to read the available data, and none is available,
405                  * simply cancel the request. If data was available, it has been read
406                  * while in by previous call (NtDelayExecution)
407                  */
408                 iosb->u.Status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING;
409             }
410
411             TRACE("read %d more bytes %ld/%d so far (%s)\n",
412                   result, iosb->Information, fileio->count, 
413                   (iosb->u.Status == STATUS_SUCCESS) ? "success" : "pending");
414         }
415         /* queue another async operation ? */
416         if (iosb->u.Status == STATUS_PENDING)
417             fileio_queue_async(fileio, iosb, TRUE);
418         else
419             fileio_terminate(fileio, iosb);
420         break;
421     default:
422         iosb->u.Status = status;
423         fileio_terminate(fileio, iosb);
424         break;
425     }
426 }
427
428
429 /******************************************************************************
430  *  NtReadFile                                  [NTDLL.@]
431  *  ZwReadFile                                  [NTDLL.@]
432  *
433  * Read from an open file handle.
434  *
435  * PARAMS
436  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
437  *  Event         [I] Event to signal upon completion (or NULL)
438  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
439  *  ApcContext    [I] Context for ApcRoutine (or NULL)
440  *  IoStatusBlock [O] Receives information about the operation on return
441  *  Buffer        [O] Destination for the data read
442  *  Length        [I] Size of Buffer
443  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
444  *  Key           [O] Function unknown (may be NULL)
445  *
446  * RETURNS
447  *  Success: 0. IoStatusBlock is updated, and the Information member contains
448  *           The number of bytes read.
449  *  Failure: An NTSTATUS error code describing the error.
450  */
451 NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
452                            PIO_APC_ROUTINE apc, void* apc_user,
453                            PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
454                            PLARGE_INTEGER offset, PULONG key)
455 {
456     int unix_handle, flags;
457
458     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n",
459           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
460
461     if (!io_status) return STATUS_ACCESS_VIOLATION;
462
463     io_status->Information = 0;
464     io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_READ, &unix_handle, &flags );
465     if (io_status->u.Status) return io_status->u.Status;
466
467     if (flags & FD_FLAG_RECV_SHUTDOWN)
468     {
469         wine_server_release_fd( hFile, unix_handle );
470         return STATUS_PIPE_DISCONNECTED;
471     }
472
473     if (flags & FD_FLAG_TIMEOUT)
474     {
475         if (hEvent)
476         {
477             /* this shouldn't happen, but check it */
478             FIXME("NIY-hEvent\n");
479             wine_server_release_fd( hFile, unix_handle );
480             return STATUS_NOT_IMPLEMENTED;
481         }
482         io_status->u.Status = NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, NULL, 0, 0);
483         if (io_status->u.Status)
484         {
485             wine_server_release_fd( hFile, unix_handle );
486             return io_status->u.Status;
487         }
488     }
489
490     if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
491     {
492         async_fileio*   fileio;
493         NTSTATUS ret;
494
495         if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
496         {
497             wine_server_release_fd( hFile, unix_handle );
498             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
499             return STATUS_NO_MEMORY;
500         }
501         fileio->handle = hFile;
502         fileio->count = length;
503         if ( offset == NULL ) 
504             fileio->offset = 0;
505         else
506         {
507             fileio->offset = offset->QuadPart;
508             if (offset->u.HighPart && fileio->offset == offset->u.LowPart)
509                 FIXME("High part of offset is lost\n");
510         } 
511         fileio->apc = apc;
512         fileio->apc_user = apc_user;
513         fileio->buffer = buffer;
514         fileio->queue_apc_on_error = 0;
515         fileio->avail_mode = (flags & FD_FLAG_AVAILABLE);
516         fileio->fd = unix_handle;  /* FIXME */
517         fileio->event = hEvent;
518         NtResetEvent(hEvent, NULL);
519
520         io_status->u.Status = STATUS_PENDING;
521         ret = fileio_queue_async(fileio, io_status, TRUE);
522         if (ret != STATUS_SUCCESS)
523         {
524             wine_server_release_fd( hFile, unix_handle );
525             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
526             RtlFreeHeap(GetProcessHeap(), 0, fileio);
527             return ret;
528         }
529         if (flags & FD_FLAG_TIMEOUT)
530         {
531             ret = NtWaitForSingleObject(hEvent, TRUE, NULL);
532             NtClose(hEvent);
533             if (ret != STATUS_USER_APC)
534                 fileio->queue_apc_on_error = 1;
535         }
536         else
537         {
538             LARGE_INTEGER   timeout;
539
540             /* let some APC be run, this will read some already pending data */
541             timeout.u.LowPart = timeout.u.HighPart = 0;
542             ret = NtDelayExecution( TRUE, &timeout );
543             /* the apc didn't run and therefore the completion routine now
544              * needs to be sent errors.
545              * Note that there is no race between setting this flag and
546              * returning errors because apc's are run only during alertable
547              * waits */
548             if (ret != STATUS_USER_APC)
549                 fileio->queue_apc_on_error = 1;
550         }
551         TRACE("= 0x%08lx\n", io_status->u.Status);
552         return io_status->u.Status;
553     }
554
555     if (offset)
556     {
557         FILE_POSITION_INFORMATION   fpi;
558
559         fpi.CurrentByteOffset = *offset;
560         io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi), 
561                                                    FilePositionInformation);
562         if (io_status->u.Status)
563         {
564             wine_server_release_fd( hFile, unix_handle );
565             return io_status->u.Status;
566         }
567     }
568     /* code for synchronous reads */
569     while ((io_status->Information = read( unix_handle, buffer, length )) == -1)
570     {
571         if ((errno == EAGAIN) || (errno == EINTR)) continue;
572         if (errno == EFAULT)
573         {
574             io_status->Information = 0;
575             io_status->u.Status = STATUS_ACCESS_VIOLATION;
576         }
577         else io_status->u.Status = FILE_GetNtStatus();
578         break;
579     }
580     wine_server_release_fd( hFile, unix_handle );
581     TRACE("= 0x%08lx\n", io_status->u.Status);
582     return io_status->u.Status;
583 }
584
585 /***********************************************************************
586  *             FILE_AsyncWriteService      (INTERNAL)
587  *
588  *  This function is called while the client is waiting on the
589  *  server, so we can't make any server calls here.
590  */
591 static void WINAPI FILE_AsyncWriteService(void *ovp, IO_STATUS_BLOCK *iosb, ULONG status)
592 {
593     async_fileio *fileio = (async_fileio *) ovp;
594     int result;
595     int already = iosb->Information;
596
597     TRACE("(%p %p %lu)\n",iosb, fileio->buffer, status);
598
599     switch (status)
600     {
601     case STATUS_ALERTED:
602         /* write some data (non-blocking) */
603         if ( fileio->avail_mode )
604             result = write(fileio->fd, &fileio->buffer[already], 
605                            fileio->count - already);
606         else
607         {
608             result = pwrite(fileio->fd, &fileio->buffer[already], 
609                             fileio->count - already, fileio->offset + already);
610             if ((result < 0) && (errno == ESPIPE))
611                 result = write(fileio->fd, &fileio->buffer[already], 
612                                fileio->count - already);
613         }
614
615         if (result < 0)
616         {
617             if (errno == EAGAIN || errno == EINTR) iosb->u.Status = STATUS_PENDING;
618             else iosb->u.Status = FILE_GetNtStatus();
619         }
620         else
621         {
622             iosb->Information += result;
623             iosb->u.Status = (iosb->Information < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
624             TRACE("wrote %d more bytes %ld/%d so far\n", 
625                   result, iosb->Information, fileio->count);
626         }
627         if (iosb->u.Status == STATUS_PENDING)
628             fileio_queue_async(fileio, iosb, FALSE);
629         break;
630     default:
631         iosb->u.Status = status;
632         fileio_terminate(fileio, iosb);
633         break;
634     }
635 }
636
637 /******************************************************************************
638  *  NtWriteFile                                 [NTDLL.@]
639  *  ZwWriteFile                                 [NTDLL.@]
640  *
641  * Write to an open file handle.
642  *
643  * PARAMS
644  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
645  *  Event         [I] Event to signal upon completion (or NULL)
646  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
647  *  ApcContext    [I] Context for ApcRoutine (or NULL)
648  *  IoStatusBlock [O] Receives information about the operation on return
649  *  Buffer        [I] Source for the data to write
650  *  Length        [I] Size of Buffer
651  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
652  *  Key           [O] Function unknown (may be NULL)
653  *
654  * RETURNS
655  *  Success: 0. IoStatusBlock is updated, and the Information member contains
656  *           The number of bytes written.
657  *  Failure: An NTSTATUS error code describing the error.
658  */
659 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
660                             PIO_APC_ROUTINE apc, void* apc_user,
661                             PIO_STATUS_BLOCK io_status, 
662                             const void* buffer, ULONG length,
663                             PLARGE_INTEGER offset, PULONG key)
664 {
665     int unix_handle, flags;
666
667     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p)!\n",
668           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
669
670     if (!io_status) return STATUS_ACCESS_VIOLATION;
671
672     io_status->Information = 0;
673     io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_WRITE, &unix_handle, &flags );
674     if (io_status->u.Status) return io_status->u.Status;
675
676     if (flags & FD_FLAG_SEND_SHUTDOWN)
677     {
678         wine_server_release_fd( hFile, unix_handle );
679         return STATUS_PIPE_DISCONNECTED;
680     }
681
682     if (flags & FD_FLAG_TIMEOUT)
683     {
684         if (hEvent)
685         {
686             /* this shouldn't happen, but check it */
687             FIXME("NIY-hEvent\n");
688             wine_server_release_fd( hFile, unix_handle );
689             return STATUS_NOT_IMPLEMENTED;
690         }
691         io_status->u.Status = NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, NULL, 0, 0);
692         if (io_status->u.Status)
693         {
694             wine_server_release_fd( hFile, unix_handle );
695             return io_status->u.Status;
696         }
697     }
698
699     if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
700     {
701         async_fileio*   fileio;
702         NTSTATUS ret;
703
704         if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
705         {
706             wine_server_release_fd( hFile, unix_handle );
707             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
708             return STATUS_NO_MEMORY;
709         }
710         fileio->handle = hFile;
711         fileio->count = length;
712         if (offset)
713         {
714             fileio->offset = offset->QuadPart;
715             if (offset->u.HighPart && fileio->offset == offset->u.LowPart)
716                 FIXME("High part of offset is lost\n");
717         }
718         else  
719         {
720             fileio->offset = 0;
721         }
722         fileio->apc = apc;
723         fileio->apc_user = apc_user;
724         fileio->buffer = (void*)buffer;
725         fileio->queue_apc_on_error = 0;
726         fileio->avail_mode = (flags & FD_FLAG_AVAILABLE);
727         fileio->fd = unix_handle;  /* FIXME */
728         fileio->event = hEvent;
729         NtResetEvent(hEvent, NULL);
730
731         io_status->Information = 0;
732         io_status->u.Status = STATUS_PENDING;
733         ret = fileio_queue_async(fileio, io_status, FALSE);
734         if (ret != STATUS_SUCCESS)
735         {
736             wine_server_release_fd( hFile, unix_handle );
737             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
738             RtlFreeHeap(GetProcessHeap(), 0, fileio);
739             return ret;
740         }
741         if (flags & FD_FLAG_TIMEOUT)
742         {
743             ret = NtWaitForSingleObject(hEvent, TRUE, NULL);
744             NtClose(hEvent);
745             if (ret != STATUS_USER_APC)
746                 fileio->queue_apc_on_error = 1;
747         }
748         else
749         {
750             LARGE_INTEGER   timeout;
751
752             /* let some APC be run, this will write as much data as possible */
753             timeout.u.LowPart = timeout.u.HighPart = 0;
754             ret = NtDelayExecution( TRUE, &timeout );
755             /* the apc didn't run and therefore the completion routine now
756              * needs to be sent errors.
757              * Note that there is no race between setting this flag and
758              * returning errors because apc's are run only during alertable
759              * waits */
760             if (ret != STATUS_USER_APC)
761                 fileio->queue_apc_on_error = 1;
762         }
763         return io_status->u.Status;
764     }
765
766     if (offset)
767     {
768         FILE_POSITION_INFORMATION   fpi;
769
770         fpi.CurrentByteOffset = *offset;
771         io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi),
772                                                    FilePositionInformation);
773         if (io_status->u.Status)
774         {
775             wine_server_release_fd( hFile, unix_handle );
776             return io_status->u.Status;
777         }
778     }
779
780     /* synchronous file write */
781     while ((io_status->Information = write( unix_handle, buffer, length )) == -1)
782     {
783         if ((errno == EAGAIN) || (errno == EINTR)) continue;
784         if (errno == EFAULT)
785         {
786             io_status->Information = 0;
787             io_status->u.Status = STATUS_INVALID_USER_BUFFER;
788         }
789         else if (errno == ENOSPC) io_status->u.Status = STATUS_DISK_FULL;
790         else io_status->u.Status = FILE_GetNtStatus();
791         break;
792     }
793     wine_server_release_fd( hFile, unix_handle );
794     return io_status->u.Status;
795 }
796
797 /**************************************************************************
798  *              NtDeviceIoControlFile                   [NTDLL.@]
799  *              ZwDeviceIoControlFile                   [NTDLL.@]
800  *
801  * Perform an I/O control operation on an open file handle.
802  *
803  * PARAMS
804  *  DeviceHandle     [I] Handle returned from ZwOpenFile() or ZwCreateFile()
805  *  Event            [I] Event to signal upon completion (or NULL)
806  *  ApcRoutine       [I] Callback to call upon completion (or NULL)
807  *  ApcContext       [I] Context for ApcRoutine (or NULL)
808  *  IoStatusBlock    [O] Receives information about the operation on return
809  *  IoControlCode    [I] Control code for the operation to perform
810  *  InputBuffer      [I] Source for any input data required (or NULL)
811  *  InputBufferSize  [I] Size of InputBuffer
812  *  OutputBuffer     [O] Source for any output data returned (or NULL)
813  *  OutputBufferSize [I] Size of OutputBuffer
814  *
815  * RETURNS
816  *  Success: 0. IoStatusBlock is updated.
817  *  Failure: An NTSTATUS error code describing the error.
818  */
819 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE DeviceHandle, HANDLE hEvent,
820                                       PIO_APC_ROUTINE UserApcRoutine, 
821                                       PVOID UserApcContext,
822                                       PIO_STATUS_BLOCK IoStatusBlock,
823                                       ULONG IoControlCode,
824                                       PVOID InputBuffer,
825                                       ULONG InputBufferSize,
826                                       PVOID OutputBuffer,
827                                       ULONG OutputBufferSize)
828 {
829     TRACE("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx)\n",
830           DeviceHandle, hEvent, UserApcRoutine, UserApcContext,
831           IoStatusBlock, IoControlCode, 
832           InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize);
833
834     if (CDROM_DeviceIoControl(DeviceHandle, hEvent,
835                               UserApcRoutine, UserApcContext,
836                               IoStatusBlock, IoControlCode,
837                               InputBuffer, InputBufferSize,
838                               OutputBuffer, OutputBufferSize) == STATUS_NO_SUCH_DEVICE)
839     {
840         /* it wasn't a CDROM */
841         FIXME("Unimplemented dwIoControlCode=%08lx\n", IoControlCode);
842         IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
843         IoStatusBlock->Information = 0;
844         if (hEvent) NtSetEvent(hEvent, NULL);
845     }
846     return IoStatusBlock->u.Status;
847 }
848
849 /******************************************************************************
850  * NtFsControlFile [NTDLL.@]
851  * ZwFsControlFile [NTDLL.@]
852  */
853 NTSTATUS WINAPI NtFsControlFile(
854         IN HANDLE DeviceHandle,
855         IN HANDLE Event OPTIONAL,
856         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
857         IN PVOID ApcContext OPTIONAL,
858         OUT PIO_STATUS_BLOCK IoStatusBlock,
859         IN ULONG IoControlCode,
860         IN PVOID InputBuffer,
861         IN ULONG InputBufferSize,
862         OUT PVOID OutputBuffer,
863         IN ULONG OutputBufferSize)
864 {
865         FIXME("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx): stub\n",
866         DeviceHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,IoControlCode,
867         InputBuffer,InputBufferSize,OutputBuffer,OutputBufferSize);
868         return 0;
869 }
870
871 /******************************************************************************
872  *  NtSetVolumeInformationFile          [NTDLL.@]
873  *  ZwSetVolumeInformationFile          [NTDLL.@]
874  *
875  * Set volume information for an open file handle.
876  *
877  * PARAMS
878  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
879  *  IoStatusBlock      [O] Receives information about the operation on return
880  *  FsInformation      [I] Source for volume information
881  *  Length             [I] Size of FsInformation
882  *  FsInformationClass [I] Type of volume information to set
883  *
884  * RETURNS
885  *  Success: 0. IoStatusBlock is updated.
886  *  Failure: An NTSTATUS error code describing the error.
887  */
888 NTSTATUS WINAPI NtSetVolumeInformationFile(
889         IN HANDLE FileHandle,
890         PIO_STATUS_BLOCK IoStatusBlock,
891         PVOID FsInformation,
892         ULONG Length,
893         FS_INFORMATION_CLASS FsInformationClass)
894 {
895         FIXME("(%p,%p,%p,0x%08lx,0x%08x) stub\n",
896         FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
897         return 0;
898 }
899
900 /******************************************************************************
901  *  NtQueryInformationFile              [NTDLL.@]
902  *  ZwQueryInformationFile              [NTDLL.@]
903  *
904  * Get information about an open file handle.
905  *
906  * PARAMS
907  *  hFile    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
908  *  io       [O] Receives information about the operation on return
909  *  ptr      [O] Destination for file information
910  *  len      [I] Size of FileInformation
911  *  class    [I] Type of file information to get
912  *
913  * RETURNS
914  *  Success: 0. IoStatusBlock and FileInformation are updated.
915  *  Failure: An NTSTATUS error code describing the error.
916  */
917 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
918                                         PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
919 {
920     static const size_t info_sizes[] =
921     {
922         0,
923         sizeof(FILE_DIRECTORY_INFORMATION),            /* FileDirectoryInformation */
924         sizeof(FILE_FULL_DIRECTORY_INFORMATION),       /* FileFullDirectoryInformation */
925         sizeof(FILE_BOTH_DIRECTORY_INFORMATION),       /* FileBothDirectoryInformation */
926         sizeof(FILE_BASIC_INFORMATION),                /* FileBasicInformation */
927         sizeof(FILE_STANDARD_INFORMATION),             /* FileStandardInformation */
928         sizeof(FILE_INTERNAL_INFORMATION),             /* FileInternalInformation */
929         sizeof(FILE_EA_INFORMATION),                   /* FileEaInformation */
930         sizeof(FILE_ACCESS_INFORMATION),               /* FileAccessInformation */
931         sizeof(FILE_NAME_INFORMATION)-sizeof(WCHAR),   /* FileNameInformation */
932         sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
933         0,                                             /* FileLinkInformation */
934         sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR),  /* FileNamesInformation */
935         sizeof(FILE_DISPOSITION_INFORMATION),          /* FileDispositionInformation */
936         sizeof(FILE_POSITION_INFORMATION),             /* FilePositionInformation */
937         sizeof(FILE_FULL_EA_INFORMATION),              /* FileFullEaInformation */
938         sizeof(FILE_MODE_INFORMATION),                 /* FileModeInformation */
939         sizeof(FILE_ALIGNMENT_INFORMATION),            /* FileAlignmentInformation */
940         sizeof(FILE_ALL_INFORMATION)-sizeof(WCHAR),    /* FileAllInformation */
941         sizeof(FILE_ALLOCATION_INFORMATION),           /* FileAllocationInformation */
942         sizeof(FILE_END_OF_FILE_INFORMATION),          /* FileEndOfFileInformation */
943         0,                                             /* FileAlternateNameInformation */
944         sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
945         0,                                             /* FilePipeInformation */
946         0,                                             /* FilePipeLocalInformation */
947         0,                                             /* FilePipeRemoteInformation */
948         sizeof(FILE_MAILSLOT_QUERY_INFORMATION),       /* FileMailslotQueryInformation */
949         0,                                             /* FileMailslotSetInformation */
950         0,                                             /* FileCompressionInformation */
951         0,                                             /* FileObjectIdInformation */
952         0,                                             /* FileCompletionInformation */
953         0,                                             /* FileMoveClusterInformation */
954         0,                                             /* FileQuotaInformation */
955         0,                                             /* FileReparsePointInformation */
956         0,                                             /* FileNetworkOpenInformation */
957         0,                                             /* FileAttributeTagInformation */
958         0                                              /* FileTrackingInformation */
959     };
960
961     struct stat st;
962     int fd;
963
964     TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", hFile, io, ptr, len, class);
965
966     io->Information = 0;
967
968     if (class <= 0 || class >= FileMaximumInformation)
969         return io->u.Status = STATUS_INVALID_INFO_CLASS;
970     if (!info_sizes[class])
971     {
972         FIXME("Unsupported class (%d)\n", class);
973         return io->u.Status = STATUS_NOT_IMPLEMENTED;
974     }
975     if (len < info_sizes[class])
976         return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
977
978     if ((io->u.Status = wine_server_handle_to_fd( hFile, 0, &fd, NULL )))
979         return io->u.Status;
980
981     switch (class)
982     {
983     case FileBasicInformation:
984         {
985             FILE_BASIC_INFORMATION *info = ptr;
986
987             if (fstat( fd, &st ) == -1)
988                 io->u.Status = FILE_GetNtStatus();
989             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
990                 io->u.Status = STATUS_INVALID_INFO_CLASS;
991             else
992             {
993                 if (S_ISDIR(st.st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
994                 else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
995                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
996                     info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
997                 RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime);
998                 RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime);
999                 RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime);
1000                 RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime);
1001             }
1002         }
1003         break;
1004     case FileStandardInformation:
1005         {
1006             FILE_STANDARD_INFORMATION *info = ptr;
1007
1008             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1009             else
1010             {
1011                 if ((info->Directory = S_ISDIR(st.st_mode)))
1012                 {
1013                     info->AllocationSize.QuadPart = 0;
1014                     info->EndOfFile.QuadPart      = 0;
1015                     info->NumberOfLinks           = 1;
1016                     info->DeletePending           = FALSE;
1017                 }
1018                 else
1019                 {
1020                     info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1021                     info->EndOfFile.QuadPart      = st.st_size;
1022                     info->NumberOfLinks           = st.st_nlink;
1023                     info->DeletePending           = FALSE; /* FIXME */
1024                 }
1025             }
1026         }
1027         break;
1028     case FilePositionInformation:
1029         {
1030             FILE_POSITION_INFORMATION *info = ptr;
1031             off_t res = lseek( fd, 0, SEEK_CUR );
1032             if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
1033             else info->CurrentByteOffset.QuadPart = res;
1034         }
1035         break;
1036     case FileInternalInformation:
1037         {
1038             FILE_INTERNAL_INFORMATION *info = ptr;
1039
1040             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1041             else info->IndexNumber.QuadPart = st.st_ino;
1042         }
1043         break;
1044     case FileEaInformation:
1045         {
1046             FILE_EA_INFORMATION *info = ptr;
1047             info->EaSize = 0;
1048         }
1049         break;
1050     case FileEndOfFileInformation:
1051         {
1052             FILE_END_OF_FILE_INFORMATION *info = ptr;
1053
1054             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1055             else info->EndOfFile.QuadPart = S_ISDIR(st.st_mode) ? 0 : st.st_size;
1056         }
1057         break;
1058     case FileAllInformation:
1059         {
1060             FILE_ALL_INFORMATION *info = ptr;
1061
1062             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1063             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1064                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1065             else
1066             {
1067                 if ((info->StandardInformation.Directory = S_ISDIR(st.st_mode)))
1068                 {
1069                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1070                     info->StandardInformation.AllocationSize.QuadPart = 0;
1071                     info->StandardInformation.EndOfFile.QuadPart      = 0;
1072                     info->StandardInformation.NumberOfLinks           = 1;
1073                     info->StandardInformation.DeletePending           = FALSE;
1074                 }
1075                 else
1076                 {
1077                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1078                     info->StandardInformation.AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1079                     info->StandardInformation.EndOfFile.QuadPart      = st.st_size;
1080                     info->StandardInformation.NumberOfLinks           = st.st_nlink;
1081                     info->StandardInformation.DeletePending           = FALSE; /* FIXME */
1082                 }
1083                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1084                     info->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_READONLY;
1085                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.CreationTime);
1086                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.LastWriteTime);
1087                 RtlSecondsSince1970ToTime( st.st_ctime, &info->BasicInformation.ChangeTime);
1088                 RtlSecondsSince1970ToTime( st.st_atime, &info->BasicInformation.LastAccessTime);
1089                 info->InternalInformation.IndexNumber.QuadPart = st.st_ino;
1090                 info->EaInformation.EaSize = 0;
1091                 info->AccessInformation.AccessFlags = 0;  /* FIXME */
1092                 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
1093                 info->ModeInformation.Mode = 0;  /* FIXME */
1094                 info->AlignmentInformation.AlignmentRequirement = 1;  /* FIXME */
1095                 info->NameInformation.FileNameLength = 0;
1096                 io->Information = sizeof(*info) - sizeof(WCHAR);
1097             }
1098         }
1099         break;
1100     case FileMailslotQueryInformation:
1101         {
1102             FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
1103
1104             SERVER_START_REQ( set_mailslot_info )
1105             {
1106                 req->handle = hFile;
1107                 req->flags = 0;
1108                 io->u.Status = wine_server_call( req );
1109                 if( io->u.Status == STATUS_SUCCESS )
1110                 {
1111                     info->MaximumMessageSize = reply->max_msgsize;
1112                     info->MailslotQuota = 0;
1113                     info->NextMessageSize = reply->next_msgsize;
1114                     info->MessagesAvailable = reply->msg_count;
1115                     info->ReadTimeout.QuadPart = reply->read_timeout * -10000;
1116                 }
1117             }
1118             SERVER_END_REQ;
1119         }
1120         break;
1121     default:
1122         FIXME("Unsupported class (%d)\n", class);
1123         io->u.Status = STATUS_NOT_IMPLEMENTED;
1124         break;
1125     }
1126     wine_server_release_fd( hFile, fd );
1127     if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
1128     return io->u.Status;
1129 }
1130
1131 /******************************************************************************
1132  *  NtSetInformationFile                [NTDLL.@]
1133  *  ZwSetInformationFile                [NTDLL.@]
1134  *
1135  * Set information about an open file handle.
1136  *
1137  * PARAMS
1138  *  handle  [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1139  *  io      [O] Receives information about the operation on return
1140  *  ptr     [I] Source for file information
1141  *  len     [I] Size of FileInformation
1142  *  class   [I] Type of file information to set
1143  *
1144  * RETURNS
1145  *  Success: 0. io is updated.
1146  *  Failure: An NTSTATUS error code describing the error.
1147  */
1148 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
1149                                      PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
1150 {
1151     int fd;
1152
1153     TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", handle, io, ptr, len, class);
1154
1155     if ((io->u.Status = wine_server_handle_to_fd( handle, 0, &fd, NULL )))
1156         return io->u.Status;
1157
1158     io->u.Status = STATUS_SUCCESS;
1159     switch (class)
1160     {
1161     case FileBasicInformation:
1162         if (len >= sizeof(FILE_BASIC_INFORMATION))
1163         {
1164             struct stat st;
1165             const FILE_BASIC_INFORMATION *info = ptr;
1166
1167             if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
1168             {
1169                 ULONGLONG sec, nsec;
1170                 struct timeval tv[2];
1171
1172                 if (!info->LastAccessTime.QuadPart || !info->LastWriteTime.QuadPart)
1173                 {
1174
1175                     tv[0].tv_sec = tv[0].tv_usec = 0;
1176                     tv[1].tv_sec = tv[1].tv_usec = 0;
1177                     if (!fstat( fd, &st ))
1178                     {
1179                         tv[0].tv_sec = st.st_atime;
1180                         tv[1].tv_sec = st.st_mtime;
1181                     }
1182                 }
1183                 if (info->LastAccessTime.QuadPart)
1184                 {
1185                     sec = RtlLargeIntegerDivide( info->LastAccessTime.QuadPart, 10000000, &nsec );
1186                     tv[0].tv_sec = sec - SECS_1601_TO_1970;
1187                     tv[0].tv_usec = (UINT)nsec / 10;
1188                 }
1189                 if (info->LastWriteTime.QuadPart)
1190                 {
1191                     sec = RtlLargeIntegerDivide( info->LastWriteTime.QuadPart, 10000000, &nsec );
1192                     tv[1].tv_sec = sec - SECS_1601_TO_1970;
1193                     tv[1].tv_usec = (UINT)nsec / 10;
1194                 }
1195                 if (futimes( fd, tv ) == -1) io->u.Status = FILE_GetNtStatus();
1196             }
1197
1198             if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
1199             {
1200                 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1201                 else
1202                 {
1203                     if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
1204                     {
1205                         if (S_ISDIR( st.st_mode))
1206                             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
1207                         else
1208                             st.st_mode &= ~0222; /* clear write permission bits */
1209                     }
1210                     else
1211                     {
1212                         /* add write permission only where we already have read permission */
1213                         st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
1214                     }
1215                     if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
1216                 }
1217             }
1218         }
1219         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1220         break;
1221
1222     case FilePositionInformation:
1223         if (len >= sizeof(FILE_POSITION_INFORMATION))
1224         {
1225             const FILE_POSITION_INFORMATION *info = ptr;
1226
1227             if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
1228                 io->u.Status = FILE_GetNtStatus();
1229         }
1230         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1231         break;
1232
1233     case FileEndOfFileInformation:
1234         if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
1235         {
1236             struct stat st;
1237             const FILE_END_OF_FILE_INFORMATION *info = ptr;
1238
1239             /* first try normal truncate */
1240             if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1241
1242             /* now check for the need to extend the file */
1243             if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
1244             {
1245                 static const char zero;
1246
1247                 /* extend the file one byte beyond the requested size and then truncate it */
1248                 /* this should work around ftruncate implementations that can't extend files */
1249                 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
1250                     ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1251             }
1252             io->u.Status = FILE_GetNtStatus();
1253         }
1254         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1255         break;
1256
1257     case FileMailslotSetInformation:
1258         {
1259             FILE_MAILSLOT_SET_INFORMATION *info = ptr;
1260
1261             SERVER_START_REQ( set_mailslot_info )
1262             {
1263                 req->handle = handle;
1264                 req->flags = MAILSLOT_SET_READ_TIMEOUT;
1265                 req->read_timeout = info->ReadTimeout.QuadPart / -10000;
1266                 io->u.Status = wine_server_call( req );
1267             }
1268             SERVER_END_REQ;
1269         }
1270         break;
1271
1272     default:
1273         FIXME("Unsupported class (%d)\n", class);
1274         io->u.Status = STATUS_NOT_IMPLEMENTED;
1275         break;
1276     }
1277     wine_server_release_fd( handle, fd );
1278     io->Information = 0;
1279     return io->u.Status;
1280 }
1281
1282
1283 /******************************************************************************
1284  *              NtQueryFullAttributesFile   (NTDLL.@)
1285  */
1286 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
1287                                            FILE_NETWORK_OPEN_INFORMATION *info )
1288 {
1289     ANSI_STRING unix_name;
1290     NTSTATUS status;
1291
1292     if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN,
1293                                               !(attr->Attributes & OBJ_CASE_INSENSITIVE) )))
1294     {
1295         struct stat st;
1296
1297         if (stat( unix_name.Buffer, &st ) == -1)
1298             status = FILE_GetNtStatus();
1299         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1300             status = STATUS_INVALID_INFO_CLASS;
1301         else
1302         {
1303             if (S_ISDIR(st.st_mode))
1304             {
1305                 info->FileAttributes          = FILE_ATTRIBUTE_DIRECTORY;
1306                 info->AllocationSize.QuadPart = 0;
1307                 info->EndOfFile.QuadPart      = 0;
1308             }
1309             else
1310             {
1311                 info->FileAttributes          = FILE_ATTRIBUTE_ARCHIVE;
1312                 info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1313                 info->EndOfFile.QuadPart      = st.st_size;
1314             }
1315             if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1316                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1317             RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime );
1318             RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime );
1319             RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime );
1320             RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime );
1321             if (DIR_is_hidden_file( attr->ObjectName ))
1322                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1323         }
1324         RtlFreeAnsiString( &unix_name );
1325     }
1326     else WARN("%s not found (%lx)\n", debugstr_us(attr->ObjectName), status );
1327     return status;
1328 }
1329
1330
1331 /******************************************************************************
1332  *              NtQueryAttributesFile   (NTDLL.@)
1333  *              ZwQueryAttributesFile   (NTDLL.@)
1334  */
1335 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
1336 {
1337     FILE_NETWORK_OPEN_INFORMATION full_info;
1338     NTSTATUS status;
1339
1340     if (!(status = NtQueryFullAttributesFile( attr, &full_info )))
1341     {
1342         info->CreationTime.QuadPart   = full_info.CreationTime.QuadPart;
1343         info->LastAccessTime.QuadPart = full_info.LastAccessTime.QuadPart;
1344         info->LastWriteTime.QuadPart  = full_info.LastWriteTime.QuadPart;
1345         info->ChangeTime.QuadPart     = full_info.ChangeTime.QuadPart;
1346         info->FileAttributes          = full_info.FileAttributes;
1347     }
1348     return status;
1349 }
1350
1351
1352 /******************************************************************************
1353  *  NtQueryVolumeInformationFile                [NTDLL.@]
1354  *  ZwQueryVolumeInformationFile                [NTDLL.@]
1355  *
1356  * Get volume information for an open file handle.
1357  *
1358  * PARAMS
1359  *  handle      [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1360  *  io          [O] Receives information about the operation on return
1361  *  buffer      [O] Destination for volume information
1362  *  length      [I] Size of FsInformation
1363  *  info_class  [I] Type of volume information to set
1364  *
1365  * RETURNS
1366  *  Success: 0. io and buffer are updated.
1367  *  Failure: An NTSTATUS error code describing the error.
1368  */
1369 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
1370                                               PVOID buffer, ULONG length,
1371                                               FS_INFORMATION_CLASS info_class )
1372 {
1373     int fd;
1374     struct stat st;
1375
1376     if ((io->u.Status = wine_server_handle_to_fd( handle, 0, &fd, NULL )) != STATUS_SUCCESS)
1377         return io->u.Status;
1378
1379     io->u.Status = STATUS_NOT_IMPLEMENTED;
1380     io->Information = 0;
1381
1382     switch( info_class )
1383     {
1384     case FileFsVolumeInformation:
1385         FIXME( "%p: volume info not supported\n", handle );
1386         break;
1387     case FileFsLabelInformation:
1388         FIXME( "%p: label info not supported\n", handle );
1389         break;
1390     case FileFsSizeInformation:
1391         if (length < sizeof(FILE_FS_SIZE_INFORMATION))
1392             io->u.Status = STATUS_BUFFER_TOO_SMALL;
1393         else
1394         {
1395             FILE_FS_SIZE_INFORMATION *info = buffer;
1396
1397             if (fstat( fd, &st ) < 0)
1398             {
1399                 io->u.Status = FILE_GetNtStatus();
1400                 break;
1401             }
1402             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1403             {
1404                 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
1405             }
1406             else
1407             {
1408                 /* Linux's fstatvfs is buggy */
1409 #if !defined(linux) || !defined(HAVE_FSTATFS)
1410                 struct statvfs stfs;
1411
1412                 if (fstatvfs( fd, &stfs ) < 0)
1413                 {
1414                     io->u.Status = FILE_GetNtStatus();
1415                     break;
1416                 }
1417                 info->BytesPerSector = stfs.f_frsize;
1418 #else
1419                 struct statfs stfs;
1420                 if (fstatfs( fd, &stfs ) < 0)
1421                 {
1422                     io->u.Status = FILE_GetNtStatus();
1423                     break;
1424                 }
1425                 info->BytesPerSector = stfs.f_bsize;
1426 #endif
1427                 info->TotalAllocationUnits.QuadPart = stfs.f_blocks;
1428                 info->AvailableAllocationUnits.QuadPart = stfs.f_bavail;
1429                 info->SectorsPerAllocationUnit = 1;
1430                 io->Information = sizeof(*info);
1431                 io->u.Status = STATUS_SUCCESS;
1432             }
1433         }
1434         break;
1435     case FileFsDeviceInformation:
1436         if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
1437             io->u.Status = STATUS_BUFFER_TOO_SMALL;
1438         else
1439         {
1440             FILE_FS_DEVICE_INFORMATION *info = buffer;
1441
1442             info->Characteristics = 0;
1443             if (fstat( fd, &st ) < 0)
1444             {
1445                 io->u.Status = FILE_GetNtStatus();
1446                 break;
1447             }
1448             if (S_ISCHR( st.st_mode ))
1449             {
1450                 info->DeviceType = FILE_DEVICE_UNKNOWN;
1451 #ifdef linux
1452                 switch(major(st.st_rdev))
1453                 {
1454                 case MEM_MAJOR:
1455                     info->DeviceType = FILE_DEVICE_NULL;
1456                     break;
1457                 case TTY_MAJOR:
1458                     info->DeviceType = FILE_DEVICE_SERIAL_PORT;
1459                     break;
1460                 case LP_MAJOR:
1461                     info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
1462                     break;
1463                 }
1464 #endif
1465             }
1466             else if (S_ISBLK( st.st_mode ))
1467             {
1468                 info->DeviceType = FILE_DEVICE_DISK;
1469             }
1470             else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
1471             {
1472                 info->DeviceType = FILE_DEVICE_NAMED_PIPE;
1473             }
1474             else  /* regular file or directory */
1475             {
1476 #if defined(linux) && defined(HAVE_FSTATFS)
1477                 struct statfs stfs;
1478
1479                 /* check for floppy disk */
1480                 if (major(st.st_dev) == FLOPPY_MAJOR)
1481                     info->Characteristics |= FILE_REMOVABLE_MEDIA;
1482
1483                 if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
1484                 switch (stfs.f_type)
1485                 {
1486                 case 0x9660:      /* iso9660 */
1487                 case 0x15013346:  /* udf */
1488                     info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
1489                     info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
1490                     break;
1491                 case 0x6969:  /* nfs */
1492                 case 0x517B:  /* smbfs */
1493                 case 0x564c:  /* ncpfs */
1494                     info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
1495                     info->Characteristics |= FILE_REMOTE_DEVICE;
1496                     break;
1497                 case 0x01021994:  /* tmpfs */
1498                 case 0x28cd3d45:  /* cramfs */
1499                 case 0x1373:      /* devfs */
1500                 case 0x9fa0:      /* procfs */
1501                     info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
1502                     break;
1503                 default:
1504                     info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1505                     break;
1506                 }
1507 #elif defined (__APPLE__)
1508 # include <IOKit/IOKitLib.h>
1509 # include <CoreFoundation/CFNumber.h> /* for kCFBooleanTrue, kCFBooleanFalse */
1510 # include <paths.h>
1511                 struct statfs stfs;
1512                 
1513                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1514                 
1515                 if (fstatfs( fd, &stfs ) < 0) break;
1516
1517                 /* stfs.f_type is reserved (always set to 0) so use IOKit */
1518                 kern_return_t kernResult = KERN_FAILURE; 
1519                 mach_port_t masterPort;
1520                 
1521                 char bsdName[6]; /* disk#\0 */
1522                 const char *name = stfs.f_mntfromname + strlen(_PATH_DEV);
1523                 memcpy( bsdName, name, min(strlen(name)+1,sizeof(bsdName)) );
1524                 bsdName[sizeof(bsdName)-1] = 0;
1525
1526                 kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
1527
1528                 if (kernResult == KERN_SUCCESS)
1529                 {
1530                     CFMutableDictionaryRef matching = IOBSDNameMatching(masterPort, 0, bsdName);
1531                     
1532                     if (matching)
1533                     {
1534                         CFMutableDictionaryRef properties;
1535                         io_service_t devService = IOServiceGetMatchingService(masterPort, matching);
1536                         
1537                         if (IORegistryEntryCreateCFProperties(devService, 
1538                                                                 &properties,
1539                                                                 kCFAllocatorDefault, 0) != KERN_SUCCESS)
1540                                                                     break;
1541                         if ( CFEqual(
1542                                         CFDictionaryGetValue(properties, CFSTR("Removable")),
1543                                         kCFBooleanTrue)
1544                             ) info->Characteristics |= FILE_REMOVABLE_MEDIA;
1545                             
1546                         if ( CFEqual(
1547                                         CFDictionaryGetValue(properties, CFSTR("Writable")),
1548                                         kCFBooleanFalse)
1549                             ) info->Characteristics |= FILE_READ_ONLY_DEVICE;
1550
1551                         /*
1552                             NB : mounted disk image (.img/.dmg) don't provide specific type
1553                         */
1554                         CFStringRef type;
1555                         if ( (type = CFDictionaryGetValue(properties, CFSTR("Type"))) )
1556                         {
1557                             if ( CFStringCompare(type, CFSTR("CD-ROM"), 0) == kCFCompareEqualTo
1558                                 || CFStringCompare(type, CFSTR("DVD-ROM"), 0) == kCFCompareEqualTo
1559                             )
1560                             {
1561                                 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
1562                             }
1563                         } 
1564                         
1565                         if (properties)
1566                             CFRelease(properties);
1567                     }
1568                 }
1569 #elif defined(sun)
1570                 /* Use dkio to work out device types */
1571                 {
1572 # include <sys/dkio.h>
1573 # include <sys/vtoc.h>
1574                     struct dk_cinfo dkinf;
1575                     int retval = ioctl(fd, DKIOCINFO, &dkinf);
1576                     if(retval==-1){
1577                         WARN("Unable to get disk device type information - assuming a disk like device\n");
1578                         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1579                     }
1580                     switch (dkinf.dki_ctype)
1581                     {
1582                     case DKC_CDROM:
1583                         info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
1584                         info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
1585                         break;
1586                     case DKC_NCRFLOPPY:
1587                     case DKC_SMSFLOPPY:
1588                     case DKC_INTEL82072:
1589                     case DKC_INTEL82077:
1590                         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1591                         info->Characteristics |= FILE_REMOVABLE_MEDIA;
1592                         break;
1593                     case DKC_MD:
1594                         info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
1595                         break;
1596                     default:
1597                         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1598                     }
1599                 }
1600 #else
1601                 static int warned;
1602                 if (!warned++) FIXME( "device info not properly supported on this platform\n" );
1603                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1604 #endif
1605                 info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
1606             }
1607             io->Information = sizeof(*info);
1608             io->u.Status = STATUS_SUCCESS;
1609         }
1610         break;
1611     case FileFsAttributeInformation:
1612         FIXME( "%p: attribute info not supported\n", handle );
1613         break;
1614     case FileFsControlInformation:
1615         FIXME( "%p: control info not supported\n", handle );
1616         break;
1617     case FileFsFullSizeInformation:
1618         FIXME( "%p: full size info not supported\n", handle );
1619         break;
1620     case FileFsObjectIdInformation:
1621         FIXME( "%p: object id info not supported\n", handle );
1622         break;
1623     case FileFsMaximumInformation:
1624         FIXME( "%p: maximum info not supported\n", handle );
1625         break;
1626     default:
1627         io->u.Status = STATUS_INVALID_PARAMETER;
1628         break;
1629     }
1630     wine_server_release_fd( handle, fd );
1631     return io->u.Status;
1632 }
1633
1634
1635 /******************************************************************
1636  *              NtFlushBuffersFile  (NTDLL.@)
1637  *
1638  * Flush any buffered data on an open file handle.
1639  *
1640  * PARAMS
1641  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1642  *  IoStatusBlock      [O] Receives information about the operation on return
1643  *
1644  * RETURNS
1645  *  Success: 0. IoStatusBlock is updated.
1646  *  Failure: An NTSTATUS error code describing the error.
1647  */
1648 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
1649 {
1650     NTSTATUS ret;
1651     HANDLE hEvent = NULL;
1652
1653     SERVER_START_REQ( flush_file )
1654     {
1655         req->handle = hFile;
1656         ret = wine_server_call( req );
1657         hEvent = reply->event;
1658     }
1659     SERVER_END_REQ;
1660     if (!ret && hEvent)
1661     {
1662         ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
1663         NtClose( hEvent );
1664     }
1665     return ret;
1666 }
1667
1668 /******************************************************************
1669  *              NtLockFile       (NTDLL.@)
1670  *
1671  *
1672  */
1673 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
1674                             PIO_APC_ROUTINE apc, void* apc_user,
1675                             PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
1676                             PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
1677                             BOOLEAN exclusive )
1678 {
1679     NTSTATUS    ret;
1680     HANDLE      handle;
1681     BOOLEAN     async;
1682
1683     if (apc || io_status || key)
1684     {
1685         FIXME("Unimplemented yet parameter\n");
1686         return STATUS_NOT_IMPLEMENTED;
1687     }
1688
1689     for (;;)
1690     {
1691         SERVER_START_REQ( lock_file )
1692         {
1693             req->handle      = hFile;
1694             req->offset_low  = offset->u.LowPart;
1695             req->offset_high = offset->u.HighPart;
1696             req->count_low   = count->u.LowPart;
1697             req->count_high  = count->u.HighPart;
1698             req->shared      = !exclusive;
1699             req->wait        = !dont_wait;
1700             ret = wine_server_call( req );
1701             handle = reply->handle;
1702             async  = reply->overlapped;
1703         }
1704         SERVER_END_REQ;
1705         if (ret != STATUS_PENDING)
1706         {
1707             if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
1708             return ret;
1709         }
1710
1711         if (async)
1712         {
1713             FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
1714             if (handle) NtClose( handle );
1715             return STATUS_PENDING;
1716         }
1717         if (handle)
1718         {
1719             NtWaitForSingleObject( handle, FALSE, NULL );
1720             NtClose( handle );
1721         }
1722         else
1723         {
1724             LARGE_INTEGER time;
1725     
1726             /* Unix lock conflict, sleep a bit and retry */
1727             time.QuadPart = 100 * (ULONGLONG)10000;
1728             time.QuadPart = -time.QuadPart;
1729             NtDelayExecution( FALSE, &time );
1730         }
1731     }
1732 }
1733
1734
1735 /******************************************************************
1736  *              NtUnlockFile    (NTDLL.@)
1737  *
1738  *
1739  */
1740 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
1741                               PLARGE_INTEGER offset, PLARGE_INTEGER count,
1742                               PULONG key )
1743 {
1744     NTSTATUS status;
1745
1746     TRACE( "%p %lx%08lx %lx%08lx\n",
1747            hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
1748
1749     if (io_status || key)
1750     {
1751         FIXME("Unimplemented yet parameter\n");
1752         return STATUS_NOT_IMPLEMENTED;
1753     }
1754
1755     SERVER_START_REQ( unlock_file )
1756     {
1757         req->handle      = hFile;
1758         req->offset_low  = offset->u.LowPart;
1759         req->offset_high = offset->u.HighPart;
1760         req->count_low   = count->u.LowPart;
1761         req->count_high  = count->u.HighPart;
1762         status = wine_server_call( req );
1763     }
1764     SERVER_END_REQ;
1765     return status;
1766 }
1767
1768 /******************************************************************
1769  *              NtCreateNamedPipeFile    (NTDLL.@)
1770  *
1771  *
1772  */
1773 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
1774                                        POBJECT_ATTRIBUTES oa, PIO_STATUS_BLOCK iosb,
1775                                        ULONG sharing, ULONG dispo, ULONG options,
1776                                        ULONG pipe_type, ULONG read_mode, 
1777                                        ULONG completion_mode, ULONG max_inst,
1778                                        ULONG inbound_quota, ULONG outbound_quota,
1779                                        PLARGE_INTEGER timeout)
1780 {
1781     NTSTATUS    status;
1782     static const WCHAR leadin[] = {'\\','?','?','\\','P','I','P','E','\\'};
1783
1784     TRACE("(%p %lx %p %p %lx %ld %lx %ld %ld %ld %ld %ld %ld %p): stub\n",
1785           handle, access, oa, iosb, sharing, dispo, options, pipe_type,
1786           read_mode, completion_mode, max_inst, inbound_quota, outbound_quota,
1787           timeout);
1788
1789     if (oa->ObjectName->Length < sizeof(leadin) ||
1790         strncmpiW( oa->ObjectName->Buffer, 
1791                    leadin, sizeof(leadin)/sizeof(leadin[0]) ))
1792         return STATUS_OBJECT_NAME_INVALID;
1793     /* assume we only get relative timeout, and storable in a DWORD as ms */
1794     if (timeout->QuadPart > 0 || (timeout->QuadPart / -10000) >> 32)
1795         FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
1796
1797     SERVER_START_REQ( create_named_pipe )
1798     {
1799         req->options = options; /* FIXME not used in server yet !!!! */
1800         req->flags = 
1801             (pipe_type) ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0 |
1802             (read_mode) ? NAMED_PIPE_MESSAGE_STREAM_READ  : 0 |
1803             (completion_mode) ? NAMED_PIPE_NONBLOCKING_MODE  : 0;
1804         req->maxinstances = max_inst;
1805         req->outsize = outbound_quota;
1806         req->insize  = inbound_quota;
1807         req->timeout = timeout->QuadPart / -10000;
1808         req->inherit = (oa->Attributes & OBJ_INHERIT) != 0;
1809         wine_server_add_data( req, oa->ObjectName->Buffer + 4, 
1810                               oa->ObjectName->Length - 4 * sizeof(WCHAR) );
1811         status = wine_server_call( req );
1812         if (!status) *handle = reply->handle;
1813     }
1814     SERVER_END_REQ;
1815     return status;
1816 }
1817
1818 /******************************************************************
1819  *              NtDeleteFile    (NTDLL.@)
1820  *
1821  *
1822  */
1823 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
1824 {
1825     NTSTATUS status;
1826     HANDLE hFile;
1827     IO_STATUS_BLOCK io;
1828
1829     TRACE("%p\n", ObjectAttributes);
1830     status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE, ObjectAttributes, 
1831                            &io, NULL, 0,
1832                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
1833                            FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
1834     if (status == STATUS_SUCCESS) status = NtClose(hFile);
1835     return status;
1836 }
1837
1838 /******************************************************************
1839  *              NtCancelIoFile    (NTDLL.@)
1840  *
1841  *
1842  */
1843 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
1844 {
1845     LARGE_INTEGER timeout;
1846
1847     TRACE("%p %p\n", hFile, io_status );
1848
1849     SERVER_START_REQ( cancel_async )
1850     {
1851         req->handle = hFile;
1852         wine_server_call( req );
1853     }
1854     SERVER_END_REQ;
1855     /* Let some APC be run, so that we can run the remaining APCs on hFile
1856      * either the cancelation of the pending one, but also the execution
1857      * of the queued APC, but not yet run. This is needed to ensure proper
1858      * clean-up of allocated data.
1859      */
1860     timeout.u.LowPart = timeout.u.HighPart = 0;
1861     return io_status->u.Status = NtDelayExecution( TRUE, &timeout );
1862 }
1863
1864 /******************************************************************************
1865  *  NtCreateMailslotFile        [NTDLL.@]
1866  *  ZwCreateMailslotFile        [NTDLL.@]
1867  *
1868  * PARAMS
1869  *  pHandle          [O] pointer to receive the handle created
1870  *  DesiredAccess    [I] access mode (read, write, etc)
1871  *  ObjectAttributes [I] fully qualified NT path of the mailslot
1872  *  IoStatusBlock    [O] receives completion status and other info
1873  *  CreateOptions    [I]
1874  *  MailslotQuota    [I]
1875  *  MaxMessageSize   [I]
1876  *  TimeOut          [I]
1877  *
1878  * RETURNS
1879  *  An NT status code
1880  */
1881 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
1882      POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
1883      ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
1884      PLARGE_INTEGER TimeOut)
1885 {
1886     static const WCHAR leadin[] = {
1887         '\\','?','?','\\','M','A','I','L','S','L','O','T','\\'};
1888     NTSTATUS ret;
1889
1890     TRACE("%p %08lx %p %p %08lx %08lx %08lx %p\n",
1891               pHandle, DesiredAccess, attr, IoStatusBlock,
1892               CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
1893
1894     if (attr->ObjectName->Length < sizeof(leadin) ||
1895         strncmpiW( attr->ObjectName->Buffer, 
1896                    leadin, sizeof(leadin)/sizeof(leadin[0]) ))
1897     {
1898         return STATUS_OBJECT_NAME_INVALID;
1899     }
1900
1901     SERVER_START_REQ( create_mailslot )
1902     {
1903         req->max_msgsize = MaxMessageSize;
1904         req->read_timeout = TimeOut->QuadPart / -10000;
1905         req->inherit = (attr->Attributes & OBJ_INHERIT) != 0;
1906         wine_server_add_data( req, attr->ObjectName->Buffer + 4,
1907                               attr->ObjectName->Length - 4*sizeof(WCHAR) );
1908         ret = wine_server_call( req );
1909         if( ret == STATUS_SUCCESS )
1910             *pHandle = reply->handle;
1911     }
1912     SERVER_END_REQ;
1913  
1914     return ret;
1915 }