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