wined3d: Add a missing return statement to surface_prepare_texture().
[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_SYS_FILIO_H
49 # include <sys/filio.h>
50 #endif
51 #ifdef HAVE_POLL_H
52 #include <poll.h>
53 #endif
54 #ifdef HAVE_SYS_POLL_H
55 #include <sys/poll.h>
56 #endif
57 #ifdef HAVE_SYS_SOCKET_H
58 #include <sys/socket.h>
59 #endif
60 #ifdef HAVE_UTIME_H
61 # include <utime.h>
62 #endif
63 #ifdef HAVE_SYS_VFS_H
64 # include <sys/vfs.h>
65 #endif
66 #ifdef HAVE_SYS_MOUNT_H
67 # include <sys/mount.h>
68 #endif
69 #ifdef HAVE_SYS_STATFS_H
70 # include <sys/statfs.h>
71 #endif
72 #ifdef HAVE_VALGRIND_MEMCHECK_H
73 # include <valgrind/memcheck.h>
74 #endif
75
76 #define NONAMELESSUNION
77 #define NONAMELESSSTRUCT
78 #include "ntstatus.h"
79 #define WIN32_NO_STATUS
80 #include "wine/unicode.h"
81 #include "wine/debug.h"
82 #include "wine/server.h"
83 #include "ntdll_misc.h"
84
85 #include "winternl.h"
86 #include "winioctl.h"
87 #include "ddk/ntddser.h"
88
89 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
90 WINE_DECLARE_DEBUG_CHANNEL(winediag);
91
92 mode_t FILE_umask = 0;
93
94 #define SECSPERDAY         86400
95 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
96
97
98 /**************************************************************************
99  *                 FILE_CreateFile                    (internal)
100  * Open a file.
101  *
102  * Parameter set fully identical with NtCreateFile
103  */
104 static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
105                                  PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
106                                  ULONG attributes, ULONG sharing, ULONG disposition,
107                                  ULONG options, PVOID ea_buffer, ULONG ea_length )
108 {
109     ANSI_STRING unix_name;
110     int created = FALSE;
111
112     TRACE("handle=%p access=%08x name=%s objattr=%08x root=%p sec=%p io=%p alloc_size=%p "
113           "attr=%08x sharing=%08x disp=%d options=%08x ea=%p.0x%08x\n",
114           handle, access, debugstr_us(attr->ObjectName), attr->Attributes,
115           attr->RootDirectory, attr->SecurityDescriptor, io, alloc_size,
116           attributes, sharing, disposition, options, ea_buffer, ea_length );
117
118     if (!attr || !attr->ObjectName) return STATUS_INVALID_PARAMETER;
119
120     if (alloc_size) FIXME( "alloc_size not supported\n" );
121
122     if (options & FILE_OPEN_BY_FILE_ID)
123         io->u.Status = file_id_to_unix_file_name( attr, &unix_name );
124     else
125         io->u.Status = nt_to_unix_file_name_attr( attr, &unix_name, disposition );
126
127     if (io->u.Status == STATUS_BAD_DEVICE_TYPE)
128     {
129         SERVER_START_REQ( open_file_object )
130         {
131             req->access     = access;
132             req->attributes = attr->Attributes;
133             req->rootdir    = wine_server_obj_handle( attr->RootDirectory );
134             req->sharing    = sharing;
135             req->options    = options;
136             wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
137             io->u.Status = wine_server_call( req );
138             *handle = wine_server_ptr_handle( reply->handle );
139         }
140         SERVER_END_REQ;
141         if (io->u.Status == STATUS_SUCCESS) io->Information = FILE_OPENED;
142         return io->u.Status;
143     }
144
145     if (io->u.Status == STATUS_NO_SUCH_FILE &&
146         disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
147     {
148         created = TRUE;
149         io->u.Status = STATUS_SUCCESS;
150     }
151
152     if (io->u.Status == STATUS_SUCCESS)
153     {
154         struct security_descriptor *sd;
155         struct object_attributes objattr;
156
157         objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
158         objattr.name_len = 0;
159         io->u.Status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
160         if (io->u.Status != STATUS_SUCCESS)
161         {
162             RtlFreeAnsiString( &unix_name );
163             return io->u.Status;
164         }
165
166         SERVER_START_REQ( create_file )
167         {
168             req->access     = access;
169             req->attributes = attr->Attributes;
170             req->sharing    = sharing;
171             req->create     = disposition;
172             req->options    = options;
173             req->attrs      = attributes;
174             wine_server_add_data( req, &objattr, sizeof(objattr) );
175             if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
176             wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
177             io->u.Status = wine_server_call( req );
178             *handle = wine_server_ptr_handle( reply->handle );
179         }
180         SERVER_END_REQ;
181         NTDLL_free_struct_sd( sd );
182         RtlFreeAnsiString( &unix_name );
183     }
184     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
185
186     if (io->u.Status == STATUS_SUCCESS)
187     {
188         if (created) io->Information = FILE_CREATED;
189         else switch(disposition)
190         {
191         case FILE_SUPERSEDE:
192             io->Information = FILE_SUPERSEDED;
193             break;
194         case FILE_CREATE:
195             io->Information = FILE_CREATED;
196             break;
197         case FILE_OPEN:
198         case FILE_OPEN_IF:
199             io->Information = FILE_OPENED;
200             break;
201         case FILE_OVERWRITE:
202         case FILE_OVERWRITE_IF:
203             io->Information = FILE_OVERWRITTEN;
204             break;
205         }
206     }
207     else if (io->u.Status == STATUS_TOO_MANY_OPENED_FILES)
208     {
209         static int once;
210         if (!once++) ERR_(winediag)( "Too many open files, ulimit -n probably needs to be increased\n" );
211     }
212
213     return io->u.Status;
214 }
215
216 /**************************************************************************
217  *                 NtOpenFile                           [NTDLL.@]
218  *                 ZwOpenFile                           [NTDLL.@]
219  *
220  * Open a file.
221  *
222  * PARAMS
223  *  handle    [O] Variable that receives the file handle on return
224  *  access    [I] Access desired by the caller to the file
225  *  attr      [I] Structure describing the file to be opened
226  *  io        [O] Receives details about the result of the operation
227  *  sharing   [I] Type of shared access the caller requires
228  *  options   [I] Options for the file open
229  *
230  * RETURNS
231  *  Success: 0. FileHandle and IoStatusBlock are updated.
232  *  Failure: An NTSTATUS error code describing the error.
233  */
234 NTSTATUS WINAPI NtOpenFile( PHANDLE handle, ACCESS_MASK access,
235                             POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK io,
236                             ULONG sharing, ULONG options )
237 {
238     return FILE_CreateFile( handle, access, attr, io, NULL, 0,
239                             sharing, FILE_OPEN, options, NULL, 0 );
240 }
241
242 /**************************************************************************
243  *              NtCreateFile                            [NTDLL.@]
244  *              ZwCreateFile                            [NTDLL.@]
245  *
246  * Either create a new file or directory, or open an existing file, device,
247  * directory or volume.
248  *
249  * PARAMS
250  *      handle       [O] Points to a variable which receives the file handle on return
251  *      access       [I] Desired access to the file
252  *      attr         [I] Structure describing the file
253  *      io           [O] Receives information about the operation on return
254  *      alloc_size   [I] Initial size of the file in bytes
255  *      attributes   [I] Attributes to create the file with
256  *      sharing      [I] Type of shared access the caller would like to the file
257  *      disposition  [I] Specifies what to do, depending on whether the file already exists
258  *      options      [I] Options for creating a new file
259  *      ea_buffer    [I] Pointer to an extended attributes buffer
260  *      ea_length    [I] Length of ea_buffer
261  *
262  * RETURNS
263  *  Success: 0. handle and io are updated.
264  *  Failure: An NTSTATUS error code describing the error.
265  */
266 NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
267                               PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
268                               ULONG attributes, ULONG sharing, ULONG disposition,
269                               ULONG options, PVOID ea_buffer, ULONG ea_length )
270 {
271     return FILE_CreateFile( handle, access, attr, io, alloc_size, attributes,
272                             sharing, disposition, options, ea_buffer, ea_length );
273 }
274
275 /***********************************************************************
276  *                  Asynchronous file I/O                              *
277  */
278
279 struct async_fileio
280 {
281     HANDLE              handle;
282     PIO_APC_ROUTINE     apc;
283     void               *apc_arg;
284 };
285
286 typedef struct
287 {
288     struct async_fileio io;
289     char*               buffer;
290     unsigned int        already;
291     unsigned int        count;
292     BOOL                avail_mode;
293 } async_fileio_read;
294
295 typedef struct
296 {
297     struct async_fileio io;
298     const char         *buffer;
299     unsigned int        already;
300     unsigned int        count;
301 } async_fileio_write;
302
303
304 /* callback for file I/O user APC */
305 static void WINAPI fileio_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved )
306 {
307     struct async_fileio *async = arg;
308     if (async->apc) async->apc( async->apc_arg, io, reserved );
309     RtlFreeHeap( GetProcessHeap(), 0, async );
310 }
311
312 /***********************************************************************
313  *           FILE_GetNtStatus(void)
314  *
315  * Retrieve the Nt Status code from errno.
316  * Try to be consistent with FILE_SetDosError().
317  */
318 NTSTATUS FILE_GetNtStatus(void)
319 {
320     int err = errno;
321
322     TRACE( "errno = %d\n", errno );
323     switch (err)
324     {
325     case EAGAIN:    return STATUS_SHARING_VIOLATION;
326     case EBADF:     return STATUS_INVALID_HANDLE;
327     case EBUSY:     return STATUS_DEVICE_BUSY;
328     case ENOSPC:    return STATUS_DISK_FULL;
329     case EPERM:
330     case EROFS:
331     case EACCES:    return STATUS_ACCESS_DENIED;
332     case ENOTDIR:   return STATUS_OBJECT_PATH_NOT_FOUND;
333     case ENOENT:    return STATUS_OBJECT_NAME_NOT_FOUND;
334     case EISDIR:    return STATUS_FILE_IS_A_DIRECTORY;
335     case EMFILE:
336     case ENFILE:    return STATUS_TOO_MANY_OPENED_FILES;
337     case EINVAL:    return STATUS_INVALID_PARAMETER;
338     case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
339     case EPIPE:     return STATUS_PIPE_DISCONNECTED;
340     case EIO:       return STATUS_DEVICE_NOT_READY;
341 #ifdef ENOMEDIUM
342     case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE;
343 #endif
344     case ENXIO:     return STATUS_NO_SUCH_DEVICE;
345     case ENOTTY:
346     case EOPNOTSUPP:return STATUS_NOT_SUPPORTED;
347     case ECONNRESET:return STATUS_PIPE_DISCONNECTED;
348     case EFAULT:    return STATUS_ACCESS_VIOLATION;
349     case ESPIPE:    return STATUS_ILLEGAL_FUNCTION;
350     case ENOEXEC:   /* ?? */
351     case EEXIST:    /* ?? */
352     default:
353         FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
354         return STATUS_UNSUCCESSFUL;
355     }
356 }
357
358 /***********************************************************************
359  *             FILE_AsyncReadService      (INTERNAL)
360  */
361 static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc)
362 {
363     async_fileio_read *fileio = user;
364     int fd, needs_close, result;
365
366     switch (status)
367     {
368     case STATUS_ALERTED: /* got some new data */
369         /* check to see if the data is ready (non-blocking) */
370         if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
371                                           &needs_close, NULL, NULL )))
372             break;
373
374         result = read(fd, &fileio->buffer[fileio->already], fileio->count - fileio->already);
375         if (needs_close) close( fd );
376
377         if (result < 0)
378         {
379             if (errno == EAGAIN || errno == EINTR)
380                 status = STATUS_PENDING;
381             else /* check to see if the transfer is complete */
382                 status = FILE_GetNtStatus();
383         }
384         else if (result == 0)
385         {
386             status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN;
387         }
388         else
389         {
390             fileio->already += result;
391             if (fileio->already >= fileio->count || fileio->avail_mode)
392                 status = STATUS_SUCCESS;
393             else
394             {
395                 /* if we only have to read the available data, and none is available,
396                  * simply cancel the request. If data was available, it has been read
397                  * while in by previous call (NtDelayExecution)
398                  */
399                 status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING;
400             }
401         }
402         break;
403
404     case STATUS_TIMEOUT:
405     case STATUS_IO_TIMEOUT:
406         if (fileio->already) status = STATUS_SUCCESS;
407         break;
408     }
409     if (status != STATUS_PENDING)
410     {
411         iosb->u.Status = status;
412         iosb->Information = fileio->already;
413         *apc = fileio_apc;
414     }
415     return status;
416 }
417
418 struct io_timeouts
419 {
420     int interval;   /* max interval between two bytes */
421     int total;      /* total timeout for the whole operation */
422     int end_time;   /* absolute time of end of operation */
423 };
424
425 /* retrieve the I/O timeouts to use for a given handle */
426 static NTSTATUS get_io_timeouts( HANDLE handle, enum server_fd_type type, ULONG count, BOOL is_read,
427                                  struct io_timeouts *timeouts )
428 {
429     NTSTATUS status = STATUS_SUCCESS;
430
431     timeouts->interval = timeouts->total = -1;
432
433     switch(type)
434     {
435     case FD_TYPE_SERIAL:
436         {
437             /* GetCommTimeouts */
438             SERIAL_TIMEOUTS st;
439             IO_STATUS_BLOCK io;
440
441             status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
442                                             IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
443             if (status) break;
444
445             if (is_read)
446             {
447                 if (st.ReadIntervalTimeout)
448                     timeouts->interval = st.ReadIntervalTimeout;
449
450                 if (st.ReadTotalTimeoutMultiplier || st.ReadTotalTimeoutConstant)
451                 {
452                     timeouts->total = st.ReadTotalTimeoutConstant;
453                     if (st.ReadTotalTimeoutMultiplier != MAXDWORD)
454                         timeouts->total += count * st.ReadTotalTimeoutMultiplier;
455                 }
456                 else if (st.ReadIntervalTimeout == MAXDWORD)
457                     timeouts->interval = timeouts->total = 0;
458             }
459             else  /* write */
460             {
461                 if (st.WriteTotalTimeoutMultiplier || st.WriteTotalTimeoutConstant)
462                 {
463                     timeouts->total = st.WriteTotalTimeoutConstant;
464                     if (st.WriteTotalTimeoutMultiplier != MAXDWORD)
465                         timeouts->total += count * st.WriteTotalTimeoutMultiplier;
466                 }
467             }
468         }
469         break;
470     case FD_TYPE_MAILSLOT:
471         if (is_read)
472         {
473             timeouts->interval = 0;  /* return as soon as we got something */
474             SERVER_START_REQ( set_mailslot_info )
475             {
476                 req->handle = wine_server_obj_handle( handle );
477                 req->flags = 0;
478                 if (!(status = wine_server_call( req )) &&
479                     reply->read_timeout != TIMEOUT_INFINITE)
480                     timeouts->total = reply->read_timeout / -10000;
481             }
482             SERVER_END_REQ;
483         }
484         break;
485     case FD_TYPE_SOCKET:
486     case FD_TYPE_PIPE:
487     case FD_TYPE_CHAR:
488         if (is_read) timeouts->interval = 0;  /* return as soon as we got something */
489         break;
490     default:
491         break;
492     }
493     if (timeouts->total != -1) timeouts->end_time = NtGetTickCount() + timeouts->total;
494     return STATUS_SUCCESS;
495 }
496
497
498 /* retrieve the timeout for the next wait, in milliseconds */
499 static inline int get_next_io_timeout( const struct io_timeouts *timeouts, ULONG already )
500 {
501     int ret = -1;
502
503     if (timeouts->total != -1)
504     {
505         ret = timeouts->end_time - NtGetTickCount();
506         if (ret < 0) ret = 0;
507     }
508     if (already && timeouts->interval != -1)
509     {
510         if (ret == -1 || ret > timeouts->interval) ret = timeouts->interval;
511     }
512     return ret;
513 }
514
515
516 /* retrieve the avail_mode flag for async reads */
517 static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL *avail_mode )
518 {
519     NTSTATUS status = STATUS_SUCCESS;
520
521     switch(type)
522     {
523     case FD_TYPE_SERIAL:
524         {
525             /* GetCommTimeouts */
526             SERIAL_TIMEOUTS st;
527             IO_STATUS_BLOCK io;
528
529             status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
530                                             IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
531             if (status) break;
532             *avail_mode = (!st.ReadTotalTimeoutMultiplier &&
533                            !st.ReadTotalTimeoutConstant &&
534                            st.ReadIntervalTimeout == MAXDWORD);
535         }
536         break;
537     case FD_TYPE_MAILSLOT:
538     case FD_TYPE_SOCKET:
539     case FD_TYPE_PIPE:
540     case FD_TYPE_CHAR:
541         *avail_mode = TRUE;
542         break;
543     default:
544         *avail_mode = FALSE;
545         break;
546     }
547     return status;
548 }
549
550
551 /******************************************************************************
552  *  NtReadFile                                  [NTDLL.@]
553  *  ZwReadFile                                  [NTDLL.@]
554  *
555  * Read from an open file handle.
556  *
557  * PARAMS
558  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
559  *  Event         [I] Event to signal upon completion (or NULL)
560  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
561  *  ApcContext    [I] Context for ApcRoutine (or NULL)
562  *  IoStatusBlock [O] Receives information about the operation on return
563  *  Buffer        [O] Destination for the data read
564  *  Length        [I] Size of Buffer
565  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
566  *  Key           [O] Function unknown (may be NULL)
567  *
568  * RETURNS
569  *  Success: 0. IoStatusBlock is updated, and the Information member contains
570  *           The number of bytes read.
571  *  Failure: An NTSTATUS error code describing the error.
572  */
573 NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
574                            PIO_APC_ROUTINE apc, void* apc_user,
575                            PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
576                            PLARGE_INTEGER offset, PULONG key)
577 {
578     int result, unix_handle, needs_close, timeout_init_done = 0;
579     unsigned int options;
580     struct io_timeouts timeouts;
581     NTSTATUS status;
582     ULONG total = 0;
583     enum server_fd_type type;
584     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
585     BOOL send_completion = FALSE;
586
587     TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
588           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
589
590     if (!io_status) return STATUS_ACCESS_VIOLATION;
591
592     status = server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
593                                  &needs_close, &type, &options );
594     if (status) return status;
595
596     if (!virtual_check_buffer_for_write( buffer, length ))
597     {
598         status = STATUS_ACCESS_VIOLATION;
599         goto done;
600     }
601
602     if (type == FD_TYPE_FILE && offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */ )
603     {
604         /* async I/O doesn't make sense on regular files */
605         while ((result = pread( unix_handle, buffer, length, offset->QuadPart )) == -1)
606         {
607             if (errno != EINTR)
608             {
609                 status = FILE_GetNtStatus();
610                 goto done;
611             }
612         }
613         if (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
614             /* update file pointer position */
615             lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
616
617         total = result;
618         status = total ? STATUS_SUCCESS : STATUS_END_OF_FILE;
619         goto done;
620     }
621
622     for (;;)
623     {
624         if ((result = read( unix_handle, (char *)buffer + total, length - total )) >= 0)
625         {
626             total += result;
627             if (!result || total == length)
628             {
629                 if (total)
630                 {
631                     status = STATUS_SUCCESS;
632                     goto done;
633                 }
634                 switch (type)
635                 {
636                 case FD_TYPE_FILE:
637                 case FD_TYPE_CHAR:
638                     status = STATUS_END_OF_FILE;
639                     goto done;
640                 case FD_TYPE_SERIAL:
641                     break;
642                 default:
643                     status = STATUS_PIPE_BROKEN;
644                     goto done;
645                 }
646             }
647             else if (type == FD_TYPE_FILE) continue;  /* no async I/O on regular files */
648         }
649         else if (errno != EAGAIN)
650         {
651             if (errno == EINTR) continue;
652             if (!total) status = FILE_GetNtStatus();
653             goto done;
654         }
655
656         if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
657         {
658             async_fileio_read *fileio;
659             BOOL avail_mode;
660
661             if ((status = get_io_avail_mode( hFile, type, &avail_mode )))
662                 goto err;
663             if (total && avail_mode)
664             {
665                 status = STATUS_SUCCESS;
666                 goto done;
667             }
668
669             if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio))))
670             {
671                 status = STATUS_NO_MEMORY;
672                 goto err;
673             }
674             fileio->io.handle  = hFile;
675             fileio->io.apc     = apc;
676             fileio->io.apc_arg = apc_user;
677             fileio->already = total;
678             fileio->count = length;
679             fileio->buffer = buffer;
680             fileio->avail_mode = avail_mode;
681
682             SERVER_START_REQ( register_async )
683             {
684                 req->type   = ASYNC_TYPE_READ;
685                 req->count  = length;
686                 req->async.handle   = wine_server_obj_handle( hFile );
687                 req->async.event    = wine_server_obj_handle( hEvent );
688                 req->async.callback = wine_server_client_ptr( FILE_AsyncReadService );
689                 req->async.iosb     = wine_server_client_ptr( io_status );
690                 req->async.arg      = wine_server_client_ptr( fileio );
691                 req->async.cvalue   = cvalue;
692                 status = wine_server_call( req );
693             }
694             SERVER_END_REQ;
695
696             if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
697             goto err;
698         }
699         else  /* synchronous read, wait for the fd to become ready */
700         {
701             struct pollfd pfd;
702             int ret, timeout;
703
704             if (!timeout_init_done)
705             {
706                 timeout_init_done = 1;
707                 if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts )))
708                     goto err;
709                 if (hEvent) NtResetEvent( hEvent, NULL );
710             }
711             timeout = get_next_io_timeout( &timeouts, total );
712
713             pfd.fd = unix_handle;
714             pfd.events = POLLIN;
715
716             if (!timeout || !(ret = poll( &pfd, 1, timeout )))
717             {
718                 if (total)  /* return with what we got so far */
719                     status = STATUS_SUCCESS;
720                 else
721                     status = (type == FD_TYPE_MAILSLOT) ? STATUS_IO_TIMEOUT : STATUS_TIMEOUT;
722                 goto done;
723             }
724             if (ret == -1 && errno != EINTR)
725             {
726                 status = FILE_GetNtStatus();
727                 goto done;
728             }
729             /* will now restart the read */
730         }
731     }
732
733 done:
734     send_completion = cvalue != 0;
735
736 err:
737     if (needs_close) close( unix_handle );
738     if (status == STATUS_SUCCESS)
739     {
740         io_status->u.Status = status;
741         io_status->Information = total;
742         TRACE("= SUCCESS (%u)\n", total);
743         if (hEvent) NtSetEvent( hEvent, NULL );
744         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
745                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
746     }
747     else
748     {
749         TRACE("= 0x%08x\n", status);
750         if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
751     }
752
753     if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total );
754
755     return status;
756 }
757
758
759 /******************************************************************************
760  *  NtReadFileScatter   [NTDLL.@]
761  *  ZwReadFileScatter   [NTDLL.@]
762  */
763 NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
764                                    PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
765                                    ULONG length, PLARGE_INTEGER offset, PULONG key )
766 {
767     size_t page_size = getpagesize();
768     int result, unix_handle, needs_close;
769     unsigned int options;
770     NTSTATUS status;
771     ULONG pos = 0, total = 0;
772     enum server_fd_type type;
773     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
774     BOOL send_completion = FALSE;
775
776     TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
777            file, event, apc, apc_user, io_status, segments, length, offset, key);
778
779     if (length % page_size) return STATUS_INVALID_PARAMETER;
780     if (!io_status) return STATUS_ACCESS_VIOLATION;
781
782     status = server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
783                                  &needs_close, &type, &options );
784     if (status) return status;
785
786     if ((type != FD_TYPE_FILE) ||
787         (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
788         !(options & FILE_NO_INTERMEDIATE_BUFFERING))
789     {
790         status = STATUS_INVALID_PARAMETER;
791         goto error;
792     }
793
794     while (length)
795     {
796         if (offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */)
797             result = pread( unix_handle, (char *)segments->Buffer + pos,
798                             page_size - pos, offset->QuadPart + total );
799         else
800             result = read( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
801
802         if (result == -1)
803         {
804             if (errno == EINTR) continue;
805             status = FILE_GetNtStatus();
806             break;
807         }
808         if (!result)
809         {
810             status = STATUS_END_OF_FILE;
811             break;
812         }
813         total += result;
814         length -= result;
815         if ((pos += result) == page_size)
816         {
817             pos = 0;
818             segments++;
819         }
820     }
821
822     send_completion = cvalue != 0;
823
824  error:
825     if (needs_close) close( unix_handle );
826     if (status == STATUS_SUCCESS)
827     {
828         io_status->u.Status = status;
829         io_status->Information = total;
830         TRACE("= SUCCESS (%u)\n", total);
831         if (event) NtSetEvent( event, NULL );
832         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
833                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
834     }
835     else
836     {
837         TRACE("= 0x%08x\n", status);
838         if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
839     }
840
841     if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total );
842
843     return status;
844 }
845
846
847 /***********************************************************************
848  *             FILE_AsyncWriteService      (INTERNAL)
849  */
850 static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status, void **apc)
851 {
852     async_fileio_write *fileio = user;
853     int result, fd, needs_close;
854     enum server_fd_type type;
855
856     switch (status)
857     {
858     case STATUS_ALERTED:
859         /* write some data (non-blocking) */
860         if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
861                                           &needs_close, &type, NULL )))
862             break;
863
864         if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
865             result = send( fd, fileio->buffer, 0, 0 );
866         else
867             result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already );
868
869         if (needs_close) close( fd );
870
871         if (result < 0)
872         {
873             if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING;
874             else status = FILE_GetNtStatus();
875         }
876         else
877         {
878             fileio->already += result;
879             status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
880         }
881         break;
882
883     case STATUS_TIMEOUT:
884     case STATUS_IO_TIMEOUT:
885         if (fileio->already) status = STATUS_SUCCESS;
886         break;
887     }
888     if (status != STATUS_PENDING)
889     {
890         iosb->u.Status = status;
891         iosb->Information = fileio->already;
892         *apc = fileio_apc;
893     }
894     return status;
895 }
896
897 /******************************************************************************
898  *  NtWriteFile                                 [NTDLL.@]
899  *  ZwWriteFile                                 [NTDLL.@]
900  *
901  * Write to an open file handle.
902  *
903  * PARAMS
904  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
905  *  Event         [I] Event to signal upon completion (or NULL)
906  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
907  *  ApcContext    [I] Context for ApcRoutine (or NULL)
908  *  IoStatusBlock [O] Receives information about the operation on return
909  *  Buffer        [I] Source for the data to write
910  *  Length        [I] Size of Buffer
911  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
912  *  Key           [O] Function unknown (may be NULL)
913  *
914  * RETURNS
915  *  Success: 0. IoStatusBlock is updated, and the Information member contains
916  *           The number of bytes written.
917  *  Failure: An NTSTATUS error code describing the error.
918  */
919 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
920                             PIO_APC_ROUTINE apc, void* apc_user,
921                             PIO_STATUS_BLOCK io_status, 
922                             const void* buffer, ULONG length,
923                             PLARGE_INTEGER offset, PULONG key)
924 {
925     int result, unix_handle, needs_close, timeout_init_done = 0;
926     unsigned int options;
927     struct io_timeouts timeouts;
928     NTSTATUS status;
929     ULONG total = 0;
930     enum server_fd_type type;
931     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
932     BOOL send_completion = FALSE;
933
934     TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)!\n",
935           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
936
937     if (!io_status) return STATUS_ACCESS_VIOLATION;
938
939     status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
940                                  &needs_close, &type, &options );
941     if (status) return status;
942
943     if (!virtual_check_buffer_for_read( buffer, length ))
944     {
945         status = STATUS_INVALID_USER_BUFFER;
946         goto done;
947     }
948
949     if (type == FD_TYPE_FILE && offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */ )
950     {
951         /* async I/O doesn't make sense on regular files */
952         while ((result = pwrite( unix_handle, buffer, length, offset->QuadPart )) == -1)
953         {
954             if (errno != EINTR)
955             {
956                 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
957                 else status = FILE_GetNtStatus();
958                 goto done;
959             }
960         }
961
962         if (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
963             /* update file pointer position */
964             lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
965
966         total = result;
967         status = STATUS_SUCCESS;
968         goto done;
969     }
970
971     for (;;)
972     {
973         /* zero-length writes on sockets may not work with plain write(2) */
974         if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
975             result = send( unix_handle, buffer, 0, 0 );
976         else
977             result = write( unix_handle, (const char *)buffer + total, length - total );
978
979         if (result >= 0)
980         {
981             total += result;
982             if (total == length)
983             {
984                 status = STATUS_SUCCESS;
985                 goto done;
986             }
987             if (type == FD_TYPE_FILE) continue;  /* no async I/O on regular files */
988         }
989         else if (errno != EAGAIN)
990         {
991             if (errno == EINTR) continue;
992             if (!total)
993             {
994                 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
995                 else status = FILE_GetNtStatus();
996             }
997             goto done;
998         }
999
1000         if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
1001         {
1002             async_fileio_write *fileio;
1003
1004             if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio))))
1005             {
1006                 status = STATUS_NO_MEMORY;
1007                 goto err;
1008             }
1009             fileio->io.handle  = hFile;
1010             fileio->io.apc     = apc;
1011             fileio->io.apc_arg = apc_user;
1012             fileio->already = total;
1013             fileio->count = length;
1014             fileio->buffer = buffer;
1015
1016             SERVER_START_REQ( register_async )
1017             {
1018                 req->type   = ASYNC_TYPE_WRITE;
1019                 req->count  = length;
1020                 req->async.handle   = wine_server_obj_handle( hFile );
1021                 req->async.event    = wine_server_obj_handle( hEvent );
1022                 req->async.callback = wine_server_client_ptr( FILE_AsyncWriteService );
1023                 req->async.iosb     = wine_server_client_ptr( io_status );
1024                 req->async.arg      = wine_server_client_ptr( fileio );
1025                 req->async.cvalue   = cvalue;
1026                 status = wine_server_call( req );
1027             }
1028             SERVER_END_REQ;
1029
1030             if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
1031             goto err;
1032         }
1033         else  /* synchronous write, wait for the fd to become ready */
1034         {
1035             struct pollfd pfd;
1036             int ret, timeout;
1037
1038             if (!timeout_init_done)
1039             {
1040                 timeout_init_done = 1;
1041                 if ((status = get_io_timeouts( hFile, type, length, FALSE, &timeouts )))
1042                     goto err;
1043                 if (hEvent) NtResetEvent( hEvent, NULL );
1044             }
1045             timeout = get_next_io_timeout( &timeouts, total );
1046
1047             pfd.fd = unix_handle;
1048             pfd.events = POLLOUT;
1049
1050             if (!timeout || !(ret = poll( &pfd, 1, timeout )))
1051             {
1052                 /* return with what we got so far */
1053                 status = total ? STATUS_SUCCESS : STATUS_TIMEOUT;
1054                 goto done;
1055             }
1056             if (ret == -1 && errno != EINTR)
1057             {
1058                 status = FILE_GetNtStatus();
1059                 goto done;
1060             }
1061             /* will now restart the write */
1062         }
1063     }
1064
1065 done:
1066     send_completion = cvalue != 0;
1067
1068 err:
1069     if (needs_close) close( unix_handle );
1070     if (status == STATUS_SUCCESS)
1071     {
1072         io_status->u.Status = status;
1073         io_status->Information = total;
1074         TRACE("= SUCCESS (%u)\n", total);
1075         if (hEvent) NtSetEvent( hEvent, NULL );
1076         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1077                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1078     }
1079     else
1080     {
1081         TRACE("= 0x%08x\n", status);
1082         if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
1083     }
1084
1085     if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total );
1086
1087     return status;
1088 }
1089
1090
1091 /******************************************************************************
1092  *  NtWriteFileGather   [NTDLL.@]
1093  *  ZwWriteFileGather   [NTDLL.@]
1094  */
1095 NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1096                                    PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
1097                                    ULONG length, PLARGE_INTEGER offset, PULONG key )
1098 {
1099     size_t page_size = getpagesize();
1100     int result, unix_handle, needs_close;
1101     unsigned int options;
1102     NTSTATUS status;
1103     ULONG pos = 0, total = 0;
1104     enum server_fd_type type;
1105     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1106     BOOL send_completion = FALSE;
1107
1108     TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
1109            file, event, apc, apc_user, io_status, segments, length, offset, key);
1110
1111     if (length % page_size) return STATUS_INVALID_PARAMETER;
1112     if (!io_status) return STATUS_ACCESS_VIOLATION;
1113
1114     status = server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
1115                                  &needs_close, &type, &options );
1116     if (status) return status;
1117
1118     if ((type != FD_TYPE_FILE) ||
1119         (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
1120         !(options & FILE_NO_INTERMEDIATE_BUFFERING))
1121     {
1122         status = STATUS_INVALID_PARAMETER;
1123         goto error;
1124     }
1125
1126     while (length)
1127     {
1128         if (offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */)
1129             result = pwrite( unix_handle, (char *)segments->Buffer + pos,
1130                              page_size - pos, offset->QuadPart + total );
1131         else
1132             result = write( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
1133
1134         if (result == -1)
1135         {
1136             if (errno == EINTR) continue;
1137             if (errno == EFAULT)
1138             {
1139                 status = STATUS_INVALID_USER_BUFFER;
1140                 goto error;
1141             }
1142             status = FILE_GetNtStatus();
1143             break;
1144         }
1145         if (!result)
1146         {
1147             status = STATUS_DISK_FULL;
1148             break;
1149         }
1150         total += result;
1151         length -= result;
1152         if ((pos += result) == page_size)
1153         {
1154             pos = 0;
1155             segments++;
1156         }
1157     }
1158
1159     send_completion = cvalue != 0;
1160
1161  error:
1162     if (needs_close) close( unix_handle );
1163     if (status == STATUS_SUCCESS)
1164     {
1165         io_status->u.Status = status;
1166         io_status->Information = total;
1167         TRACE("= SUCCESS (%u)\n", total);
1168         if (event) NtSetEvent( event, NULL );
1169         if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1170                                    (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1171     }
1172     else
1173     {
1174         TRACE("= 0x%08x\n", status);
1175         if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
1176     }
1177
1178     if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total );
1179
1180     return status;
1181 }
1182
1183
1184 struct async_ioctl
1185 {
1186     HANDLE          handle;   /* handle to the device */
1187     HANDLE          event;    /* async event */
1188     void           *buffer;   /* buffer for output */
1189     ULONG           size;     /* size of buffer */
1190     PIO_APC_ROUTINE apc;      /* user apc params */
1191     void           *apc_arg;
1192 };
1193
1194 /* callback for ioctl user APC */
1195 static void WINAPI ioctl_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved )
1196 {
1197     struct async_ioctl *async = arg;
1198     if (async->apc) async->apc( async->apc_arg, io, reserved );
1199     RtlFreeHeap( GetProcessHeap(), 0, async );
1200 }
1201
1202 /* callback for ioctl async I/O completion */
1203 static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS status, void **apc )
1204 {
1205     struct async_ioctl *async = arg;
1206
1207     if (status == STATUS_ALERTED)
1208     {
1209         SERVER_START_REQ( get_ioctl_result )
1210         {
1211             req->handle   = wine_server_obj_handle( async->handle );
1212             req->user_arg = wine_server_client_ptr( async );
1213             wine_server_set_reply( req, async->buffer, async->size );
1214             status = wine_server_call( req );
1215             if (status != STATUS_PENDING) io->Information = wine_server_reply_size( reply );
1216         }
1217         SERVER_END_REQ;
1218     }
1219     if (status != STATUS_PENDING)
1220     {
1221         io->u.Status = status;
1222         if (async->apc || async->event) *apc = ioctl_apc;
1223     }
1224     return status;
1225 }
1226
1227 /* do a ioctl call through the server */
1228 static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
1229                                    PIO_APC_ROUTINE apc, PVOID apc_context,
1230                                    IO_STATUS_BLOCK *io, ULONG code,
1231                                    const void *in_buffer, ULONG in_size,
1232                                    PVOID out_buffer, ULONG out_size )
1233 {
1234     struct async_ioctl *async;
1235     NTSTATUS status;
1236     HANDLE wait_handle;
1237     ULONG options;
1238     ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
1239
1240     if (!(async = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*async) )))
1241         return STATUS_NO_MEMORY;
1242     async->handle  = handle;
1243     async->event   = event;
1244     async->buffer  = out_buffer;
1245     async->size    = out_size;
1246     async->apc     = apc;
1247     async->apc_arg = apc_context;
1248
1249     SERVER_START_REQ( ioctl )
1250     {
1251         req->code           = code;
1252         req->blocking       = !apc && !event && !cvalue;
1253         req->async.handle   = wine_server_obj_handle( handle );
1254         req->async.callback = wine_server_client_ptr( ioctl_completion );
1255         req->async.iosb     = wine_server_client_ptr( io );
1256         req->async.arg      = wine_server_client_ptr( async );
1257         req->async.event    = wine_server_obj_handle( event );
1258         req->async.cvalue   = cvalue;
1259         wine_server_add_data( req, in_buffer, in_size );
1260         wine_server_set_reply( req, out_buffer, out_size );
1261         status = wine_server_call( req );
1262         wait_handle = wine_server_ptr_handle( reply->wait );
1263         options     = reply->options;
1264         if (status != STATUS_PENDING) io->Information = wine_server_reply_size( reply );
1265     }
1266     SERVER_END_REQ;
1267
1268     if (status == STATUS_NOT_SUPPORTED)
1269         FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
1270               code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1271
1272     if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
1273
1274     if (wait_handle)
1275     {
1276         NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL );
1277         status = io->u.Status;
1278         NtClose( wait_handle );
1279         RtlFreeHeap( GetProcessHeap(), 0, async );
1280     }
1281
1282     return status;
1283 }
1284
1285 /* Tell Valgrind to ignore any holes in structs we will be passing to the
1286  * server */
1287 static void ignore_server_ioctl_struct_holes (ULONG code, const void *in_buffer,
1288                                               ULONG in_size)
1289 {
1290 #ifdef VALGRIND_MAKE_MEM_DEFINED
1291 # define IGNORE_STRUCT_HOLE(buf, size, t, f1, f2) \
1292     do { \
1293         if ((size) >= FIELD_OFFSET(t, f2) && \
1294             FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1) < FIELD_OFFSET(t, f2)) \
1295             VALGRIND_MAKE_MEM_DEFINED( \
1296                 (const char *)(buf) + FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1), \
1297                 FIELD_OFFSET(t, f2) - FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1)); \
1298     } while (0)
1299
1300     switch (code)
1301     {
1302     case FSCTL_PIPE_WAIT:
1303         IGNORE_STRUCT_HOLE(in_buffer, in_size, FILE_PIPE_WAIT_FOR_BUFFER, TimeoutSpecified, Name);
1304         break;
1305     }
1306 #endif
1307 }
1308
1309
1310 /**************************************************************************
1311  *              NtDeviceIoControlFile                   [NTDLL.@]
1312  *              ZwDeviceIoControlFile                   [NTDLL.@]
1313  *
1314  * Perform an I/O control operation on an open file handle.
1315  *
1316  * PARAMS
1317  *  handle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1318  *  event          [I] Event to signal upon completion (or NULL)
1319  *  apc            [I] Callback to call upon completion (or NULL)
1320  *  apc_context    [I] Context for ApcRoutine (or NULL)
1321  *  io             [O] Receives information about the operation on return
1322  *  code           [I] Control code for the operation to perform
1323  *  in_buffer      [I] Source for any input data required (or NULL)
1324  *  in_size        [I] Size of InputBuffer
1325  *  out_buffer     [O] Source for any output data returned (or NULL)
1326  *  out_size       [I] Size of OutputBuffer
1327  *
1328  * RETURNS
1329  *  Success: 0. IoStatusBlock is updated.
1330  *  Failure: An NTSTATUS error code describing the error.
1331  */
1332 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
1333                                       PIO_APC_ROUTINE apc, PVOID apc_context,
1334                                       PIO_STATUS_BLOCK io, ULONG code,
1335                                       PVOID in_buffer, ULONG in_size,
1336                                       PVOID out_buffer, ULONG out_size)
1337 {
1338     ULONG device = (code >> 16);
1339     NTSTATUS status = STATUS_NOT_SUPPORTED;
1340
1341     TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1342           handle, event, apc, apc_context, io, code,
1343           in_buffer, in_size, out_buffer, out_size);
1344
1345     switch(device)
1346     {
1347     case FILE_DEVICE_DISK:
1348     case FILE_DEVICE_CD_ROM:
1349     case FILE_DEVICE_DVD:
1350     case FILE_DEVICE_CONTROLLER:
1351     case FILE_DEVICE_MASS_STORAGE:
1352         status = CDROM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1353                                        in_buffer, in_size, out_buffer, out_size);
1354         break;
1355     case FILE_DEVICE_SERIAL_PORT:
1356         status = COMM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1357                                       in_buffer, in_size, out_buffer, out_size);
1358         break;
1359     case FILE_DEVICE_TAPE:
1360         status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
1361                                       in_buffer, in_size, out_buffer, out_size);
1362         break;
1363     }
1364
1365     if (status == STATUS_NOT_SUPPORTED || status == STATUS_BAD_DEVICE_TYPE)
1366         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1367                                     in_buffer, in_size, out_buffer, out_size );
1368
1369     if (status != STATUS_PENDING) io->u.Status = status;
1370     return status;
1371 }
1372
1373
1374 /**************************************************************************
1375  *              NtFsControlFile                 [NTDLL.@]
1376  *              ZwFsControlFile                 [NTDLL.@]
1377  *
1378  * Perform a file system control operation on an open file handle.
1379  *
1380  * PARAMS
1381  *  handle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1382  *  event          [I] Event to signal upon completion (or NULL)
1383  *  apc            [I] Callback to call upon completion (or NULL)
1384  *  apc_context    [I] Context for ApcRoutine (or NULL)
1385  *  io             [O] Receives information about the operation on return
1386  *  code           [I] Control code for the operation to perform
1387  *  in_buffer      [I] Source for any input data required (or NULL)
1388  *  in_size        [I] Size of InputBuffer
1389  *  out_buffer     [O] Source for any output data returned (or NULL)
1390  *  out_size       [I] Size of OutputBuffer
1391  *
1392  * RETURNS
1393  *  Success: 0. IoStatusBlock is updated.
1394  *  Failure: An NTSTATUS error code describing the error.
1395  */
1396 NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
1397                                 PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code,
1398                                 PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size)
1399 {
1400     NTSTATUS status;
1401
1402     TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1403           handle, event, apc, apc_context, io, code,
1404           in_buffer, in_size, out_buffer, out_size);
1405
1406     if (!io) return STATUS_INVALID_PARAMETER;
1407
1408     ignore_server_ioctl_struct_holes( code, in_buffer, in_size );
1409
1410     switch(code)
1411     {
1412     case FSCTL_DISMOUNT_VOLUME:
1413         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1414                                     in_buffer, in_size, out_buffer, out_size );
1415         if (!status) status = DIR_unmount_device( handle );
1416         break;
1417
1418     case FSCTL_PIPE_PEEK:
1419         {
1420             FILE_PIPE_PEEK_BUFFER *buffer = out_buffer;
1421             int avail = 0, fd, needs_close;
1422
1423             if (out_size < FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ))
1424             {
1425                 status = STATUS_INFO_LENGTH_MISMATCH;
1426                 break;
1427             }
1428
1429             if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )))
1430                 break;
1431
1432 #ifdef FIONREAD
1433             if (ioctl( fd, FIONREAD, &avail ) != 0)
1434             {
1435                 TRACE("FIONREAD failed reason: %s\n",strerror(errno));
1436                 if (needs_close) close( fd );
1437                 status = FILE_GetNtStatus();
1438                 break;
1439             }
1440 #endif
1441             if (!avail)  /* check for closed pipe */
1442             {
1443                 struct pollfd pollfd;
1444                 int ret;
1445
1446                 pollfd.fd = fd;
1447                 pollfd.events = POLLIN;
1448                 pollfd.revents = 0;
1449                 ret = poll( &pollfd, 1, 0 );
1450                 if (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR))))
1451                 {
1452                     if (needs_close) close( fd );
1453                     status = STATUS_PIPE_BROKEN;
1454                     break;
1455                 }
1456             }
1457             buffer->NamedPipeState    = 0;  /* FIXME */
1458             buffer->ReadDataAvailable = avail;
1459             buffer->NumberOfMessages  = 0;  /* FIXME */
1460             buffer->MessageLength     = 0;  /* FIXME */
1461             io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1462             status = STATUS_SUCCESS;
1463             if (avail)
1464             {
1465                 ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1466                 if (data_size)
1467                 {
1468                     int res = recv( fd, buffer->Data, data_size, MSG_PEEK );
1469                     if (res >= 0) io->Information += res;
1470                 }
1471             }
1472             if (needs_close) close( fd );
1473         }
1474         break;
1475
1476     case FSCTL_PIPE_DISCONNECT:
1477         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1478                                     in_buffer, in_size, out_buffer, out_size );
1479         if (!status)
1480         {
1481             int fd = server_remove_fd_from_cache( handle );
1482             if (fd != -1) close( fd );
1483         }
1484         break;
1485
1486     case FSCTL_PIPE_IMPERSONATE:
1487         FIXME("FSCTL_PIPE_IMPERSONATE: impersonating self\n");
1488         status = RtlImpersonateSelf( SecurityImpersonation );
1489         break;
1490
1491     case FSCTL_LOCK_VOLUME:
1492     case FSCTL_UNLOCK_VOLUME:
1493         FIXME("stub! return success - Unsupported fsctl %x (device=%x access=%x func=%x method=%x)\n",
1494               code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1495         status = STATUS_SUCCESS;
1496         break;
1497
1498     case FSCTL_PIPE_LISTEN:
1499     case FSCTL_PIPE_WAIT:
1500     default:
1501         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1502                                     in_buffer, in_size, out_buffer, out_size );
1503         break;
1504     }
1505
1506     if (status != STATUS_PENDING) io->u.Status = status;
1507     return status;
1508 }
1509
1510 /******************************************************************************
1511  *  NtSetVolumeInformationFile          [NTDLL.@]
1512  *  ZwSetVolumeInformationFile          [NTDLL.@]
1513  *
1514  * Set volume information for an open file handle.
1515  *
1516  * PARAMS
1517  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1518  *  IoStatusBlock      [O] Receives information about the operation on return
1519  *  FsInformation      [I] Source for volume information
1520  *  Length             [I] Size of FsInformation
1521  *  FsInformationClass [I] Type of volume information to set
1522  *
1523  * RETURNS
1524  *  Success: 0. IoStatusBlock is updated.
1525  *  Failure: An NTSTATUS error code describing the error.
1526  */
1527 NTSTATUS WINAPI NtSetVolumeInformationFile(
1528         IN HANDLE FileHandle,
1529         PIO_STATUS_BLOCK IoStatusBlock,
1530         PVOID FsInformation,
1531         ULONG Length,
1532         FS_INFORMATION_CLASS FsInformationClass)
1533 {
1534         FIXME("(%p,%p,%p,0x%08x,0x%08x) stub\n",
1535         FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
1536         return 0;
1537 }
1538
1539 static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, LARGE_INTEGER *ctime,
1540                                    LARGE_INTEGER *atime, LARGE_INTEGER *creation )
1541 {
1542     RtlSecondsSince1970ToTime( st->st_mtime, mtime );
1543     RtlSecondsSince1970ToTime( st->st_ctime, ctime );
1544     RtlSecondsSince1970ToTime( st->st_atime, atime );
1545 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1546     mtime->QuadPart += st->st_mtim.tv_nsec / 100;
1547 #endif
1548 #ifdef HAVE_STRUCT_STAT_ST_CTIM
1549     ctime->QuadPart += st->st_ctim.tv_nsec / 100;
1550 #endif
1551 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1552     atime->QuadPart += st->st_atim.tv_nsec / 100;
1553 #endif
1554     *creation = *mtime;
1555 }
1556
1557 /* fill in the file information that depends on the stat info */
1558 NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLASS class )
1559 {
1560     switch (class)
1561     {
1562     case FileBasicInformation:
1563         {
1564             FILE_BASIC_INFORMATION *info = ptr;
1565
1566             get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
1567                             &info->LastAccessTime, &info->CreationTime );
1568             if (S_ISDIR(st->st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1569             else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1570             if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1571                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1572         }
1573         break;
1574     case FileStandardInformation:
1575         {
1576             FILE_STANDARD_INFORMATION *info = ptr;
1577
1578             if ((info->Directory = S_ISDIR(st->st_mode)))
1579             {
1580                 info->AllocationSize.QuadPart = 0;
1581                 info->EndOfFile.QuadPart      = 0;
1582                 info->NumberOfLinks           = 1;
1583             }
1584             else
1585             {
1586                 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
1587                 info->EndOfFile.QuadPart      = st->st_size;
1588                 info->NumberOfLinks           = st->st_nlink;
1589             }
1590         }
1591         break;
1592     case FileInternalInformation:
1593         {
1594             FILE_INTERNAL_INFORMATION *info = ptr;
1595             info->IndexNumber.QuadPart = st->st_ino;
1596         }
1597         break;
1598     case FileEndOfFileInformation:
1599         {
1600             FILE_END_OF_FILE_INFORMATION *info = ptr;
1601             info->EndOfFile.QuadPart = S_ISDIR(st->st_mode) ? 0 : st->st_size;
1602         }
1603         break;
1604     case FileAllInformation:
1605         {
1606             FILE_ALL_INFORMATION *info = ptr;
1607             fill_stat_info( st, &info->BasicInformation, FileBasicInformation );
1608             fill_stat_info( st, &info->StandardInformation, FileStandardInformation );
1609             fill_stat_info( st, &info->InternalInformation, FileInternalInformation );
1610         }
1611         break;
1612     /* all directory structures start with the FileDirectoryInformation layout */
1613     case FileBothDirectoryInformation:
1614     case FileFullDirectoryInformation:
1615     case FileDirectoryInformation:
1616         {
1617             FILE_DIRECTORY_INFORMATION *info = ptr;
1618
1619             get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
1620                             &info->LastAccessTime, &info->CreationTime );
1621             if (S_ISDIR(st->st_mode))
1622             {
1623                 info->AllocationSize.QuadPart = 0;
1624                 info->EndOfFile.QuadPart      = 0;
1625                 info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1626             }
1627             else
1628             {
1629                 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
1630                 info->EndOfFile.QuadPart      = st->st_size;
1631                 info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1632             }
1633             if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1634                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1635         }
1636         break;
1637     case FileIdFullDirectoryInformation:
1638         {
1639             FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr;
1640             info->FileId.QuadPart = st->st_ino;
1641             fill_stat_info( st, info, FileDirectoryInformation );
1642         }
1643         break;
1644     case FileIdBothDirectoryInformation:
1645         {
1646             FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr;
1647             info->FileId.QuadPart = st->st_ino;
1648             fill_stat_info( st, info, FileDirectoryInformation );
1649         }
1650         break;
1651
1652     default:
1653         return STATUS_INVALID_INFO_CLASS;
1654     }
1655     return STATUS_SUCCESS;
1656 }
1657
1658 NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name )
1659 {
1660     data_size_t size = 1024;
1661     NTSTATUS ret;
1662     char *name;
1663
1664     for (;;)
1665     {
1666         name = RtlAllocateHeap( GetProcessHeap(), 0, size + 1 );
1667         if (!name) return STATUS_NO_MEMORY;
1668         unix_name->MaximumLength = size + 1;
1669
1670         SERVER_START_REQ( get_handle_unix_name )
1671         {
1672             req->handle = wine_server_obj_handle( handle );
1673             wine_server_set_reply( req, name, size );
1674             ret = wine_server_call( req );
1675             size = reply->name_len;
1676         }
1677         SERVER_END_REQ;
1678
1679         if (!ret)
1680         {
1681             name[size] = 0;
1682             unix_name->Buffer = name;
1683             unix_name->Length = size;
1684             break;
1685         }
1686         RtlFreeHeap( GetProcessHeap(), 0, name );
1687         if (ret != STATUS_BUFFER_OVERFLOW) break;
1688     }
1689     return ret;
1690 }
1691
1692 static NTSTATUS fill_name_info( const ANSI_STRING *unix_name, FILE_NAME_INFORMATION *info, LONG *name_len )
1693 {
1694     UNICODE_STRING nt_name;
1695     NTSTATUS status;
1696
1697     if (!(status = wine_unix_to_nt_file_name( unix_name, &nt_name )))
1698     {
1699         const WCHAR *ptr = nt_name.Buffer;
1700         const WCHAR *end = ptr + (nt_name.Length / sizeof(WCHAR));
1701
1702         /* Skip the volume mount point. */
1703         while (ptr != end && *ptr == '\\') ++ptr;
1704         while (ptr != end && *ptr != '\\') ++ptr;
1705         while (ptr != end && *ptr == '\\') ++ptr;
1706         while (ptr != end && *ptr != '\\') ++ptr;
1707
1708         info->FileNameLength = (end - ptr) * sizeof(WCHAR);
1709         if (*name_len < info->FileNameLength) status = STATUS_BUFFER_OVERFLOW;
1710         else *name_len = info->FileNameLength;
1711
1712         memcpy( info->FileName, ptr, *name_len );
1713         RtlFreeUnicodeString( &nt_name );
1714     }
1715
1716     return status;
1717 }
1718
1719 /******************************************************************************
1720  *  NtQueryInformationFile              [NTDLL.@]
1721  *  ZwQueryInformationFile              [NTDLL.@]
1722  *
1723  * Get information about an open file handle.
1724  *
1725  * PARAMS
1726  *  hFile    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1727  *  io       [O] Receives information about the operation on return
1728  *  ptr      [O] Destination for file information
1729  *  len      [I] Size of FileInformation
1730  *  class    [I] Type of file information to get
1731  *
1732  * RETURNS
1733  *  Success: 0. IoStatusBlock and FileInformation are updated.
1734  *  Failure: An NTSTATUS error code describing the error.
1735  */
1736 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
1737                                         PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
1738 {
1739     static const size_t info_sizes[] =
1740     {
1741         0,
1742         sizeof(FILE_DIRECTORY_INFORMATION),            /* FileDirectoryInformation */
1743         sizeof(FILE_FULL_DIRECTORY_INFORMATION),       /* FileFullDirectoryInformation */
1744         sizeof(FILE_BOTH_DIRECTORY_INFORMATION),       /* FileBothDirectoryInformation */
1745         sizeof(FILE_BASIC_INFORMATION),                /* FileBasicInformation */
1746         sizeof(FILE_STANDARD_INFORMATION),             /* FileStandardInformation */
1747         sizeof(FILE_INTERNAL_INFORMATION),             /* FileInternalInformation */
1748         sizeof(FILE_EA_INFORMATION),                   /* FileEaInformation */
1749         sizeof(FILE_ACCESS_INFORMATION),               /* FileAccessInformation */
1750         sizeof(FILE_NAME_INFORMATION),                 /* FileNameInformation */
1751         sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
1752         0,                                             /* FileLinkInformation */
1753         sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR),  /* FileNamesInformation */
1754         sizeof(FILE_DISPOSITION_INFORMATION),          /* FileDispositionInformation */
1755         sizeof(FILE_POSITION_INFORMATION),             /* FilePositionInformation */
1756         sizeof(FILE_FULL_EA_INFORMATION),              /* FileFullEaInformation */
1757         sizeof(FILE_MODE_INFORMATION),                 /* FileModeInformation */
1758         sizeof(FILE_ALIGNMENT_INFORMATION),            /* FileAlignmentInformation */
1759         sizeof(FILE_ALL_INFORMATION),                  /* FileAllInformation */
1760         sizeof(FILE_ALLOCATION_INFORMATION),           /* FileAllocationInformation */
1761         sizeof(FILE_END_OF_FILE_INFORMATION),          /* FileEndOfFileInformation */
1762         0,                                             /* FileAlternateNameInformation */
1763         sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
1764         0,                                             /* FilePipeInformation */
1765         sizeof(FILE_PIPE_LOCAL_INFORMATION),           /* FilePipeLocalInformation */
1766         0,                                             /* FilePipeRemoteInformation */
1767         sizeof(FILE_MAILSLOT_QUERY_INFORMATION),       /* FileMailslotQueryInformation */
1768         0,                                             /* FileMailslotSetInformation */
1769         0,                                             /* FileCompressionInformation */
1770         0,                                             /* FileObjectIdInformation */
1771         0,                                             /* FileCompletionInformation */
1772         0,                                             /* FileMoveClusterInformation */
1773         0,                                             /* FileQuotaInformation */
1774         0,                                             /* FileReparsePointInformation */
1775         0,                                             /* FileNetworkOpenInformation */
1776         0,                                             /* FileAttributeTagInformation */
1777         0,                                             /* FileTrackingInformation */
1778         0,                                             /* FileIdBothDirectoryInformation */
1779         0,                                             /* FileIdFullDirectoryInformation */
1780         0,                                             /* FileValidDataLengthInformation */
1781         0,                                             /* FileShortNameInformation */
1782         0,
1783         0,
1784         0,
1785         0,                                             /* FileSfioReserveInformation */
1786         0,                                             /* FileSfioVolumeInformation */
1787         0,                                             /* FileHardLinkInformation */
1788         0,
1789         0,                                             /* FileNormalizedNameInformation */
1790         0,
1791         0,                                             /* FileIdGlobalTxDirectoryInformation */
1792         0,
1793         0,
1794         0,
1795         0                                              /* FileStandardLinkInformation */
1796     };
1797
1798     struct stat st;
1799     int fd, needs_close = FALSE;
1800
1801     TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
1802
1803     io->Information = 0;
1804
1805     if (class <= 0 || class >= FileMaximumInformation)
1806         return io->u.Status = STATUS_INVALID_INFO_CLASS;
1807     if (!info_sizes[class])
1808     {
1809         FIXME("Unsupported class (%d)\n", class);
1810         return io->u.Status = STATUS_NOT_IMPLEMENTED;
1811     }
1812     if (len < info_sizes[class])
1813         return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
1814
1815     if (class != FilePipeLocalInformation)
1816     {
1817         if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, NULL )))
1818             return io->u.Status;
1819     }
1820
1821     switch (class)
1822     {
1823     case FileBasicInformation:
1824         if (fstat( fd, &st ) == -1)
1825             io->u.Status = FILE_GetNtStatus();
1826         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1827             io->u.Status = STATUS_INVALID_INFO_CLASS;
1828         else
1829             fill_stat_info( &st, ptr, class );
1830         break;
1831     case FileStandardInformation:
1832         {
1833             FILE_STANDARD_INFORMATION *info = ptr;
1834
1835             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1836             else
1837             {
1838                 fill_stat_info( &st, info, class );
1839                 info->DeletePending = FALSE; /* FIXME */
1840             }
1841         }
1842         break;
1843     case FilePositionInformation:
1844         {
1845             FILE_POSITION_INFORMATION *info = ptr;
1846             off_t res = lseek( fd, 0, SEEK_CUR );
1847             if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
1848             else info->CurrentByteOffset.QuadPart = res;
1849         }
1850         break;
1851     case FileInternalInformation:
1852         if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1853         else fill_stat_info( &st, ptr, class );
1854         break;
1855     case FileEaInformation:
1856         {
1857             FILE_EA_INFORMATION *info = ptr;
1858             info->EaSize = 0;
1859         }
1860         break;
1861     case FileEndOfFileInformation:
1862         if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1863         else fill_stat_info( &st, ptr, class );
1864         break;
1865     case FileAllInformation:
1866         {
1867             FILE_ALL_INFORMATION *info = ptr;
1868             ANSI_STRING unix_name;
1869
1870             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1871             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1872                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1873             else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
1874             {
1875                 LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
1876
1877                 fill_stat_info( &st, info, FileAllInformation );
1878                 info->StandardInformation.DeletePending = FALSE; /* FIXME */
1879                 info->EaInformation.EaSize = 0;
1880                 info->AccessInformation.AccessFlags = 0;  /* FIXME */
1881                 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
1882                 info->ModeInformation.Mode = 0;  /* FIXME */
1883                 info->AlignmentInformation.AlignmentRequirement = 1;  /* FIXME */
1884
1885                 io->u.Status = fill_name_info( &unix_name, &info->NameInformation, &name_len );
1886                 RtlFreeAnsiString( &unix_name );
1887                 io->Information = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + name_len;
1888             }
1889         }
1890         break;
1891     case FileMailslotQueryInformation:
1892         {
1893             FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
1894
1895             SERVER_START_REQ( set_mailslot_info )
1896             {
1897                 req->handle = wine_server_obj_handle( hFile );
1898                 req->flags = 0;
1899                 io->u.Status = wine_server_call( req );
1900                 if( io->u.Status == STATUS_SUCCESS )
1901                 {
1902                     info->MaximumMessageSize = reply->max_msgsize;
1903                     info->MailslotQuota = 0;
1904                     info->NextMessageSize = 0;
1905                     info->MessagesAvailable = 0;
1906                     info->ReadTimeout.QuadPart = reply->read_timeout;
1907                 }
1908             }
1909             SERVER_END_REQ;
1910             if (!io->u.Status)
1911             {
1912                 char *tmpbuf;
1913                 ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000;
1914                 if (size > 0x10000) size = 0x10000;
1915                 if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
1916                 {
1917                     int fd, needs_close;
1918                     if (!server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
1919                     {
1920                         int res = recv( fd, tmpbuf, size, MSG_PEEK );
1921                         info->MessagesAvailable = (res > 0);
1922                         info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE;
1923                         if (needs_close) close( fd );
1924                     }
1925                     RtlFreeHeap( GetProcessHeap(), 0, tmpbuf );
1926                 }
1927             }
1928         }
1929         break;
1930     case FilePipeLocalInformation:
1931         {
1932             FILE_PIPE_LOCAL_INFORMATION* pli = ptr;
1933
1934             SERVER_START_REQ( get_named_pipe_info )
1935             {
1936                 req->handle = wine_server_obj_handle( hFile );
1937                 if (!(io->u.Status = wine_server_call( req )))
1938                 {
1939                     pli->NamedPipeType = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ? 
1940                         FILE_PIPE_TYPE_MESSAGE : FILE_PIPE_TYPE_BYTE;
1941                     pli->NamedPipeConfiguration = 0; /* FIXME */
1942                     pli->MaximumInstances = reply->maxinstances;
1943                     pli->CurrentInstances = reply->instances;
1944                     pli->InboundQuota = reply->insize;
1945                     pli->ReadDataAvailable = 0; /* FIXME */
1946                     pli->OutboundQuota = reply->outsize;
1947                     pli->WriteQuotaAvailable = 0; /* FIXME */
1948                     pli->NamedPipeState = 0; /* FIXME */
1949                     pli->NamedPipeEnd = (reply->flags & NAMED_PIPE_SERVER_END) ?
1950                         FILE_PIPE_SERVER_END : FILE_PIPE_CLIENT_END;
1951                 }
1952             }
1953             SERVER_END_REQ;
1954         }
1955         break;
1956     case FileNameInformation:
1957         {
1958             FILE_NAME_INFORMATION *info = ptr;
1959             ANSI_STRING unix_name;
1960
1961             if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
1962             {
1963                 LONG name_len = len - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
1964                 io->u.Status = fill_name_info( &unix_name, info, &name_len );
1965                 RtlFreeAnsiString( &unix_name );
1966                 io->Information = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + name_len;
1967             }
1968         }
1969         break;
1970     default:
1971         FIXME("Unsupported class (%d)\n", class);
1972         io->u.Status = STATUS_NOT_IMPLEMENTED;
1973         break;
1974     }
1975     if (needs_close) close( fd );
1976     if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
1977     return io->u.Status;
1978 }
1979
1980 /******************************************************************************
1981  *  NtSetInformationFile                [NTDLL.@]
1982  *  ZwSetInformationFile                [NTDLL.@]
1983  *
1984  * Set information about an open file handle.
1985  *
1986  * PARAMS
1987  *  handle  [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1988  *  io      [O] Receives information about the operation on return
1989  *  ptr     [I] Source for file information
1990  *  len     [I] Size of FileInformation
1991  *  class   [I] Type of file information to set
1992  *
1993  * RETURNS
1994  *  Success: 0. io is updated.
1995  *  Failure: An NTSTATUS error code describing the error.
1996  */
1997 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
1998                                      PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
1999 {
2000     int fd, needs_close;
2001
2002     TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", handle, io, ptr, len, class);
2003
2004     io->u.Status = STATUS_SUCCESS;
2005     switch (class)
2006     {
2007     case FileBasicInformation:
2008         if (len >= sizeof(FILE_BASIC_INFORMATION))
2009         {
2010             struct stat st;
2011             const FILE_BASIC_INFORMATION *info = ptr;
2012
2013             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2014                 return io->u.Status;
2015
2016             if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
2017             {
2018                 struct timeval tv[2];
2019
2020                 if (!info->LastAccessTime.QuadPart || !info->LastWriteTime.QuadPart)
2021                 {
2022
2023                     tv[0].tv_sec = tv[0].tv_usec = 0;
2024                     tv[1].tv_sec = tv[1].tv_usec = 0;
2025                     if (!fstat( fd, &st ))
2026                     {
2027                         tv[0].tv_sec = st.st_atime;
2028                         tv[1].tv_sec = st.st_mtime;
2029                     }
2030                 }
2031                 if (info->LastAccessTime.QuadPart)
2032                 {
2033                     ULONGLONG sec = info->LastAccessTime.QuadPart / 10000000;
2034                     UINT nsec = info->LastAccessTime.QuadPart % 10000000;
2035                     tv[0].tv_sec = sec - SECS_1601_TO_1970;
2036                     tv[0].tv_usec = nsec / 10;
2037                 }
2038                 if (info->LastWriteTime.QuadPart)
2039                 {
2040                     ULONGLONG sec = info->LastWriteTime.QuadPart / 10000000;
2041                     UINT nsec = info->LastWriteTime.QuadPart % 10000000;
2042                     tv[1].tv_sec = sec - SECS_1601_TO_1970;
2043                     tv[1].tv_usec = nsec / 10;
2044                 }
2045                 if (futimes( fd, tv ) == -1) io->u.Status = FILE_GetNtStatus();
2046             }
2047
2048             if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
2049             {
2050                 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2051                 else
2052                 {
2053                     if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
2054                     {
2055                         if (S_ISDIR( st.st_mode))
2056                             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
2057                         else
2058                             st.st_mode &= ~0222; /* clear write permission bits */
2059                     }
2060                     else
2061                     {
2062                         /* add write permission only where we already have read permission */
2063                         st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
2064                     }
2065                     if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
2066                 }
2067             }
2068
2069             if (needs_close) close( fd );
2070         }
2071         else io->u.Status = STATUS_INVALID_PARAMETER_3;
2072         break;
2073
2074     case FilePositionInformation:
2075         if (len >= sizeof(FILE_POSITION_INFORMATION))
2076         {
2077             const FILE_POSITION_INFORMATION *info = ptr;
2078
2079             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2080                 return io->u.Status;
2081
2082             if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
2083                 io->u.Status = FILE_GetNtStatus();
2084
2085             if (needs_close) close( fd );
2086         }
2087         else io->u.Status = STATUS_INVALID_PARAMETER_3;
2088         break;
2089
2090     case FileEndOfFileInformation:
2091         if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
2092         {
2093             struct stat st;
2094             const FILE_END_OF_FILE_INFORMATION *info = ptr;
2095
2096             if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2097                 return io->u.Status;
2098
2099             /* first try normal truncate */
2100             if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2101
2102             /* now check for the need to extend the file */
2103             if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
2104             {
2105                 static const char zero;
2106
2107                 /* extend the file one byte beyond the requested size and then truncate it */
2108                 /* this should work around ftruncate implementations that can't extend files */
2109                 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
2110                     ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2111             }
2112             io->u.Status = FILE_GetNtStatus();
2113
2114             if (needs_close) close( fd );
2115         }
2116         else io->u.Status = STATUS_INVALID_PARAMETER_3;
2117         break;
2118
2119     case FileMailslotSetInformation:
2120         {
2121             FILE_MAILSLOT_SET_INFORMATION *info = ptr;
2122
2123             SERVER_START_REQ( set_mailslot_info )
2124             {
2125                 req->handle = wine_server_obj_handle( handle );
2126                 req->flags = MAILSLOT_SET_READ_TIMEOUT;
2127                 req->read_timeout = info->ReadTimeout.QuadPart;
2128                 io->u.Status = wine_server_call( req );
2129             }
2130             SERVER_END_REQ;
2131         }
2132         break;
2133
2134     case FileCompletionInformation:
2135         if (len >= sizeof(FILE_COMPLETION_INFORMATION))
2136         {
2137             FILE_COMPLETION_INFORMATION *info = ptr;
2138
2139             SERVER_START_REQ( set_completion_info )
2140             {
2141                 req->handle   = wine_server_obj_handle( handle );
2142                 req->chandle  = wine_server_obj_handle( info->CompletionPort );
2143                 req->ckey     = info->CompletionKey;
2144                 io->u.Status  = wine_server_call( req );
2145             }
2146             SERVER_END_REQ;
2147         } else
2148             io->u.Status = STATUS_INVALID_PARAMETER_3;
2149         break;
2150
2151     case FileAllInformation:
2152         io->u.Status = STATUS_INVALID_INFO_CLASS;
2153         break;
2154
2155     default:
2156         FIXME("Unsupported class (%d)\n", class);
2157         io->u.Status = STATUS_NOT_IMPLEMENTED;
2158         break;
2159     }
2160     io->Information = 0;
2161     return io->u.Status;
2162 }
2163
2164
2165 /******************************************************************************
2166  *              NtQueryFullAttributesFile   (NTDLL.@)
2167  */
2168 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
2169                                            FILE_NETWORK_OPEN_INFORMATION *info )
2170 {
2171     ANSI_STRING unix_name;
2172     NTSTATUS status;
2173
2174     if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2175     {
2176         struct stat st;
2177
2178         if (stat( unix_name.Buffer, &st ) == -1)
2179             status = FILE_GetNtStatus();
2180         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2181             status = STATUS_INVALID_INFO_CLASS;
2182         else
2183         {
2184             FILE_BASIC_INFORMATION basic;
2185             FILE_STANDARD_INFORMATION std;
2186
2187             fill_stat_info( &st, &basic, FileBasicInformation );
2188             fill_stat_info( &st, &std, FileStandardInformation );
2189
2190             info->CreationTime   = basic.CreationTime;
2191             info->LastAccessTime = basic.LastAccessTime;
2192             info->LastWriteTime  = basic.LastWriteTime;
2193             info->ChangeTime     = basic.ChangeTime;
2194             info->AllocationSize = std.AllocationSize;
2195             info->EndOfFile      = std.EndOfFile;
2196             info->FileAttributes = basic.FileAttributes;
2197             if (DIR_is_hidden_file( attr->ObjectName ))
2198                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2199         }
2200         RtlFreeAnsiString( &unix_name );
2201     }
2202     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2203     return status;
2204 }
2205
2206
2207 /******************************************************************************
2208  *              NtQueryAttributesFile   (NTDLL.@)
2209  *              ZwQueryAttributesFile   (NTDLL.@)
2210  */
2211 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
2212 {
2213     ANSI_STRING unix_name;
2214     NTSTATUS status;
2215
2216     if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2217     {
2218         struct stat st;
2219
2220         if (stat( unix_name.Buffer, &st ) == -1)
2221             status = FILE_GetNtStatus();
2222         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2223             status = STATUS_INVALID_INFO_CLASS;
2224         else
2225         {
2226             status = fill_stat_info( &st, info, FileBasicInformation );
2227             if (DIR_is_hidden_file( attr->ObjectName ))
2228                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2229         }
2230         RtlFreeAnsiString( &unix_name );
2231     }
2232     else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2233     return status;
2234 }
2235
2236
2237 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
2238 /* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */
2239 static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename,
2240                                             unsigned int flags )
2241 {
2242     if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename))
2243     {
2244         info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2245         /* Don't assume read-only, let the mount options set it below */
2246         info->Characteristics |= FILE_REMOVABLE_MEDIA;
2247     }
2248     else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) ||
2249              !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename))
2250     {
2251         info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2252         info->Characteristics |= FILE_REMOTE_DEVICE;
2253     }
2254     else if (!strcmp("procfs", fstypename))
2255         info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2256     else
2257         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2258
2259     if (flags & MNT_RDONLY)
2260         info->Characteristics |= FILE_READ_ONLY_DEVICE;
2261
2262     if (!(flags & MNT_LOCAL))
2263     {
2264         info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2265         info->Characteristics |= FILE_REMOTE_DEVICE;
2266     }
2267 }
2268 #endif
2269
2270 static inline int is_device_placeholder( int fd )
2271 {
2272     static const char wine_placeholder[] = "Wine device placeholder";
2273     char buffer[sizeof(wine_placeholder)-1];
2274
2275     if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
2276         return 0;
2277     return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
2278 }
2279
2280 /******************************************************************************
2281  *              get_device_info
2282  *
2283  * Implementation of the FileFsDeviceInformation query for NtQueryVolumeInformationFile.
2284  */
2285 static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
2286 {
2287     struct stat st;
2288
2289     info->Characteristics = 0;
2290     if (fstat( fd, &st ) < 0) return FILE_GetNtStatus();
2291     if (S_ISCHR( st.st_mode ))
2292     {
2293         info->DeviceType = FILE_DEVICE_UNKNOWN;
2294 #ifdef linux
2295         switch(major(st.st_rdev))
2296         {
2297         case MEM_MAJOR:
2298             info->DeviceType = FILE_DEVICE_NULL;
2299             break;
2300         case TTY_MAJOR:
2301             info->DeviceType = FILE_DEVICE_SERIAL_PORT;
2302             break;
2303         case LP_MAJOR:
2304             info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
2305             break;
2306         case SCSI_TAPE_MAJOR:
2307             info->DeviceType = FILE_DEVICE_TAPE;
2308             break;
2309         }
2310 #endif
2311     }
2312     else if (S_ISBLK( st.st_mode ))
2313     {
2314         info->DeviceType = FILE_DEVICE_DISK;
2315     }
2316     else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
2317     {
2318         info->DeviceType = FILE_DEVICE_NAMED_PIPE;
2319     }
2320     else if (is_device_placeholder( fd ))
2321     {
2322         info->DeviceType = FILE_DEVICE_DISK;
2323     }
2324     else  /* regular file or directory */
2325     {
2326 #if defined(linux) && defined(HAVE_FSTATFS)
2327         struct statfs stfs;
2328
2329         /* check for floppy disk */
2330         if (major(st.st_dev) == FLOPPY_MAJOR)
2331             info->Characteristics |= FILE_REMOVABLE_MEDIA;
2332
2333         if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
2334         switch (stfs.f_type)
2335         {
2336         case 0x9660:      /* iso9660 */
2337         case 0x9fa1:      /* supermount */
2338         case 0x15013346:  /* udf */
2339             info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2340             info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2341             break;
2342         case 0x6969:  /* nfs */
2343         case 0x517B:  /* smbfs */
2344         case 0x564c:  /* ncpfs */
2345             info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2346             info->Characteristics |= FILE_REMOTE_DEVICE;
2347             break;
2348         case 0x01021994:  /* tmpfs */
2349         case 0x28cd3d45:  /* cramfs */
2350         case 0x1373:      /* devfs */
2351         case 0x9fa0:      /* procfs */
2352             info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2353             break;
2354         default:
2355             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2356             break;
2357         }
2358 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__APPLE__)
2359         struct statfs stfs;
2360
2361         if (fstatfs( fd, &stfs ) < 0)
2362             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2363         else
2364             get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags );
2365 #elif defined(__NetBSD__)
2366         struct statvfs stfs;
2367
2368         if (fstatvfs( fd, &stfs) < 0)
2369             info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2370         else
2371             get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag );
2372 #elif defined(sun)
2373         /* Use dkio to work out device types */
2374         {
2375 # include <sys/dkio.h>
2376 # include <sys/vtoc.h>
2377             struct dk_cinfo dkinf;
2378             int retval = ioctl(fd, DKIOCINFO, &dkinf);
2379             if(retval==-1){
2380                 WARN("Unable to get disk device type information - assuming a disk like device\n");
2381                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2382             }
2383             switch (dkinf.dki_ctype)
2384             {
2385             case DKC_CDROM:
2386                 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2387                 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2388                 break;
2389             case DKC_NCRFLOPPY:
2390             case DKC_SMSFLOPPY:
2391             case DKC_INTEL82072:
2392             case DKC_INTEL82077:
2393                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2394                 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2395                 break;
2396             case DKC_MD:
2397                 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2398                 break;
2399             default:
2400                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2401             }
2402         }
2403 #else
2404         static int warned;
2405         if (!warned++) FIXME( "device info not properly supported on this platform\n" );
2406         info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2407 #endif
2408         info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
2409     }
2410     return STATUS_SUCCESS;
2411 }
2412
2413
2414 /******************************************************************************
2415  *  NtQueryVolumeInformationFile                [NTDLL.@]
2416  *  ZwQueryVolumeInformationFile                [NTDLL.@]
2417  *
2418  * Get volume information for an open file handle.
2419  *
2420  * PARAMS
2421  *  handle      [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2422  *  io          [O] Receives information about the operation on return
2423  *  buffer      [O] Destination for volume information
2424  *  length      [I] Size of FsInformation
2425  *  info_class  [I] Type of volume information to set
2426  *
2427  * RETURNS
2428  *  Success: 0. io and buffer are updated.
2429  *  Failure: An NTSTATUS error code describing the error.
2430  */
2431 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
2432                                               PVOID buffer, ULONG length,
2433                                               FS_INFORMATION_CLASS info_class )
2434 {
2435     int fd, needs_close;
2436     struct stat st;
2437     static int once;
2438
2439     if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
2440         return io->u.Status;
2441
2442     io->u.Status = STATUS_NOT_IMPLEMENTED;
2443     io->Information = 0;
2444
2445     switch( info_class )
2446     {
2447     case FileFsVolumeInformation:
2448         if (!once++) FIXME( "%p: volume info not supported\n", handle );
2449         break;
2450     case FileFsLabelInformation:
2451         FIXME( "%p: label info not supported\n", handle );
2452         break;
2453     case FileFsSizeInformation:
2454         if (length < sizeof(FILE_FS_SIZE_INFORMATION))
2455             io->u.Status = STATUS_BUFFER_TOO_SMALL;
2456         else
2457         {
2458             FILE_FS_SIZE_INFORMATION *info = buffer;
2459
2460             if (fstat( fd, &st ) < 0)
2461             {
2462                 io->u.Status = FILE_GetNtStatus();
2463                 break;
2464             }
2465             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2466             {
2467                 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
2468             }
2469             else
2470             {
2471                 ULONGLONG bsize;
2472                 /* Linux's fstatvfs is buggy */
2473 #if !defined(linux) || !defined(HAVE_FSTATFS)
2474                 struct statvfs stfs;
2475
2476                 if (fstatvfs( fd, &stfs ) < 0)
2477                 {
2478                     io->u.Status = FILE_GetNtStatus();
2479                     break;
2480                 }
2481                 bsize = stfs.f_frsize;
2482 #else
2483                 struct statfs stfs;
2484                 if (fstatfs( fd, &stfs ) < 0)
2485                 {
2486                     io->u.Status = FILE_GetNtStatus();
2487                     break;
2488                 }
2489                 bsize = stfs.f_bsize;
2490 #endif
2491                 if (bsize == 2048)  /* assume CD-ROM */
2492                 {
2493                     info->BytesPerSector = 2048;
2494                     info->SectorsPerAllocationUnit = 1;
2495                 }
2496                 else
2497                 {
2498                     info->BytesPerSector = 512;
2499                     info->SectorsPerAllocationUnit = 8;
2500                 }
2501                 info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2502                 info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2503                 io->Information = sizeof(*info);
2504                 io->u.Status = STATUS_SUCCESS;
2505             }
2506         }
2507         break;
2508     case FileFsDeviceInformation:
2509         if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
2510             io->u.Status = STATUS_BUFFER_TOO_SMALL;
2511         else
2512         {
2513             FILE_FS_DEVICE_INFORMATION *info = buffer;
2514
2515             if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS)
2516                 io->Information = sizeof(*info);
2517         }
2518         break;
2519     case FileFsAttributeInformation:
2520         FIXME( "%p: attribute info not supported\n", handle );
2521         break;
2522     case FileFsControlInformation:
2523         FIXME( "%p: control info not supported\n", handle );
2524         break;
2525     case FileFsFullSizeInformation:
2526         FIXME( "%p: full size info not supported\n", handle );
2527         break;
2528     case FileFsObjectIdInformation:
2529         FIXME( "%p: object id info not supported\n", handle );
2530         break;
2531     case FileFsMaximumInformation:
2532         FIXME( "%p: maximum info not supported\n", handle );
2533         break;
2534     default:
2535         io->u.Status = STATUS_INVALID_PARAMETER;
2536         break;
2537     }
2538     if (needs_close) close( fd );
2539     return io->u.Status;
2540 }
2541
2542
2543 /******************************************************************
2544  *              NtQueryEaFile  (NTDLL.@)
2545  *
2546  * Read extended attributes from NTFS files.
2547  *
2548  * PARAMS
2549  *  hFile         [I] File handle, must be opened with FILE_READ_EA access
2550  *  iosb          [O] Receives information about the operation on return
2551  *  buffer        [O] Output buffer
2552  *  length        [I] Length of output buffer
2553  *  single_entry  [I] Only read and return one entry
2554  *  ea_list       [I] Optional list with names of EAs to return
2555  *  ea_list_len   [I] Length of ea_list in bytes
2556  *  ea_index      [I] Optional pointer to 1-based index of attribute to return
2557  *  restart       [I] restart EA scan
2558  *
2559  * RETURNS
2560  *  Success: 0. Atrributes read into buffer
2561  *  Failure: An NTSTATUS error code describing the error.
2562  */
2563 NTSTATUS WINAPI NtQueryEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length,
2564                                BOOLEAN single_entry, PVOID ea_list, ULONG ea_list_len,
2565                                PULONG ea_index, BOOLEAN restart )
2566 {
2567     FIXME("(%p,%p,%p,%d,%d,%p,%d,%p,%d) stub\n",
2568             hFile, iosb, buffer, length, single_entry, ea_list,
2569             ea_list_len, ea_index, restart);
2570     return STATUS_ACCESS_DENIED;
2571 }
2572
2573
2574 /******************************************************************
2575  *              NtSetEaFile  (NTDLL.@)
2576  *
2577  * Update extended attributes for NTFS files.
2578  *
2579  * PARAMS
2580  *  hFile         [I] File handle, must be opened with FILE_READ_EA access
2581  *  iosb          [O] Receives information about the operation on return
2582  *  buffer        [I] Buffer with EA information
2583  *  length        [I] Length of buffer
2584  *
2585  * RETURNS
2586  *  Success: 0. Attributes are updated
2587  *  Failure: An NTSTATUS error code describing the error.
2588  */
2589 NTSTATUS WINAPI NtSetEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length )
2590 {
2591     FIXME("(%p,%p,%p,%d) stub\n", hFile, iosb, buffer, length);
2592     return STATUS_ACCESS_DENIED;
2593 }
2594
2595
2596 /******************************************************************
2597  *              NtFlushBuffersFile  (NTDLL.@)
2598  *
2599  * Flush any buffered data on an open file handle.
2600  *
2601  * PARAMS
2602  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2603  *  IoStatusBlock      [O] Receives information about the operation on return
2604  *
2605  * RETURNS
2606  *  Success: 0. IoStatusBlock is updated.
2607  *  Failure: An NTSTATUS error code describing the error.
2608  */
2609 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
2610 {
2611     NTSTATUS ret;
2612     HANDLE hEvent = NULL;
2613
2614     SERVER_START_REQ( flush_file )
2615     {
2616         req->handle = wine_server_obj_handle( hFile );
2617         ret = wine_server_call( req );
2618         hEvent = wine_server_ptr_handle( reply->event );
2619     }
2620     SERVER_END_REQ;
2621     if (!ret && hEvent)
2622     {
2623         ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
2624         NtClose( hEvent );
2625     }
2626     return ret;
2627 }
2628
2629 /******************************************************************
2630  *              NtLockFile       (NTDLL.@)
2631  *
2632  *
2633  */
2634 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
2635                             PIO_APC_ROUTINE apc, void* apc_user,
2636                             PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
2637                             PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
2638                             BOOLEAN exclusive )
2639 {
2640     NTSTATUS    ret;
2641     HANDLE      handle;
2642     BOOLEAN     async;
2643     static BOOLEAN     warn = TRUE;
2644
2645     if (apc || io_status || key)
2646     {
2647         FIXME("Unimplemented yet parameter\n");
2648         return STATUS_NOT_IMPLEMENTED;
2649     }
2650
2651     if (apc_user && warn)
2652     {
2653         FIXME("I/O completion on lock not implemented yet\n");
2654         warn = FALSE;
2655     }
2656
2657     for (;;)
2658     {
2659         SERVER_START_REQ( lock_file )
2660         {
2661             req->handle      = wine_server_obj_handle( hFile );
2662             req->offset      = offset->QuadPart;
2663             req->count       = count->QuadPart;
2664             req->shared      = !exclusive;
2665             req->wait        = !dont_wait;
2666             ret = wine_server_call( req );
2667             handle = wine_server_ptr_handle( reply->handle );
2668             async  = reply->overlapped;
2669         }
2670         SERVER_END_REQ;
2671         if (ret != STATUS_PENDING)
2672         {
2673             if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
2674             return ret;
2675         }
2676
2677         if (async)
2678         {
2679             FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
2680             if (handle) NtClose( handle );
2681             return STATUS_PENDING;
2682         }
2683         if (handle)
2684         {
2685             NtWaitForSingleObject( handle, FALSE, NULL );
2686             NtClose( handle );
2687         }
2688         else
2689         {
2690             LARGE_INTEGER time;
2691     
2692             /* Unix lock conflict, sleep a bit and retry */
2693             time.QuadPart = 100 * (ULONGLONG)10000;
2694             time.QuadPart = -time.QuadPart;
2695             NtDelayExecution( FALSE, &time );
2696         }
2697     }
2698 }
2699
2700
2701 /******************************************************************
2702  *              NtUnlockFile    (NTDLL.@)
2703  *
2704  *
2705  */
2706 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
2707                               PLARGE_INTEGER offset, PLARGE_INTEGER count,
2708                               PULONG key )
2709 {
2710     NTSTATUS status;
2711
2712     TRACE( "%p %x%08x %x%08x\n",
2713            hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
2714
2715     if (io_status || key)
2716     {
2717         FIXME("Unimplemented yet parameter\n");
2718         return STATUS_NOT_IMPLEMENTED;
2719     }
2720
2721     SERVER_START_REQ( unlock_file )
2722     {
2723         req->handle = wine_server_obj_handle( hFile );
2724         req->offset = offset->QuadPart;
2725         req->count  = count->QuadPart;
2726         status = wine_server_call( req );
2727     }
2728     SERVER_END_REQ;
2729     return status;
2730 }
2731
2732 /******************************************************************
2733  *              NtCreateNamedPipeFile    (NTDLL.@)
2734  *
2735  *
2736  */
2737 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
2738                                        POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
2739                                        ULONG sharing, ULONG dispo, ULONG options,
2740                                        ULONG pipe_type, ULONG read_mode, 
2741                                        ULONG completion_mode, ULONG max_inst,
2742                                        ULONG inbound_quota, ULONG outbound_quota,
2743                                        PLARGE_INTEGER timeout)
2744 {
2745     NTSTATUS    status;
2746
2747     TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n",
2748           handle, access, debugstr_w(attr->ObjectName->Buffer), iosb, sharing, dispo,
2749           options, pipe_type, read_mode, completion_mode, max_inst, inbound_quota,
2750           outbound_quota, timeout);
2751
2752     /* assume we only get relative timeout */
2753     if (timeout->QuadPart > 0)
2754         FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
2755
2756     SERVER_START_REQ( create_named_pipe )
2757     {
2758         req->access  = access;
2759         req->attributes = attr->Attributes;
2760         req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2761         req->options = options;
2762         req->flags = 
2763             (pipe_type) ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0 |
2764             (read_mode) ? NAMED_PIPE_MESSAGE_STREAM_READ  : 0 |
2765             (completion_mode) ? NAMED_PIPE_NONBLOCKING_MODE  : 0;
2766         req->maxinstances = max_inst;
2767         req->outsize = outbound_quota;
2768         req->insize  = inbound_quota;
2769         req->timeout = timeout->QuadPart;
2770         wine_server_add_data( req, attr->ObjectName->Buffer,
2771                               attr->ObjectName->Length );
2772         status = wine_server_call( req );
2773         if (!status) *handle = wine_server_ptr_handle( reply->handle );
2774     }
2775     SERVER_END_REQ;
2776     return status;
2777 }
2778
2779 /******************************************************************
2780  *              NtDeleteFile    (NTDLL.@)
2781  *
2782  *
2783  */
2784 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
2785 {
2786     NTSTATUS status;
2787     HANDLE hFile;
2788     IO_STATUS_BLOCK io;
2789
2790     TRACE("%p\n", ObjectAttributes);
2791     status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE | DELETE,
2792                            ObjectAttributes, &io, NULL, 0,
2793                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
2794                            FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
2795     if (status == STATUS_SUCCESS) status = NtClose(hFile);
2796     return status;
2797 }
2798
2799 /******************************************************************
2800  *              NtCancelIoFileEx    (NTDLL.@)
2801  *
2802  *
2803  */
2804 NTSTATUS WINAPI NtCancelIoFileEx( HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status )
2805 {
2806     LARGE_INTEGER timeout;
2807
2808     TRACE("%p %p %p\n", hFile, iosb, io_status );
2809
2810     SERVER_START_REQ( cancel_async )
2811     {
2812         req->handle      = wine_server_obj_handle( hFile );
2813         req->iosb        = wine_server_client_ptr( iosb );
2814         req->only_thread = FALSE;
2815         io_status->u.Status = wine_server_call( req );
2816     }
2817     SERVER_END_REQ;
2818     if (io_status->u.Status)
2819         return io_status->u.Status;
2820
2821     /* Let some APC be run, so that we can run the remaining APCs on hFile
2822      * either the cancelation of the pending one, but also the execution
2823      * of the queued APC, but not yet run. This is needed to ensure proper
2824      * clean-up of allocated data.
2825      */
2826     timeout.u.LowPart = timeout.u.HighPart = 0;
2827     NtDelayExecution( TRUE, &timeout );
2828     return io_status->u.Status;
2829 }
2830
2831 /******************************************************************
2832  *              NtCancelIoFile    (NTDLL.@)
2833  *
2834  *
2835  */
2836 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
2837 {
2838     LARGE_INTEGER timeout;
2839
2840     TRACE("%p %p\n", hFile, io_status );
2841
2842     SERVER_START_REQ( cancel_async )
2843     {
2844         req->handle      = wine_server_obj_handle( hFile );
2845         req->iosb        = 0;
2846         req->only_thread = TRUE;
2847         io_status->u.Status = wine_server_call( req );
2848     }
2849     SERVER_END_REQ;
2850     if (io_status->u.Status)
2851         return io_status->u.Status;
2852
2853     /* Let some APC be run, so that we can run the remaining APCs on hFile
2854      * either the cancelation of the pending one, but also the execution
2855      * of the queued APC, but not yet run. This is needed to ensure proper
2856      * clean-up of allocated data.
2857      */
2858     timeout.u.LowPart = timeout.u.HighPart = 0;
2859     NtDelayExecution( TRUE, &timeout );
2860     return io_status->u.Status;
2861 }
2862
2863 /******************************************************************************
2864  *  NtCreateMailslotFile        [NTDLL.@]
2865  *  ZwCreateMailslotFile        [NTDLL.@]
2866  *
2867  * PARAMS
2868  *  pHandle          [O] pointer to receive the handle created
2869  *  DesiredAccess    [I] access mode (read, write, etc)
2870  *  ObjectAttributes [I] fully qualified NT path of the mailslot
2871  *  IoStatusBlock    [O] receives completion status and other info
2872  *  CreateOptions    [I]
2873  *  MailslotQuota    [I]
2874  *  MaxMessageSize   [I]
2875  *  TimeOut          [I]
2876  *
2877  * RETURNS
2878  *  An NT status code
2879  */
2880 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
2881      POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
2882      ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
2883      PLARGE_INTEGER TimeOut)
2884 {
2885     LARGE_INTEGER timeout;
2886     NTSTATUS ret;
2887
2888     TRACE("%p %08x %p %p %08x %08x %08x %p\n",
2889               pHandle, DesiredAccess, attr, IoStatusBlock,
2890               CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
2891
2892     if (!pHandle) return STATUS_ACCESS_VIOLATION;
2893     if (!attr) return STATUS_INVALID_PARAMETER;
2894     if (!attr->ObjectName) return STATUS_OBJECT_PATH_SYNTAX_BAD;
2895
2896     /*
2897      *  For a NULL TimeOut pointer set the default timeout value
2898      */
2899     if  (!TimeOut)
2900         timeout.QuadPart = -1;
2901     else
2902         timeout.QuadPart = TimeOut->QuadPart;
2903
2904     SERVER_START_REQ( create_mailslot )
2905     {
2906         req->access = DesiredAccess;
2907         req->attributes = attr->Attributes;
2908         req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2909         req->max_msgsize = MaxMessageSize;
2910         req->read_timeout = timeout.QuadPart;
2911         wine_server_add_data( req, attr->ObjectName->Buffer,
2912                               attr->ObjectName->Length );
2913         ret = wine_server_call( req );
2914         if( ret == STATUS_SUCCESS )
2915             *pHandle = wine_server_ptr_handle( reply->handle );
2916     }
2917     SERVER_END_REQ;
2918  
2919     return ret;
2920 }