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