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