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