- moved named pipe creation to ntdll
[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     io_status->Information = 0;
462     io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_READ, &unix_handle, &flags );
463     if (io_status->u.Status) return io_status->u.Status;
464
465     if (flags & FD_FLAG_RECV_SHUTDOWN)
466     {
467         wine_server_release_fd( hFile, unix_handle );
468         return STATUS_PIPE_DISCONNECTED;
469     }
470
471     if (flags & FD_FLAG_TIMEOUT)
472     {
473         if (hEvent)
474         {
475             /* this shouldn't happen, but check it */
476             FIXME("NIY-hEvent\n");
477             wine_server_release_fd( hFile, unix_handle );
478             return STATUS_NOT_IMPLEMENTED;
479         }
480         io_status->u.Status = NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, NULL, 0, 0);
481         if (io_status->u.Status)
482         {
483             wine_server_release_fd( hFile, unix_handle );
484             return io_status->u.Status;
485         }
486     }
487
488     if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
489     {
490         async_fileio*   fileio;
491         NTSTATUS ret;
492
493         if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
494         {
495             wine_server_release_fd( hFile, unix_handle );
496             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
497             return STATUS_NO_MEMORY;
498         }
499         fileio->handle = hFile;
500         fileio->count = length;
501         if ( offset == NULL ) 
502             fileio->offset = 0;
503         else
504         {
505             fileio->offset = offset->QuadPart;
506             if (offset->u.HighPart && fileio->offset == offset->u.LowPart)
507                 FIXME("High part of offset is lost\n");
508         } 
509         fileio->apc = apc;
510         fileio->apc_user = apc_user;
511         fileio->buffer = buffer;
512         fileio->queue_apc_on_error = 0;
513         fileio->avail_mode = (flags & FD_FLAG_AVAILABLE);
514         fileio->fd = unix_handle;  /* FIXME */
515         fileio->event = hEvent;
516         NtResetEvent(hEvent, NULL);
517
518         io_status->u.Status = STATUS_PENDING;
519         ret = fileio_queue_async(fileio, io_status, TRUE);
520         if (ret != STATUS_SUCCESS)
521         {
522             wine_server_release_fd( hFile, unix_handle );
523             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
524             RtlFreeHeap(GetProcessHeap(), 0, fileio);
525             return ret;
526         }
527         if (flags & FD_FLAG_TIMEOUT)
528         {
529             ret = NtWaitForSingleObject(hEvent, TRUE, NULL);
530             NtClose(hEvent);
531             if (ret != STATUS_USER_APC)
532                 fileio->queue_apc_on_error = 1;
533         }
534         else
535         {
536             LARGE_INTEGER   timeout;
537
538             /* let some APC be run, this will read some already pending data */
539             timeout.u.LowPart = timeout.u.HighPart = 0;
540             ret = NtDelayExecution( TRUE, &timeout );
541             /* the apc didn't run and therefore the completion routine now
542              * needs to be sent errors.
543              * Note that there is no race between setting this flag and
544              * returning errors because apc's are run only during alertable
545              * waits */
546             if (ret != STATUS_USER_APC)
547                 fileio->queue_apc_on_error = 1;
548         }
549         TRACE("= 0x%08lx\n", io_status->u.Status);
550         return io_status->u.Status;
551     }
552
553     if (offset)
554     {
555         FILE_POSITION_INFORMATION   fpi;
556
557         fpi.CurrentByteOffset = *offset;
558         io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi), 
559                                                    FilePositionInformation);
560         if (io_status->u.Status)
561         {
562             wine_server_release_fd( hFile, unix_handle );
563             return io_status->u.Status;
564         }
565     }
566     /* code for synchronous reads */
567     while ((io_status->Information = read( unix_handle, buffer, length )) == -1)
568     {
569         if ((errno == EAGAIN) || (errno == EINTR)) continue;
570         if (errno == EFAULT)
571         {
572             io_status->Information = 0;
573             io_status->u.Status = STATUS_ACCESS_VIOLATION;
574         }
575         else io_status->u.Status = FILE_GetNtStatus();
576         break;
577     }
578     wine_server_release_fd( hFile, unix_handle );
579     TRACE("= 0x%08lx\n", io_status->u.Status);
580     return io_status->u.Status;
581 }
582
583 /***********************************************************************
584  *             FILE_AsyncWriteService      (INTERNAL)
585  *
586  *  This function is called while the client is waiting on the
587  *  server, so we can't make any server calls here.
588  */
589 static void WINAPI FILE_AsyncWriteService(void *ovp, IO_STATUS_BLOCK *iosb, ULONG status)
590 {
591     async_fileio *fileio = (async_fileio *) ovp;
592     int result;
593     int already = iosb->Information;
594
595     TRACE("(%p %p %lu)\n",iosb, fileio->buffer, status);
596
597     switch (status)
598     {
599     case STATUS_ALERTED:
600         /* write some data (non-blocking) */
601         if ( fileio->avail_mode )
602             result = write(fileio->fd, &fileio->buffer[already], 
603                            fileio->count - already);
604         else
605         {
606             result = pwrite(fileio->fd, &fileio->buffer[already], 
607                             fileio->count - already, fileio->offset + already);
608             if ((result < 0) && (errno == ESPIPE))
609                 result = write(fileio->fd, &fileio->buffer[already], 
610                                fileio->count - already);
611         }
612
613         if (result < 0)
614         {
615             if (errno == EAGAIN || errno == EINTR) iosb->u.Status = STATUS_PENDING;
616             else iosb->u.Status = FILE_GetNtStatus();
617         }
618         else
619         {
620             iosb->Information += result;
621             iosb->u.Status = (iosb->Information < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
622             TRACE("wrote %d more bytes %ld/%d so far\n", 
623                   result, iosb->Information, fileio->count);
624         }
625         if (iosb->u.Status == STATUS_PENDING)
626             fileio_queue_async(fileio, iosb, FALSE);
627         break;
628     default:
629         iosb->u.Status = status;
630         fileio_terminate(fileio, iosb);
631         break;
632     }
633 }
634
635 /******************************************************************************
636  *  NtWriteFile                                 [NTDLL.@]
637  *  ZwWriteFile                                 [NTDLL.@]
638  *
639  * Write to an open file handle.
640  *
641  * PARAMS
642  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
643  *  Event         [I] Event to signal upon completion (or NULL)
644  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
645  *  ApcContext    [I] Context for ApcRoutine (or NULL)
646  *  IoStatusBlock [O] Receives information about the operation on return
647  *  Buffer        [I] Source for the data to write
648  *  Length        [I] Size of Buffer
649  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
650  *  Key           [O] Function unknown (may be NULL)
651  *
652  * RETURNS
653  *  Success: 0. IoStatusBlock is updated, and the Information member contains
654  *           The number of bytes written.
655  *  Failure: An NTSTATUS error code describing the error.
656  */
657 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
658                             PIO_APC_ROUTINE apc, void* apc_user,
659                             PIO_STATUS_BLOCK io_status, 
660                             const void* buffer, ULONG length,
661                             PLARGE_INTEGER offset, PULONG key)
662 {
663     int unix_handle, flags;
664
665     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p)!\n",
666           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
667
668     io_status->Information = 0;
669     io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_WRITE, &unix_handle, &flags );
670     if (io_status->u.Status) return io_status->u.Status;
671
672     if (flags & FD_FLAG_SEND_SHUTDOWN)
673     {
674         wine_server_release_fd( hFile, unix_handle );
675         return STATUS_PIPE_DISCONNECTED;
676     }
677
678     if (flags & FD_FLAG_TIMEOUT)
679     {
680         if (hEvent)
681         {
682             /* this shouldn't happen, but check it */
683             FIXME("NIY-hEvent\n");
684             wine_server_release_fd( hFile, unix_handle );
685             return STATUS_NOT_IMPLEMENTED;
686         }
687         io_status->u.Status = NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, NULL, 0, 0);
688         if (io_status->u.Status)
689         {
690             wine_server_release_fd( hFile, unix_handle );
691             return io_status->u.Status;
692         }
693     }
694
695     if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
696     {
697         async_fileio*   fileio;
698         NTSTATUS ret;
699
700         if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
701         {
702             wine_server_release_fd( hFile, unix_handle );
703             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
704             return STATUS_NO_MEMORY;
705         }
706         fileio->handle = hFile;
707         fileio->count = length;
708         if (offset)
709         {
710             fileio->offset = offset->QuadPart;
711             if (offset->u.HighPart && fileio->offset == offset->u.LowPart)
712                 FIXME("High part of offset is lost\n");
713         }
714         else  
715         {
716             fileio->offset = 0;
717         }
718         fileio->apc = apc;
719         fileio->apc_user = apc_user;
720         fileio->buffer = (void*)buffer;
721         fileio->queue_apc_on_error = 0;
722         fileio->avail_mode = (flags & FD_FLAG_AVAILABLE);
723         fileio->fd = unix_handle;  /* FIXME */
724         fileio->event = hEvent;
725         NtResetEvent(hEvent, NULL);
726
727         io_status->Information = 0;
728         io_status->u.Status = STATUS_PENDING;
729         ret = fileio_queue_async(fileio, io_status, FALSE);
730         if (ret != STATUS_SUCCESS)
731         {
732             wine_server_release_fd( hFile, unix_handle );
733             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
734             RtlFreeHeap(GetProcessHeap(), 0, fileio);
735             return ret;
736         }
737         if (flags & FD_FLAG_TIMEOUT)
738         {
739             ret = NtWaitForSingleObject(hEvent, TRUE, NULL);
740             NtClose(hEvent);
741             if (ret != STATUS_USER_APC)
742                 fileio->queue_apc_on_error = 1;
743         }
744         else
745         {
746             LARGE_INTEGER   timeout;
747
748             /* let some APC be run, this will write as much data as possible */
749             timeout.u.LowPart = timeout.u.HighPart = 0;
750             ret = NtDelayExecution( TRUE, &timeout );
751             /* the apc didn't run and therefore the completion routine now
752              * needs to be sent errors.
753              * Note that there is no race between setting this flag and
754              * returning errors because apc's are run only during alertable
755              * waits */
756             if (ret != STATUS_USER_APC)
757                 fileio->queue_apc_on_error = 1;
758         }
759         return io_status->u.Status;
760     }
761
762     if (offset)
763     {
764         FILE_POSITION_INFORMATION   fpi;
765
766         fpi.CurrentByteOffset = *offset;
767         io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi),
768                                                    FilePositionInformation);
769         if (io_status->u.Status)
770         {
771             wine_server_release_fd( hFile, unix_handle );
772             return io_status->u.Status;
773         }
774     }
775
776     /* synchronous file write */
777     while ((io_status->Information = write( unix_handle, buffer, length )) == -1)
778     {
779         if ((errno == EAGAIN) || (errno == EINTR)) continue;
780         if (errno == EFAULT)
781         {
782             io_status->Information = 0;
783             io_status->u.Status = STATUS_INVALID_USER_BUFFER;
784         }
785         else if (errno == ENOSPC) io_status->u.Status = STATUS_DISK_FULL;
786         else io_status->u.Status = FILE_GetNtStatus();
787         break;
788     }
789     wine_server_release_fd( hFile, unix_handle );
790     return io_status->u.Status;
791 }
792
793 /**************************************************************************
794  *              NtDeviceIoControlFile                   [NTDLL.@]
795  *              ZwDeviceIoControlFile                   [NTDLL.@]
796  *
797  * Perform an I/O control operation on an open file handle.
798  *
799  * PARAMS
800  *  DeviceHandle     [I] Handle returned from ZwOpenFile() or ZwCreateFile()
801  *  Event            [I] Event to signal upon completion (or NULL)
802  *  ApcRoutine       [I] Callback to call upon completion (or NULL)
803  *  ApcContext       [I] Context for ApcRoutine (or NULL)
804  *  IoStatusBlock    [O] Receives information about the operation on return
805  *  IoControlCode    [I] Control code for the operation to perform
806  *  InputBuffer      [I] Source for any input data required (or NULL)
807  *  InputBufferSize  [I] Size of InputBuffer
808  *  OutputBuffer     [O] Source for any output data returned (or NULL)
809  *  OutputBufferSize [I] Size of OutputBuffer
810  *
811  * RETURNS
812  *  Success: 0. IoStatusBlock is updated.
813  *  Failure: An NTSTATUS error code describing the error.
814  */
815 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE DeviceHandle, HANDLE hEvent,
816                                       PIO_APC_ROUTINE UserApcRoutine, 
817                                       PVOID UserApcContext,
818                                       PIO_STATUS_BLOCK IoStatusBlock,
819                                       ULONG IoControlCode,
820                                       PVOID InputBuffer,
821                                       ULONG InputBufferSize,
822                                       PVOID OutputBuffer,
823                                       ULONG OutputBufferSize)
824 {
825     TRACE("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx)\n",
826           DeviceHandle, hEvent, UserApcRoutine, UserApcContext,
827           IoStatusBlock, IoControlCode, 
828           InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize);
829
830     if (CDROM_DeviceIoControl(DeviceHandle, hEvent,
831                               UserApcRoutine, UserApcContext,
832                               IoStatusBlock, IoControlCode,
833                               InputBuffer, InputBufferSize,
834                               OutputBuffer, OutputBufferSize) == STATUS_NO_SUCH_DEVICE)
835     {
836         /* it wasn't a CDROM */
837         FIXME("Unimplemented dwIoControlCode=%08lx\n", IoControlCode);
838         IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
839         IoStatusBlock->Information = 0;
840         if (hEvent) NtSetEvent(hEvent, NULL);
841     }
842     return IoStatusBlock->u.Status;
843 }
844
845 /******************************************************************************
846  * NtFsControlFile [NTDLL.@]
847  * ZwFsControlFile [NTDLL.@]
848  */
849 NTSTATUS WINAPI NtFsControlFile(
850         IN HANDLE DeviceHandle,
851         IN HANDLE Event OPTIONAL,
852         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
853         IN PVOID ApcContext OPTIONAL,
854         OUT PIO_STATUS_BLOCK IoStatusBlock,
855         IN ULONG IoControlCode,
856         IN PVOID InputBuffer,
857         IN ULONG InputBufferSize,
858         OUT PVOID OutputBuffer,
859         IN ULONG OutputBufferSize)
860 {
861         FIXME("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx): stub\n",
862         DeviceHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,IoControlCode,
863         InputBuffer,InputBufferSize,OutputBuffer,OutputBufferSize);
864         return 0;
865 }
866
867 /******************************************************************************
868  *  NtSetVolumeInformationFile          [NTDLL.@]
869  *  ZwSetVolumeInformationFile          [NTDLL.@]
870  *
871  * Set volume information for an open file handle.
872  *
873  * PARAMS
874  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
875  *  IoStatusBlock      [O] Receives information about the operation on return
876  *  FsInformation      [I] Source for volume information
877  *  Length             [I] Size of FsInformation
878  *  FsInformationClass [I] Type of volume information to set
879  *
880  * RETURNS
881  *  Success: 0. IoStatusBlock is updated.
882  *  Failure: An NTSTATUS error code describing the error.
883  */
884 NTSTATUS WINAPI NtSetVolumeInformationFile(
885         IN HANDLE FileHandle,
886         PIO_STATUS_BLOCK IoStatusBlock,
887         PVOID FsInformation,
888         ULONG Length,
889         FS_INFORMATION_CLASS FsInformationClass)
890 {
891         FIXME("(%p,%p,%p,0x%08lx,0x%08x) stub\n",
892         FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
893         return 0;
894 }
895
896 /******************************************************************************
897  *  NtQueryInformationFile              [NTDLL.@]
898  *  ZwQueryInformationFile              [NTDLL.@]
899  *
900  * Get information about an open file handle.
901  *
902  * PARAMS
903  *  hFile    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
904  *  io       [O] Receives information about the operation on return
905  *  ptr      [O] Destination for file information
906  *  len      [I] Size of FileInformation
907  *  class    [I] Type of file information to get
908  *
909  * RETURNS
910  *  Success: 0. IoStatusBlock and FileInformation are updated.
911  *  Failure: An NTSTATUS error code describing the error.
912  */
913 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
914                                         PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
915 {
916     static const size_t info_sizes[] =
917     {
918         0,
919         sizeof(FILE_DIRECTORY_INFORMATION),            /* FileDirectoryInformation */
920         sizeof(FILE_FULL_DIRECTORY_INFORMATION),       /* FileFullDirectoryInformation */
921         sizeof(FILE_BOTH_DIRECTORY_INFORMATION),       /* FileBothDirectoryInformation */
922         sizeof(FILE_BASIC_INFORMATION),                /* FileBasicInformation */
923         sizeof(FILE_STANDARD_INFORMATION),             /* FileStandardInformation */
924         sizeof(FILE_INTERNAL_INFORMATION),             /* FileInternalInformation */
925         sizeof(FILE_EA_INFORMATION),                   /* FileEaInformation */
926         sizeof(FILE_ACCESS_INFORMATION),               /* FileAccessInformation */
927         sizeof(FILE_NAME_INFORMATION)-sizeof(WCHAR),   /* FileNameInformation */
928         sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
929         0,                                             /* FileLinkInformation */
930         sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR),  /* FileNamesInformation */
931         sizeof(FILE_DISPOSITION_INFORMATION),          /* FileDispositionInformation */
932         sizeof(FILE_POSITION_INFORMATION),             /* FilePositionInformation */
933         sizeof(FILE_FULL_EA_INFORMATION),              /* FileFullEaInformation */
934         sizeof(FILE_MODE_INFORMATION),                 /* FileModeInformation */
935         sizeof(FILE_ALIGNMENT_INFORMATION),            /* FileAlignmentInformation */
936         sizeof(FILE_ALL_INFORMATION)-sizeof(WCHAR),    /* FileAllInformation */
937         sizeof(FILE_ALLOCATION_INFORMATION),           /* FileAllocationInformation */
938         sizeof(FILE_END_OF_FILE_INFORMATION),          /* FileEndOfFileInformation */
939         0,                                             /* FileAlternateNameInformation */
940         sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
941         0,                                             /* FilePipeInformation */
942         0,                                             /* FilePipeLocalInformation */
943         0,                                             /* FilePipeRemoteInformation */
944         sizeof(FILE_MAILSLOT_QUERY_INFORMATION),       /* FileMailslotQueryInformation */
945         0,                                             /* FileMailslotSetInformation */
946         0,                                             /* FileCompressionInformation */
947         0,                                             /* FileObjectIdInformation */
948         0,                                             /* FileCompletionInformation */
949         0,                                             /* FileMoveClusterInformation */
950         0,                                             /* FileQuotaInformation */
951         0,                                             /* FileReparsePointInformation */
952         0,                                             /* FileNetworkOpenInformation */
953         0,                                             /* FileAttributeTagInformation */
954         0                                              /* FileTrackingInformation */
955     };
956
957     struct stat st;
958     int fd;
959
960     TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", hFile, io, ptr, len, class);
961
962     io->Information = 0;
963
964     if (class <= 0 || class >= FileMaximumInformation)
965         return io->u.Status = STATUS_INVALID_INFO_CLASS;
966     if (!info_sizes[class])
967     {
968         FIXME("Unsupported class (%d)\n", class);
969         return io->u.Status = STATUS_NOT_IMPLEMENTED;
970     }
971     if (len < info_sizes[class])
972         return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
973
974     if ((io->u.Status = wine_server_handle_to_fd( hFile, 0, &fd, NULL )))
975         return io->u.Status;
976
977     switch (class)
978     {
979     case FileBasicInformation:
980         {
981             FILE_BASIC_INFORMATION *info = ptr;
982
983             if (fstat( fd, &st ) == -1)
984                 io->u.Status = FILE_GetNtStatus();
985             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
986                 io->u.Status = STATUS_INVALID_INFO_CLASS;
987             else
988             {
989                 if (S_ISDIR(st.st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
990                 else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
991                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
992                     info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
993                 RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime);
994                 RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime);
995                 RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime);
996                 RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime);
997             }
998         }
999         break;
1000     case FileStandardInformation:
1001         {
1002             FILE_STANDARD_INFORMATION *info = ptr;
1003
1004             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1005             else
1006             {
1007                 if ((info->Directory = S_ISDIR(st.st_mode)))
1008                 {
1009                     info->AllocationSize.QuadPart = 0;
1010                     info->EndOfFile.QuadPart      = 0;
1011                     info->NumberOfLinks           = 1;
1012                     info->DeletePending           = FALSE;
1013                 }
1014                 else
1015                 {
1016                     info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1017                     info->EndOfFile.QuadPart      = st.st_size;
1018                     info->NumberOfLinks           = st.st_nlink;
1019                     info->DeletePending           = FALSE; /* FIXME */
1020                 }
1021             }
1022         }
1023         break;
1024     case FilePositionInformation:
1025         {
1026             FILE_POSITION_INFORMATION *info = ptr;
1027             off_t res = lseek( fd, 0, SEEK_CUR );
1028             if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
1029             else info->CurrentByteOffset.QuadPart = res;
1030         }
1031         break;
1032     case FileInternalInformation:
1033         {
1034             FILE_INTERNAL_INFORMATION *info = ptr;
1035
1036             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1037             else info->IndexNumber.QuadPart = st.st_ino;
1038         }
1039         break;
1040     case FileEaInformation:
1041         {
1042             FILE_EA_INFORMATION *info = ptr;
1043             info->EaSize = 0;
1044         }
1045         break;
1046     case FileEndOfFileInformation:
1047         {
1048             FILE_END_OF_FILE_INFORMATION *info = ptr;
1049
1050             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1051             else info->EndOfFile.QuadPart = S_ISDIR(st.st_mode) ? 0 : st.st_size;
1052         }
1053         break;
1054     case FileAllInformation:
1055         {
1056             FILE_ALL_INFORMATION *info = ptr;
1057
1058             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1059             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1060                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1061             else
1062             {
1063                 if ((info->StandardInformation.Directory = S_ISDIR(st.st_mode)))
1064                 {
1065                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1066                     info->StandardInformation.AllocationSize.QuadPart = 0;
1067                     info->StandardInformation.EndOfFile.QuadPart      = 0;
1068                     info->StandardInformation.NumberOfLinks           = 1;
1069                     info->StandardInformation.DeletePending           = FALSE;
1070                 }
1071                 else
1072                 {
1073                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1074                     info->StandardInformation.AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1075                     info->StandardInformation.EndOfFile.QuadPart      = st.st_size;
1076                     info->StandardInformation.NumberOfLinks           = st.st_nlink;
1077                     info->StandardInformation.DeletePending           = FALSE; /* FIXME */
1078                 }
1079                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1080                     info->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_READONLY;
1081                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.CreationTime);
1082                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.LastWriteTime);
1083                 RtlSecondsSince1970ToTime( st.st_ctime, &info->BasicInformation.ChangeTime);
1084                 RtlSecondsSince1970ToTime( st.st_atime, &info->BasicInformation.LastAccessTime);
1085                 info->InternalInformation.IndexNumber.QuadPart = st.st_ino;
1086                 info->EaInformation.EaSize = 0;
1087                 info->AccessInformation.AccessFlags = 0;  /* FIXME */
1088                 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
1089                 info->ModeInformation.Mode = 0;  /* FIXME */
1090                 info->AlignmentInformation.AlignmentRequirement = 1;  /* FIXME */
1091                 info->NameInformation.FileNameLength = 0;
1092                 io->Information = sizeof(*info) - sizeof(WCHAR);
1093             }
1094         }
1095         break;
1096     case FileMailslotQueryInformation:
1097         {
1098             FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
1099
1100             SERVER_START_REQ( set_mailslot_info )
1101             {
1102                 req->handle = hFile;
1103                 req->flags = 0;
1104                 io->u.Status = wine_server_call( req );
1105                 if( io->u.Status == STATUS_SUCCESS )
1106                 {
1107                     info->MaximumMessageSize = reply->max_msgsize;
1108                     info->MailslotQuota = 0;
1109                     info->NextMessageSize = reply->next_msgsize;
1110                     info->MessagesAvailable = reply->msg_count;
1111                     info->ReadTimeout.QuadPart = reply->read_timeout * -10000;
1112                 }
1113             }
1114             SERVER_END_REQ;
1115         }
1116         break;
1117     default:
1118         FIXME("Unsupported class (%d)\n", class);
1119         io->u.Status = STATUS_NOT_IMPLEMENTED;
1120         break;
1121     }
1122     wine_server_release_fd( hFile, fd );
1123     if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
1124     return io->u.Status;
1125 }
1126
1127 /******************************************************************************
1128  *  NtSetInformationFile                [NTDLL.@]
1129  *  ZwSetInformationFile                [NTDLL.@]
1130  *
1131  * Set information about an open file handle.
1132  *
1133  * PARAMS
1134  *  handle  [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1135  *  io      [O] Receives information about the operation on return
1136  *  ptr     [I] Source for file information
1137  *  len     [I] Size of FileInformation
1138  *  class   [I] Type of file information to set
1139  *
1140  * RETURNS
1141  *  Success: 0. io is updated.
1142  *  Failure: An NTSTATUS error code describing the error.
1143  */
1144 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
1145                                      PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
1146 {
1147     int fd;
1148
1149     TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", handle, io, ptr, len, class);
1150
1151     if ((io->u.Status = wine_server_handle_to_fd( handle, 0, &fd, NULL )))
1152         return io->u.Status;
1153
1154     io->u.Status = STATUS_SUCCESS;
1155     switch (class)
1156     {
1157     case FileBasicInformation:
1158         if (len >= sizeof(FILE_BASIC_INFORMATION))
1159         {
1160             struct stat st;
1161             const FILE_BASIC_INFORMATION *info = ptr;
1162
1163             if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
1164             {
1165                 ULONGLONG sec, nsec;
1166                 struct timeval tv[2];
1167
1168                 if (!info->LastAccessTime.QuadPart || !info->LastWriteTime.QuadPart)
1169                 {
1170
1171                     tv[0].tv_sec = tv[0].tv_usec = 0;
1172                     tv[1].tv_sec = tv[1].tv_usec = 0;
1173                     if (!fstat( fd, &st ))
1174                     {
1175                         tv[0].tv_sec = st.st_atime;
1176                         tv[1].tv_sec = st.st_mtime;
1177                     }
1178                 }
1179                 if (info->LastAccessTime.QuadPart)
1180                 {
1181                     sec = RtlLargeIntegerDivide( info->LastAccessTime.QuadPart, 10000000, &nsec );
1182                     tv[0].tv_sec = sec - SECS_1601_TO_1970;
1183                     tv[0].tv_usec = (UINT)nsec / 10;
1184                 }
1185                 if (info->LastWriteTime.QuadPart)
1186                 {
1187                     sec = RtlLargeIntegerDivide( info->LastWriteTime.QuadPart, 10000000, &nsec );
1188                     tv[1].tv_sec = sec - SECS_1601_TO_1970;
1189                     tv[1].tv_usec = (UINT)nsec / 10;
1190                 }
1191                 if (futimes( fd, tv ) == -1) io->u.Status = FILE_GetNtStatus();
1192             }
1193
1194             if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
1195             {
1196                 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1197                 else
1198                 {
1199                     if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
1200                     {
1201                         if (S_ISDIR( st.st_mode))
1202                             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
1203                         else
1204                             st.st_mode &= ~0222; /* clear write permission bits */
1205                     }
1206                     else
1207                     {
1208                         /* add write permission only where we already have read permission */
1209                         st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
1210                     }
1211                     if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
1212                 }
1213             }
1214         }
1215         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1216         break;
1217
1218     case FilePositionInformation:
1219         if (len >= sizeof(FILE_POSITION_INFORMATION))
1220         {
1221             const FILE_POSITION_INFORMATION *info = ptr;
1222
1223             if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
1224                 io->u.Status = FILE_GetNtStatus();
1225         }
1226         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1227         break;
1228
1229     case FileEndOfFileInformation:
1230         if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
1231         {
1232             struct stat st;
1233             const FILE_END_OF_FILE_INFORMATION *info = ptr;
1234
1235             /* first try normal truncate */
1236             if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1237
1238             /* now check for the need to extend the file */
1239             if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
1240             {
1241                 static const char zero;
1242
1243                 /* extend the file one byte beyond the requested size and then truncate it */
1244                 /* this should work around ftruncate implementations that can't extend files */
1245                 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
1246                     ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1247             }
1248             io->u.Status = FILE_GetNtStatus();
1249         }
1250         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1251         break;
1252
1253     case FileMailslotSetInformation:
1254         {
1255             FILE_MAILSLOT_SET_INFORMATION *info = ptr;
1256
1257             SERVER_START_REQ( set_mailslot_info )
1258             {
1259                 req->handle = handle;
1260                 req->flags = MAILSLOT_SET_READ_TIMEOUT;
1261                 req->read_timeout = info->ReadTimeout.QuadPart / -10000;
1262                 io->u.Status = wine_server_call( req );
1263             }
1264             SERVER_END_REQ;
1265         }
1266         break;
1267
1268     default:
1269         FIXME("Unsupported class (%d)\n", class);
1270         io->u.Status = STATUS_NOT_IMPLEMENTED;
1271         break;
1272     }
1273     wine_server_release_fd( handle, fd );
1274     io->Information = 0;
1275     return io->u.Status;
1276 }
1277
1278
1279 /******************************************************************************
1280  *              NtQueryFullAttributesFile   (NTDLL.@)
1281  */
1282 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
1283                                            FILE_NETWORK_OPEN_INFORMATION *info )
1284 {
1285     ANSI_STRING unix_name;
1286     NTSTATUS status;
1287
1288     if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN,
1289                                               !(attr->Attributes & OBJ_CASE_INSENSITIVE) )))
1290     {
1291         struct stat st;
1292
1293         if (stat( unix_name.Buffer, &st ) == -1)
1294             status = FILE_GetNtStatus();
1295         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1296             status = STATUS_INVALID_INFO_CLASS;
1297         else
1298         {
1299             if (S_ISDIR(st.st_mode))
1300             {
1301                 info->FileAttributes          = FILE_ATTRIBUTE_DIRECTORY;
1302                 info->AllocationSize.QuadPart = 0;
1303                 info->EndOfFile.QuadPart      = 0;
1304             }
1305             else
1306             {
1307                 info->FileAttributes          = FILE_ATTRIBUTE_ARCHIVE;
1308                 info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1309                 info->EndOfFile.QuadPart      = st.st_size;
1310             }
1311             if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1312                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1313             RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime );
1314             RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime );
1315             RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime );
1316             RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime );
1317             if (DIR_is_hidden_file( attr->ObjectName ))
1318                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1319         }
1320         RtlFreeAnsiString( &unix_name );
1321     }
1322     else WARN("%s not found (%lx)\n", debugstr_us(attr->ObjectName), status );
1323     return status;
1324 }
1325
1326
1327 /******************************************************************************
1328  *              NtQueryAttributesFile   (NTDLL.@)
1329  *              ZwQueryAttributesFile   (NTDLL.@)
1330  */
1331 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
1332 {
1333     FILE_NETWORK_OPEN_INFORMATION full_info;
1334     NTSTATUS status;
1335
1336     if (!(status = NtQueryFullAttributesFile( attr, &full_info )))
1337     {
1338         info->CreationTime.QuadPart   = full_info.CreationTime.QuadPart;
1339         info->LastAccessTime.QuadPart = full_info.LastAccessTime.QuadPart;
1340         info->LastWriteTime.QuadPart  = full_info.LastWriteTime.QuadPart;
1341         info->ChangeTime.QuadPart     = full_info.ChangeTime.QuadPart;
1342         info->FileAttributes          = full_info.FileAttributes;
1343     }
1344     return status;
1345 }
1346
1347
1348 /******************************************************************************
1349  *  NtQueryVolumeInformationFile                [NTDLL.@]
1350  *  ZwQueryVolumeInformationFile                [NTDLL.@]
1351  *
1352  * Get volume information for an open file handle.
1353  *
1354  * PARAMS
1355  *  handle      [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1356  *  io          [O] Receives information about the operation on return
1357  *  buffer      [O] Destination for volume information
1358  *  length      [I] Size of FsInformation
1359  *  info_class  [I] Type of volume information to set
1360  *
1361  * RETURNS
1362  *  Success: 0. io and buffer are updated.
1363  *  Failure: An NTSTATUS error code describing the error.
1364  */
1365 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
1366                                               PVOID buffer, ULONG length,
1367                                               FS_INFORMATION_CLASS info_class )
1368 {
1369     int fd;
1370     struct stat st;
1371
1372     if ((io->u.Status = wine_server_handle_to_fd( handle, 0, &fd, NULL )) != STATUS_SUCCESS)
1373         return io->u.Status;
1374
1375     io->u.Status = STATUS_NOT_IMPLEMENTED;
1376     io->Information = 0;
1377
1378     switch( info_class )
1379     {
1380     case FileFsVolumeInformation:
1381         FIXME( "%p: volume info not supported\n", handle );
1382         break;
1383     case FileFsLabelInformation:
1384         FIXME( "%p: label info not supported\n", handle );
1385         break;
1386     case FileFsSizeInformation:
1387         if (length < sizeof(FILE_FS_SIZE_INFORMATION))
1388             io->u.Status = STATUS_BUFFER_TOO_SMALL;
1389         else
1390         {
1391             FILE_FS_SIZE_INFORMATION *info = buffer;
1392
1393             if (fstat( fd, &st ) < 0)
1394             {
1395                 io->u.Status = FILE_GetNtStatus();
1396                 break;
1397             }
1398             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1399             {
1400                 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
1401             }
1402             else
1403             {
1404                 /* Linux's fstatvfs is buggy */
1405 #if !defined(linux) || !defined(HAVE_FSTATFS)
1406                 struct statvfs stfs;
1407
1408                 if (fstatvfs( fd, &stfs ) < 0)
1409                 {
1410                     io->u.Status = FILE_GetNtStatus();
1411                     break;
1412                 }
1413                 info->BytesPerSector = stfs.f_frsize;
1414 #else
1415                 struct statfs stfs;
1416                 if (fstatfs( fd, &stfs ) < 0)
1417                 {
1418                     io->u.Status = FILE_GetNtStatus();
1419                     break;
1420                 }
1421                 info->BytesPerSector = stfs.f_bsize;
1422 #endif
1423                 info->TotalAllocationUnits.QuadPart = stfs.f_blocks;
1424                 info->AvailableAllocationUnits.QuadPart = stfs.f_bavail;
1425                 info->SectorsPerAllocationUnit = 1;
1426                 io->Information = sizeof(*info);
1427                 io->u.Status = STATUS_SUCCESS;
1428             }
1429         }
1430         break;
1431     case FileFsDeviceInformation:
1432         if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
1433             io->u.Status = STATUS_BUFFER_TOO_SMALL;
1434         else
1435         {
1436             FILE_FS_DEVICE_INFORMATION *info = buffer;
1437
1438             info->Characteristics = 0;
1439             if (fstat( fd, &st ) < 0)
1440             {
1441                 io->u.Status = FILE_GetNtStatus();
1442                 break;
1443             }
1444             if (S_ISCHR( st.st_mode ))
1445             {
1446                 info->DeviceType = FILE_DEVICE_UNKNOWN;
1447 #ifdef linux
1448                 switch(major(st.st_rdev))
1449                 {
1450                 case MEM_MAJOR:
1451                     info->DeviceType = FILE_DEVICE_NULL;
1452                     break;
1453                 case TTY_MAJOR:
1454                     info->DeviceType = FILE_DEVICE_SERIAL_PORT;
1455                     break;
1456                 case LP_MAJOR:
1457                     info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
1458                     break;
1459                 }
1460 #endif
1461             }
1462             else if (S_ISBLK( st.st_mode ))
1463             {
1464                 info->DeviceType = FILE_DEVICE_DISK;
1465             }
1466             else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
1467             {
1468                 info->DeviceType = FILE_DEVICE_NAMED_PIPE;
1469             }
1470             else  /* regular file or directory */
1471             {
1472 #if defined(linux) && defined(HAVE_FSTATFS)
1473                 struct statfs stfs;
1474
1475                 /* check for floppy disk */
1476                 if (major(st.st_dev) == FLOPPY_MAJOR)
1477                     info->Characteristics |= FILE_REMOVABLE_MEDIA;
1478
1479                 if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
1480                 switch (stfs.f_type)
1481                 {
1482                 case 0x9660:      /* iso9660 */
1483                 case 0x15013346:  /* udf */
1484                     info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
1485                     info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
1486                     break;
1487                 case 0x6969:  /* nfs */
1488                 case 0x517B:  /* smbfs */
1489                 case 0x564c:  /* ncpfs */
1490                     info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
1491                     info->Characteristics |= FILE_REMOTE_DEVICE;
1492                     break;
1493                 case 0x01021994:  /* tmpfs */
1494                 case 0x28cd3d45:  /* cramfs */
1495                 case 0x1373:      /* devfs */
1496                 case 0x9fa0:      /* procfs */
1497                     info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
1498                     break;
1499                 default:
1500                     info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1501                     break;
1502                 }
1503 #elif defined (__APPLE__)
1504 # include <IOKit/IOKitLib.h>
1505 # include <CoreFoundation/CFNumber.h> /* for kCFBooleanTrue, kCFBooleanFalse */
1506 # include <paths.h>
1507                 struct statfs stfs;
1508                 
1509                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1510                 
1511                 if (fstatfs( fd, &stfs ) < 0) break;
1512
1513                 /* stfs.f_type is reserved (always set to 0) so use IOKit */
1514                 kern_return_t kernResult = KERN_FAILURE; 
1515                 mach_port_t masterPort;
1516                 
1517                 char bsdName[6]; /* disk#\0 */
1518                 
1519                 strncpy(bsdName, stfs.f_mntfromname+strlen(_PATH_DEV) , 5);
1520                 bsdName[5] = 0;
1521
1522                 kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
1523
1524                 if (kernResult == KERN_SUCCESS)
1525                 {
1526                     CFMutableDictionaryRef matching = IOBSDNameMatching(masterPort, 0, bsdName);
1527                     
1528                     if (matching)
1529                     {
1530                         CFMutableDictionaryRef properties;
1531                         io_service_t devService = IOServiceGetMatchingService(masterPort, matching);
1532                         
1533                         if (IORegistryEntryCreateCFProperties(devService, 
1534                                                                 &properties,
1535                                                                 kCFAllocatorDefault, 0) != KERN_SUCCESS)
1536                                                                     break;
1537                         if ( CFEqual(
1538                                         CFDictionaryGetValue(properties, CFSTR("Removable")),
1539                                         kCFBooleanTrue)
1540                             ) info->Characteristics |= FILE_REMOVABLE_MEDIA;
1541                             
1542                         if ( CFEqual(
1543                                         CFDictionaryGetValue(properties, CFSTR("Writable")),
1544                                         kCFBooleanFalse)
1545                             ) info->Characteristics |= FILE_READ_ONLY_DEVICE;
1546
1547                         /*
1548                             NB : mounted disk image (.img/.dmg) don't provide specific type
1549                         */
1550                         CFStringRef type;
1551                         if ( (type = CFDictionaryGetValue(properties, CFSTR("Type"))) )
1552                         {
1553                             if ( CFStringCompare(type, CFSTR("CD-ROM"), 0) == kCFCompareEqualTo
1554                                 || CFStringCompare(type, CFSTR("DVD-ROM"), 0) == kCFCompareEqualTo
1555                             )
1556                             {
1557                                 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
1558                             }
1559                         } 
1560                         
1561                         if (properties)
1562                             CFRelease(properties);
1563                     }
1564                 }
1565 #else
1566                 static int warned;
1567                 if (!warned++) FIXME( "device info not properly supported on this platform\n" );
1568                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1569 #endif
1570                 info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
1571             }
1572             io->Information = sizeof(*info);
1573             io->u.Status = STATUS_SUCCESS;
1574         }
1575         break;
1576     case FileFsAttributeInformation:
1577         FIXME( "%p: attribute info not supported\n", handle );
1578         break;
1579     case FileFsControlInformation:
1580         FIXME( "%p: control info not supported\n", handle );
1581         break;
1582     case FileFsFullSizeInformation:
1583         FIXME( "%p: full size info not supported\n", handle );
1584         break;
1585     case FileFsObjectIdInformation:
1586         FIXME( "%p: object id info not supported\n", handle );
1587         break;
1588     case FileFsMaximumInformation:
1589         FIXME( "%p: maximum info not supported\n", handle );
1590         break;
1591     default:
1592         io->u.Status = STATUS_INVALID_PARAMETER;
1593         break;
1594     }
1595     wine_server_release_fd( handle, fd );
1596     return io->u.Status;
1597 }
1598
1599
1600 /******************************************************************
1601  *              NtFlushBuffersFile  (NTDLL.@)
1602  *
1603  * Flush any buffered data on an open file handle.
1604  *
1605  * PARAMS
1606  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1607  *  IoStatusBlock      [O] Receives information about the operation on return
1608  *
1609  * RETURNS
1610  *  Success: 0. IoStatusBlock is updated.
1611  *  Failure: An NTSTATUS error code describing the error.
1612  */
1613 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
1614 {
1615     NTSTATUS ret;
1616     HANDLE hEvent = NULL;
1617
1618     SERVER_START_REQ( flush_file )
1619     {
1620         req->handle = hFile;
1621         ret = wine_server_call( req );
1622         hEvent = reply->event;
1623     }
1624     SERVER_END_REQ;
1625     if (!ret && hEvent)
1626     {
1627         ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
1628         NtClose( hEvent );
1629     }
1630     return ret;
1631 }
1632
1633 /******************************************************************
1634  *              NtLockFile       (NTDLL.@)
1635  *
1636  *
1637  */
1638 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
1639                             PIO_APC_ROUTINE apc, void* apc_user,
1640                             PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
1641                             PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
1642                             BOOLEAN exclusive )
1643 {
1644     NTSTATUS    ret;
1645     HANDLE      handle;
1646     BOOLEAN     async;
1647
1648     if (apc || io_status || key)
1649     {
1650         FIXME("Unimplemented yet parameter\n");
1651         return STATUS_NOT_IMPLEMENTED;
1652     }
1653
1654     for (;;)
1655     {
1656         SERVER_START_REQ( lock_file )
1657         {
1658             req->handle      = hFile;
1659             req->offset_low  = offset->u.LowPart;
1660             req->offset_high = offset->u.HighPart;
1661             req->count_low   = count->u.LowPart;
1662             req->count_high  = count->u.HighPart;
1663             req->shared      = !exclusive;
1664             req->wait        = !dont_wait;
1665             ret = wine_server_call( req );
1666             handle = reply->handle;
1667             async  = reply->overlapped;
1668         }
1669         SERVER_END_REQ;
1670         if (ret != STATUS_PENDING)
1671         {
1672             if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
1673             return ret;
1674         }
1675
1676         if (async)
1677         {
1678             FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
1679             if (handle) NtClose( handle );
1680             return STATUS_PENDING;
1681         }
1682         if (handle)
1683         {
1684             NtWaitForSingleObject( handle, FALSE, NULL );
1685             NtClose( handle );
1686         }
1687         else
1688         {
1689             LARGE_INTEGER time;
1690     
1691             /* Unix lock conflict, sleep a bit and retry */
1692             time.QuadPart = 100 * (ULONGLONG)10000;
1693             time.QuadPart = -time.QuadPart;
1694             NtDelayExecution( FALSE, &time );
1695         }
1696     }
1697 }
1698
1699
1700 /******************************************************************
1701  *              NtUnlockFile    (NTDLL.@)
1702  *
1703  *
1704  */
1705 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
1706                               PLARGE_INTEGER offset, PLARGE_INTEGER count,
1707                               PULONG key )
1708 {
1709     NTSTATUS status;
1710
1711     TRACE( "%p %lx%08lx %lx%08lx\n",
1712            hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
1713
1714     if (io_status || key)
1715     {
1716         FIXME("Unimplemented yet parameter\n");
1717         return STATUS_NOT_IMPLEMENTED;
1718     }
1719
1720     SERVER_START_REQ( unlock_file )
1721     {
1722         req->handle      = hFile;
1723         req->offset_low  = offset->u.LowPart;
1724         req->offset_high = offset->u.HighPart;
1725         req->count_low   = count->u.LowPart;
1726         req->count_high  = count->u.HighPart;
1727         status = wine_server_call( req );
1728     }
1729     SERVER_END_REQ;
1730     return status;
1731 }
1732
1733 /******************************************************************
1734  *              NtCreateNamedPipeFile    (NTDLL.@)
1735  *
1736  *
1737  */
1738 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
1739                                        POBJECT_ATTRIBUTES oa, PIO_STATUS_BLOCK iosb,
1740                                        ULONG sharing, ULONG dispo, ULONG options,
1741                                        ULONG pipe_type, ULONG read_mode, 
1742                                        ULONG completion_mode, ULONG max_inst,
1743                                        ULONG inbound_quota, ULONG outbound_quota,
1744                                        PLARGE_INTEGER timeout)
1745 {
1746     NTSTATUS    status;
1747     static const WCHAR leadin[] = {'\\','?','?','\\','P','I','P','E','\\'};
1748
1749     TRACE("(%p %lx %p %p %lx %ld %lx %ld %ld %ld %ld %ld %ld %p): stub\n",
1750           handle, access, oa, iosb, sharing, dispo, options, pipe_type,
1751           read_mode, completion_mode, max_inst, inbound_quota, outbound_quota,
1752           timeout);
1753
1754     if (oa->ObjectName->Length < sizeof(leadin) ||
1755         strncmpiW( oa->ObjectName->Buffer, 
1756                    leadin, sizeof(leadin)/sizeof(leadin[0]) ))
1757         return STATUS_OBJECT_NAME_INVALID;
1758     /* assume we only get relative timeout, and storable in a DWORD as ms */
1759     if (timeout->QuadPart > 0 || (timeout->QuadPart / -10000) >> 32)
1760         FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
1761
1762     SERVER_START_REQ( create_named_pipe )
1763     {
1764         req->options = options; /* FIXME not used in server yet !!!! */
1765         req->flags = 
1766             (pipe_type) ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0 |
1767             (read_mode) ? NAMED_PIPE_MESSAGE_STREAM_READ  : 0 |
1768             (completion_mode) ? NAMED_PIPE_NONBLOCKING_MODE  : 0;
1769         req->maxinstances = max_inst;
1770         req->outsize = outbound_quota;
1771         req->insize  = inbound_quota;
1772         req->timeout = timeout->QuadPart / -10000;
1773         req->inherit = (oa->Attributes & OBJ_INHERIT) != 0;
1774         wine_server_add_data( req, oa->ObjectName->Buffer + 4, 
1775                               oa->ObjectName->Length - 4 * sizeof(WCHAR) );
1776         status = wine_server_call( req );
1777         if (!status) *handle = reply->handle;
1778     }
1779     SERVER_END_REQ;
1780     return status;
1781 }
1782
1783 /******************************************************************
1784  *              NtDeleteFile    (NTDLL.@)
1785  *
1786  *
1787  */
1788 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
1789 {
1790     NTSTATUS status;
1791     HANDLE hFile;
1792     IO_STATUS_BLOCK io;
1793
1794     TRACE("%p\n", ObjectAttributes);
1795     status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE, ObjectAttributes, 
1796                            &io, NULL, 0,
1797                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
1798                            FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
1799     if (status == STATUS_SUCCESS) status = NtClose(hFile);
1800     return status;
1801 }
1802
1803 /******************************************************************
1804  *              NtCancelIoFile    (NTDLL.@)
1805  *
1806  *
1807  */
1808 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
1809 {
1810     LARGE_INTEGER timeout;
1811
1812     TRACE("%p %p\n", hFile, io_status );
1813
1814     SERVER_START_REQ( cancel_async )
1815     {
1816         req->handle = hFile;
1817         wine_server_call( req );
1818     }
1819     SERVER_END_REQ;
1820     /* Let some APC be run, so that we can run the remaining APCs on hFile
1821      * either the cancelation of the pending one, but also the execution
1822      * of the queued APC, but not yet run. This is needed to ensure proper
1823      * clean-up of allocated data.
1824      */
1825     timeout.u.LowPart = timeout.u.HighPart = 0;
1826     return io_status->u.Status = NtDelayExecution( TRUE, &timeout );
1827 }
1828
1829 /******************************************************************************
1830  *  NtCreateMailslotFile        [NTDLL.@]
1831  *  ZwCreateMailslotFile        [NTDLL.@]
1832  *
1833  * PARAMS
1834  *  pHandle          [O] pointer to receive the handle created
1835  *  DesiredAccess    [I] access mode (read, write, etc)
1836  *  ObjectAttributes [I] fully qualified NT path of the mailslot
1837  *  IoStatusBlock    [O] receives completion status and other info
1838  *  CreateOptions    [I]
1839  *  MailslotQuota    [I]
1840  *  MaxMessageSize   [I]
1841  *  TimeOut          [I]
1842  *
1843  * RETURNS
1844  *  An NT status code
1845  */
1846 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
1847      POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
1848      ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
1849      PLARGE_INTEGER TimeOut)
1850 {
1851     static const WCHAR leadin[] = {
1852         '\\','?','?','\\','M','A','I','L','S','L','O','T','\\'};
1853     NTSTATUS ret;
1854
1855     TRACE("%p %08lx %p %p %08lx %08lx %08lx %p\n",
1856               pHandle, DesiredAccess, attr, IoStatusBlock,
1857               CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
1858
1859     if (attr->ObjectName->Length < sizeof(leadin) ||
1860         strncmpiW( attr->ObjectName->Buffer, 
1861                    leadin, sizeof(leadin)/sizeof(leadin[0]) ))
1862     {
1863         return STATUS_OBJECT_NAME_INVALID;
1864     }
1865
1866     SERVER_START_REQ( create_mailslot )
1867     {
1868         req->max_msgsize = MaxMessageSize;
1869         req->read_timeout = TimeOut->QuadPart / -10000;
1870         req->inherit = (attr->Attributes & OBJ_INHERIT) != 0;
1871         wine_server_add_data( req, attr->ObjectName->Buffer + 4,
1872                               attr->ObjectName->Length - 4*sizeof(WCHAR) );
1873         ret = wine_server_call( req );
1874         if( ret == STATUS_SUCCESS )
1875             *pHandle = reply->handle;
1876     }
1877     SERVER_END_REQ;
1878  
1879     return ret;
1880 }