Only ignore certain keyboard events if a XLookupString returned a
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38 #include "wine/server.h"
39 #include "async.h"
40 #include "ntdll_misc.h"
41 #include "file.h" /* FIXME */
42 #include "../files/smb.h"
43
44 #include "winternl.h"
45 #include "winioctl.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
48
49 /**************************************************************************
50  *                 NtOpenFile                           [NTDLL.@]
51  *                 ZwOpenFile                           [NTDLL.@]
52  *
53  * Open a file.
54  *
55  * PARAMS
56  *  FileHandle       [O] Variable that receives the file handle on return
57  *  DesiredAccess    [I] Access desired by the caller to the file
58  *  ObjectAttributes [I] Structue describing the file to be opened
59  *  IoStatusBlock    [O] Receives details about the result of the operation
60  *  ShareAccess      [I] Type of shared access the caller requires
61  *  OpenOptions      [I] Options for the file open
62  *
63  * RETURNS
64  *  Success: 0. FileHandle and IoStatusBlock are updated.
65  *  Failure: An NTSTATUS error code describing the error.
66  */
67 NTSTATUS WINAPI NtOpenFile(
68         OUT PHANDLE FileHandle,
69         ACCESS_MASK DesiredAccess,
70         POBJECT_ATTRIBUTES ObjectAttributes,
71         OUT PIO_STATUS_BLOCK IoStatusBlock,
72         ULONG ShareAccess,
73         ULONG OpenOptions)
74 {
75         LPWSTR filename;
76         static const WCHAR szDosDevices[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0};
77         DOS_FULL_NAME full_name;
78         NTSTATUS r;
79
80         FIXME("(%p,0x%08lx,%p,%p,0x%08lx,0x%08lx) partial stub\n",
81                 FileHandle, DesiredAccess, ObjectAttributes,
82                 IoStatusBlock, ShareAccess, OpenOptions);
83
84         dump_ObjectAttributes (ObjectAttributes);
85
86         if(ObjectAttributes->RootDirectory)
87         {
88                 FIXME("Object root directory unknown %p\n",
89                         ObjectAttributes->RootDirectory);
90                 return STATUS_OBJECT_NAME_NOT_FOUND;
91         }
92
93         filename = ObjectAttributes->ObjectName->Buffer;
94
95         /* FIXME: DOSFS stuff should call here, not vice-versa */
96         if(strncmpW(filename, szDosDevices, strlenW(szDosDevices)))
97                 return STATUS_OBJECT_NAME_NOT_FOUND;
98
99         /* FIXME: this calls SetLastError() -> bad */
100         if(!DOSFS_GetFullName(&filename[strlenW(szDosDevices)], TRUE,
101                                 &full_name))
102                 return STATUS_OBJECT_NAME_NOT_FOUND;
103
104         /* FIXME: modify server protocol so
105                   create file takes an OBJECT_ATTRIBUTES structure */
106         SERVER_START_REQ( create_file )
107         {
108             req->access     = DesiredAccess;
109             req->inherit    = 0;
110             req->sharing    = ShareAccess;
111             req->create     = OPEN_EXISTING;
112             req->attrs      = 0;
113             req->drive_type = GetDriveTypeW( full_name.short_name );
114             wine_server_add_data( req, full_name.long_name, strlen(full_name.long_name) );
115             SetLastError(0);
116             r = wine_server_call( req );
117             *FileHandle = reply->handle;
118         }
119         SERVER_END_REQ;
120
121         return r;
122 }
123
124 /**************************************************************************
125  *              NtCreateFile                            [NTDLL.@]
126  *              ZwCreateFile                            [NTDLL.@]
127  *
128  * Either create a new file or directory, or open an existing file, device,
129  * directory or volume.
130  *
131  * PARAMS
132  *      FileHandle        [O] Points to a variable which receives the file handle on return
133  *      DesiredAccess     [I] Desired access to the file
134  *      ObjectAttributes  [I] Structure describing the file
135  *      IoStatusBlock     [O] Receives information about the operation on return
136  *      AllocationSize    [I] Initial size of the file in bytes
137  *      FileAttributes    [I] Attributes to create the file with
138  *      ShareAccess       [I] Type of shared access the caller would like to the file
139  *      CreateDisposition [I] Specifies what to do, depending on whether the file already exists
140  *      CreateOptions     [I] Options for creating a new file
141  *      EaBuffer          [I] Undocumented
142  *      EaLength          [I] Undocumented
143  *
144  * RETURNS
145  *  Success: 0. FileHandle and IoStatusBlock are updated.
146  *  Failure: An NTSTATUS error code describing the error.
147  */
148 NTSTATUS WINAPI NtCreateFile(
149         OUT PHANDLE FileHandle,
150         ACCESS_MASK DesiredAccess,
151         POBJECT_ATTRIBUTES ObjectAttributes,
152         OUT PIO_STATUS_BLOCK IoStatusBlock,
153         PLARGE_INTEGER AllocateSize,
154         ULONG FileAttributes,
155         ULONG ShareAccess,
156         ULONG CreateDisposition,
157         ULONG CreateOptions,
158         PVOID EaBuffer,
159         ULONG EaLength)
160 {
161         FIXME("(%p,0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx) stub\n",
162         FileHandle,DesiredAccess,ObjectAttributes,
163         IoStatusBlock,AllocateSize,FileAttributes,
164         ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
165         dump_ObjectAttributes (ObjectAttributes);
166         return 0;
167 }
168
169 /***********************************************************************
170  *                  Asynchronous file I/O                              *
171  */
172 static DWORD fileio_get_async_count(const async_private *ovp);
173 static void CALLBACK fileio_call_completion_func(ULONG_PTR data);
174 static void fileio_async_cleanup(async_private *ovp);
175
176 static async_ops fileio_async_ops =
177 {
178     fileio_get_async_count,        /* get_count */
179     fileio_call_completion_func,   /* call_completion */
180     fileio_async_cleanup           /* cleanup */
181 };
182
183 static async_ops fileio_nocomp_async_ops =
184 {
185     fileio_get_async_count,        /* get_count */
186     NULL,                          /* call_completion */
187     fileio_async_cleanup           /* cleanup */
188 };
189
190 typedef struct async_fileio
191 {
192     struct async_private             async;
193     PIO_APC_ROUTINE                  apc;
194     void*                            apc_user;
195     char                             *buffer;
196     unsigned int                     count;
197     unsigned long                    offset;
198     enum fd_type                     fd_type;
199 } async_fileio;
200
201 static DWORD fileio_get_async_count(const struct async_private *ovp)
202 {
203     async_fileio *fileio = (async_fileio*) ovp;
204
205     if (fileio->count < fileio->async.iosb->Information)
206         return 0;
207     return fileio->count - fileio->async.iosb->Information;
208 }
209
210 static void CALLBACK fileio_call_completion_func(ULONG_PTR data)
211 {
212     async_fileio *ovp = (async_fileio*) data;
213     TRACE("data: %p\n", ovp);
214
215     ovp->apc( ovp->apc_user, ovp->async.iosb, ovp->async.iosb->Information );
216
217     fileio_async_cleanup( &ovp->async );
218 }
219
220 static void fileio_async_cleanup( struct async_private *ovp )
221 {
222     RtlFreeHeap( ntdll_get_process_heap(), 0, ovp );
223 }
224
225 /***********************************************************************
226  *           FILE_GetUnixHandleType
227  *
228  * Retrieve the Unix handle corresponding to a file handle.
229  * Returns -1 on failure.
230  */
231 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr, int *fd )
232 {
233     int ret, flags;
234
235     *fd = -1;
236     ret = wine_server_handle_to_fd( handle, access, fd, type, &flags );
237     if (flags_ptr) *flags_ptr = flags;
238     if (!ret && (((access & GENERIC_READ)  && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
239                  ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN))))
240     {
241         close(*fd);
242         ret = STATUS_PIPE_DISCONNECTED;
243     }
244     return ret;
245 }
246
247 /***********************************************************************
248  *           FILE_GetNtStatus(void)
249  *
250  * Retrieve the Nt Status code from errno.
251  * Try to be consistent with FILE_SetDosError().
252  */
253 static DWORD FILE_GetNtStatus(void)
254 {
255     int err = errno;
256     DWORD nt;
257
258     TRACE( "errno = %d\n", errno );
259     switch (err)
260     {
261     case EAGAIN:       nt = STATUS_SHARING_VIOLATION;       break;
262     case EBADF:        nt = STATUS_INVALID_HANDLE;          break;
263     case ENOSPC:       nt = STATUS_DISK_FULL;               break;
264     case EPERM:
265     case EROFS:
266     case EACCES:       nt = STATUS_ACCESS_DENIED;           break;
267     case ENOENT:       nt = STATUS_SHARING_VIOLATION;       break;
268     case EISDIR:       nt = STATUS_FILE_IS_A_DIRECTORY;     break;
269     case EMFILE:
270     case ENFILE:       nt = STATUS_NO_MORE_FILES;           break;
271     case EINVAL:
272     case ENOTEMPTY:    nt = STATUS_DIRECTORY_NOT_EMPTY;     break;
273     case EPIPE:        nt = STATUS_PIPE_BROKEN;             break;
274     case ENOEXEC:      /* ?? */
275     case ESPIPE:       /* ?? */
276     case EEXIST:       /* ?? */
277     default:
278         FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
279         nt = STATUS_UNSUCCESSFUL;
280     }
281     return nt;
282 }
283
284 /***********************************************************************
285  *             FILE_AsyncReadService      (INTERNAL)
286  *
287  *  This function is called while the client is waiting on the
288  *  server, so we can't make any server calls here.
289  */
290 static void FILE_AsyncReadService(async_private *ovp)
291 {
292     async_fileio *fileio = (async_fileio*) ovp;
293     IO_STATUS_BLOCK*  io_status = fileio->async.iosb;
294     int result;
295     int already = io_status->Information;
296
297     TRACE("%p %p\n", io_status, fileio->buffer );
298
299     /* check to see if the data is ready (non-blocking) */
300
301     if ( fileio->fd_type == FD_TYPE_SOCKET )
302         result = read(ovp->fd, &fileio->buffer[already], fileio->count - already);
303     else
304     {
305         result = pread(ovp->fd, &fileio->buffer[already], fileio->count - already,
306                        fileio->offset + already);
307         if ((result < 0) && (errno == ESPIPE))
308             result = read(ovp->fd, &fileio->buffer[already], fileio->count - already);
309     }
310
311     if ((result < 0) && ((errno == EAGAIN) || (errno == EINTR)))
312     {
313         TRACE("Deferred read %d\n",errno);
314         io_status->u.Status = STATUS_PENDING;
315         return;
316     }
317
318     /* check to see if the transfer is complete */
319     if (result < 0)
320     {
321         io_status->u.Status = FILE_GetNtStatus();
322         return;
323     }
324     else if (result == 0)
325     {
326         io_status->u.Status = io_status->Information ? STATUS_SUCCESS : STATUS_END_OF_FILE;
327         return;
328     }
329
330     io_status->Information += result;
331     if (io_status->Information >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
332         io_status->u.Status = STATUS_SUCCESS;
333     else
334         io_status->u.Status = STATUS_PENDING;
335
336     TRACE("read %d more bytes %ld/%d so far\n",
337           result, io_status->Information, fileio->count);
338 }
339
340
341 /******************************************************************************
342  *  NtReadFile                                  [NTDLL.@]
343  *  ZwReadFile                                  [NTDLL.@]
344  *
345  * Read from an open file handle.
346  *
347  * PARAMS
348  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
349  *  Event         [I] Event to signal upon completion (or NULL)
350  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
351  *  ApcContext    [I] Context for ApcRoutine (or NULL)
352  *  IoStatusBlock [O] Receives information about the operation on return
353  *  Buffer        [O] Destination for the data read
354  *  Length        [I] Size of Buffer
355  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
356  *  Key           [O] Function unknown (may be NULL)
357  *
358  * RETURNS
359  *  Success: 0. IoStatusBlock is updated, and the Information member contains
360  *           The number of bytes read.
361  *  Failure: An NTSTATUS error code describing the error.
362  */
363 NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
364                            PIO_APC_ROUTINE apc, void* apc_user,
365                            PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
366                            PLARGE_INTEGER offset, PULONG key)
367 {
368     int unix_handle, flags;
369     enum fd_type type;
370
371     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n",
372           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
373
374     io_status->Information = 0;
375     io_status->u.Status = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags, &unix_handle );
376     if (io_status->u.Status) return io_status->u.Status;
377
378     if (flags & FD_FLAG_TIMEOUT)
379     {
380         if (hEvent)
381         {
382             /* this shouldn't happen, but check it */
383             FIXME("NIY-hEvent\n");
384             return STATUS_NOT_IMPLEMENTED;
385         }
386         io_status->u.Status = NtCreateEvent(&hEvent, SYNCHRONIZE, NULL, 0, 0);
387         if (io_status->u.Status) return io_status->u.Status;
388     }
389
390     if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
391     {
392         async_fileio*   ovp;
393         NTSTATUS ret;
394
395         if (unix_handle < 0) return STATUS_INVALID_HANDLE;
396
397         ovp = RtlAllocateHeap(ntdll_get_process_heap(), 0, sizeof(async_fileio));
398         if (!ovp) return STATUS_NO_MEMORY;
399
400         ovp->async.ops = (apc ? &fileio_async_ops : &fileio_nocomp_async_ops );
401         ovp->async.handle = hFile;
402         ovp->async.fd = unix_handle;
403         ovp->async.type = ASYNC_TYPE_READ;
404         ovp->async.func = FILE_AsyncReadService;
405         ovp->async.event = hEvent;
406         ovp->async.iosb = io_status;
407         ovp->count = length;
408         ovp->offset = offset->s.LowPart;
409         if (offset->s.HighPart) FIXME("NIY-high part\n");
410         ovp->apc = apc;
411         ovp->apc_user = apc_user;
412         ovp->buffer = buffer;
413         ovp->fd_type = type;
414
415         io_status->Information = 0;
416         ret = register_new_async(&ovp->async);
417         if (ret != STATUS_SUCCESS)
418             return ret;
419         if (flags & FD_FLAG_TIMEOUT)
420         {
421             NtWaitForSingleObject(hEvent, TRUE, NULL);
422             NtClose(hEvent);
423         }
424         else
425         {
426             LARGE_INTEGER   timeout;
427
428             /* let some APC be run, this will read some already pending data */
429             timeout.s.LowPart = timeout.s.HighPart = 0;
430             NtDelayExecution( TRUE, &timeout );
431         }
432         return io_status->u.Status;
433     }
434     switch (type)
435     {
436     case FD_TYPE_SMB:
437         FIXME("NIY-SMB\n");
438         close(unix_handle);
439         return SMB_ReadFile(hFile, buffer, length, io_status);
440
441     case FD_TYPE_DEFAULT:
442         /* normal unix files */
443         if (unix_handle == -1) return STATUS_INVALID_HANDLE;
444         break;
445
446     default:
447         FIXME("Unsupported type of fd %d\n", type);
448         if (unix_handle == -1) close(unix_handle);
449         return STATUS_INVALID_HANDLE;
450     }
451
452     if (offset)
453     {
454         FILE_POSITION_INFORMATION   fpi;
455
456         fpi.CurrentByteOffset = *offset;
457         io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi), 
458                                                    FilePositionInformation);
459         if (io_status->u.Status)
460         {
461             close(unix_handle);
462             return io_status->u.Status;
463         }
464     }
465     /* code for synchronous reads */
466     while ((io_status->Information = read( unix_handle, buffer, length )) == -1)
467     {
468         if ((errno == EAGAIN) || (errno == EINTR)) continue;
469         if (errno == EFAULT) FIXME( "EFAULT handling broken for now\n" );
470         io_status->u.Status = FILE_GetNtStatus();
471         break;
472     }
473     close( unix_handle );
474     return io_status->u.Status;
475 }
476
477 /***********************************************************************
478  *             FILE_AsyncWriteService      (INTERNAL)
479  *
480  *  This function is called while the client is waiting on the
481  *  server, so we can't make any server calls here.
482  */
483 static void FILE_AsyncWriteService(struct async_private *ovp)
484 {
485     async_fileio *fileio = (async_fileio *) ovp;
486     PIO_STATUS_BLOCK io_status = fileio->async.iosb;
487     int result;
488     int already = io_status->Information;
489
490     TRACE("(%p %p)\n",io_status,fileio->buffer);
491
492     /* write some data (non-blocking) */
493
494     if ( fileio->fd_type == FD_TYPE_SOCKET )
495         result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
496     else
497     {
498         result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
499                         fileio->offset + already);
500         if ((result < 0) && (errno == ESPIPE))
501             result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
502     }
503
504     if ((result < 0) && ((errno == EAGAIN) || (errno == EINTR)))
505     {
506         io_status->u.Status = STATUS_PENDING;
507         return;
508     }
509
510     /* check to see if the transfer is complete */
511     if (result < 0)
512     {
513         io_status->u.Status = FILE_GetNtStatus();
514         return;
515     }
516
517     io_status->Information += result;
518     io_status->u.Status = (io_status->Information < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
519     TRACE("wrote %d more bytes %ld/%d so far\n",result,io_status->Information,fileio->count);
520 }
521
522 /******************************************************************************
523  *  NtWriteFile                                 [NTDLL.@]
524  *  ZwWriteFile                                 [NTDLL.@]
525  *
526  * Write to an open file handle.
527  *
528  * PARAMS
529  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
530  *  Event         [I] Event to signal upon completion (or NULL)
531  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
532  *  ApcContext    [I] Context for ApcRoutine (or NULL)
533  *  IoStatusBlock [O] Receives information about the operation on return
534  *  Buffer        [I] Source for the data to write
535  *  Length        [I] Size of Buffer
536  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
537  *  Key           [O] Function unknown (may be NULL)
538  *
539  * RETURNS
540  *  Success: 0. IoStatusBlock is updated, and the Information member contains
541  *           The number of bytes written.
542  *  Failure: An NTSTATUS error code describing the error.
543  */
544 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
545                             PIO_APC_ROUTINE apc, void* apc_user,
546                             PIO_STATUS_BLOCK io_status, 
547                             const void* buffer, ULONG length,
548                             PLARGE_INTEGER offset, PULONG key)
549 {
550     int unix_handle, flags;
551     enum fd_type type;
552
553     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p)!\n",
554           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
555
556     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n",
557           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
558
559     io_status->Information = 0;
560
561     io_status->u.Status = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags, &unix_handle );
562     if (io_status->u.Status) return io_status->u.Status;
563
564     if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
565     {
566         async_fileio*   ovp;
567         NTSTATUS ret;
568
569         if (unix_handle < 0) return STATUS_INVALID_HANDLE;
570
571         ovp = RtlAllocateHeap(ntdll_get_process_heap(), 0, sizeof(async_fileio));
572         if (!ovp) return STATUS_NO_MEMORY;
573
574         ovp->async.ops = (apc ? &fileio_async_ops : &fileio_nocomp_async_ops );
575         ovp->async.handle = hFile;
576         ovp->async.fd = unix_handle;
577         ovp->async.type = ASYNC_TYPE_WRITE;
578         ovp->async.func = FILE_AsyncWriteService;
579         ovp->async.event = hEvent;
580         ovp->async.iosb = io_status;
581         ovp->count = length;
582         ovp->offset = offset->s.LowPart;
583         if (offset->s.HighPart) FIXME("NIY-high part\n");
584         ovp->apc = apc;
585         ovp->apc_user = apc_user;
586         ovp->buffer = (void*)buffer;
587         ovp->fd_type = type;
588
589         io_status->Information = 0;
590         ret = register_new_async(&ovp->async);
591         if (ret != STATUS_SUCCESS)
592             return ret;
593         if (flags & FD_FLAG_TIMEOUT)
594         {
595             NtWaitForSingleObject(hEvent, TRUE, NULL);
596             NtClose(hEvent);
597         }
598         else
599         {
600             LARGE_INTEGER   timeout;
601
602             /* let some APC be run, this will write as much data as possible */
603             timeout.s.LowPart = timeout.s.HighPart = 0;
604             NtDelayExecution( TRUE, &timeout );
605         }
606         return io_status->u.Status;
607     }
608     switch (type)
609     {
610     case FD_TYPE_SMB:
611         FIXME("NIY-SMB\n");
612         close(unix_handle);
613         return STATUS_NOT_IMPLEMENTED;
614
615     case FD_TYPE_DEFAULT:
616         /* normal unix files */
617         if (unix_handle == -1) return STATUS_INVALID_HANDLE;
618         break;
619
620     default:
621         FIXME("Unsupported type of fd %d\n", type);
622         if (unix_handle == -1) close(unix_handle);
623         return STATUS_INVALID_HANDLE;
624     }
625
626     if (offset)
627     {
628         FILE_POSITION_INFORMATION   fpi;
629
630         fpi.CurrentByteOffset = *offset;
631         io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi),
632                                                    FilePositionInformation);
633         if (io_status->u.Status)
634         {
635             close(unix_handle);
636             return io_status->u.Status;
637         }
638     }
639
640     /* synchronous file write */
641     while ((io_status->Information = write( unix_handle, buffer, length )) == -1)
642     {
643         if ((errno == EAGAIN) || (errno == EINTR)) continue;
644         if (errno == EFAULT) FIXME( "EFAULT handling broken for now\n" );
645         if (errno == ENOSPC) io_status->u.Status = STATUS_DISK_FULL;
646         else io_status->u.Status = FILE_GetNtStatus();
647         break;
648     }
649     close( unix_handle );
650     return io_status->u.Status;
651 }
652
653 /**************************************************************************
654  *              NtDeviceIoControlFile                   [NTDLL.@]
655  *              ZwDeviceIoControlFile                   [NTDLL.@]
656  *
657  * Perform an I/O control operation on an open file handle.
658  *
659  * PARAMS
660  *  DeviceHandle     [I] Handle returned from ZwOpenFile() or ZwCreateFile()
661  *  Event            [I] Event to signal upon completion (or NULL)
662  *  ApcRoutine       [I] Callback to call upon completion (or NULL)
663  *  ApcContext       [I] Context for ApcRoutine (or NULL)
664  *  IoStatusBlock    [O] Receives information about the operation on return
665  *  IoControlCode    [I] Control code for the operation to perform
666  *  InputBuffer      [I] Source for any input data required (or NULL)
667  *  InputBufferSize  [I] Size of InputBuffer
668  *  OutputBuffer     [O] Source for any output data returned (or NULL)
669  *  OutputBufferSize [I] Size of OutputBuffer
670  *
671  * RETURNS
672  *  Success: 0. IoStatusBlock is updated.
673  *  Failure: An NTSTATUS error code describing the error.
674  */
675 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE DeviceHandle, HANDLE hEvent,
676                                       PIO_APC_ROUTINE UserApcRoutine, 
677                                       PVOID UserApcContext,
678                                       PIO_STATUS_BLOCK IoStatusBlock,
679                                       ULONG IoControlCode,
680                                       PVOID InputBuffer,
681                                       ULONG InputBufferSize,
682                                       PVOID OutputBuffer,
683                                       ULONG OutputBufferSize)
684 {
685     DWORD               clientID = 0;
686     char                str[3];
687
688     TRACE("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx)\n",
689           DeviceHandle, hEvent, UserApcRoutine, UserApcContext,
690           IoStatusBlock, IoControlCode, 
691           InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize);
692
693     /* FIXME: clientID hack should disappear */
694     SERVER_START_REQ( get_device_id )
695     {
696         req->handle = DeviceHandle;
697         if (!wine_server_call( req )) clientID = reply->id;
698     }
699     SERVER_END_REQ;
700
701     if (!clientID) return STATUS_INVALID_PARAMETER;
702     strcpy(str,  "A:");
703     str[0] += LOBYTE(clientID);
704     
705     /* FIXME: should use the NTDLL equivalent */
706     if (GetDriveTypeA(str) == DRIVE_CDROM)
707     {
708         return CDROM_DeviceIoControl(clientID, DeviceHandle, hEvent, 
709                                      UserApcRoutine, UserApcContext, 
710                                      IoStatusBlock, IoControlCode,
711                                      InputBuffer, InputBufferSize,
712                                      OutputBuffer, OutputBufferSize);
713     }
714     
715     FIXME("Unimplemented dwIoControlCode=%08lx\n", IoControlCode);
716     IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
717     IoStatusBlock->Information = 0;
718     if (hEvent) NtSetEvent(hEvent, NULL);
719     return STATUS_NOT_IMPLEMENTED;
720 }
721
722 /******************************************************************************
723  * NtFsControlFile [NTDLL.@]
724  * ZwFsControlFile [NTDLL.@]
725  */
726 NTSTATUS WINAPI NtFsControlFile(
727         IN HANDLE DeviceHandle,
728         IN HANDLE Event OPTIONAL,
729         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
730         IN PVOID ApcContext OPTIONAL,
731         OUT PIO_STATUS_BLOCK IoStatusBlock,
732         IN ULONG IoControlCode,
733         IN PVOID InputBuffer,
734         IN ULONG InputBufferSize,
735         OUT PVOID OutputBuffer,
736         IN ULONG OutputBufferSize)
737 {
738         FIXME("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx): stub\n",
739         DeviceHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,IoControlCode,
740         InputBuffer,InputBufferSize,OutputBuffer,OutputBufferSize);
741         return 0;
742 }
743
744 /******************************************************************************
745  *  NtSetVolumeInformationFile          [NTDLL.@]
746  *  ZwSetVolumeInformationFile          [NTDLL.@]
747  *
748  * Set volume information for an open file handle.
749  *
750  * PARAMS
751  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
752  *  IoStatusBlock      [O] Receives information about the operation on return
753  *  FsInformation      [I] Source for volume information
754  *  Length             [I] Size of FsInformation
755  *  FsInformationClass [I] Type of volume information to set
756  *
757  * RETURNS
758  *  Success: 0. IoStatusBlock is updated.
759  *  Failure: An NTSTATUS error code describing the error.
760  */
761 NTSTATUS WINAPI NtSetVolumeInformationFile(
762         IN HANDLE FileHandle,
763         PIO_STATUS_BLOCK IoStatusBlock,
764         PVOID FsInformation,
765         ULONG Length,
766         FS_INFORMATION_CLASS FsInformationClass)
767 {
768         FIXME("(%p,%p,%p,0x%08lx,0x%08x) stub\n",
769         FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
770         return 0;
771 }
772
773 /******************************************************************************
774  *  NtQueryInformationFile              [NTDLL.@]
775  *  ZwQueryInformationFile              [NTDLL.@]
776  *
777  * Get information about an open file handle.
778  *
779  * PARAMS
780  *  FileHandle           [I] Handle returned from ZwOpenFile() or ZwCreateFile()
781  *  IoStatusBlock        [O] Receives information about the operation on return
782  *  FileInformation      [O] Destination for file information
783  *  Length               [I] Size of FileInformation
784  *  FileInformationClass [I] Type of file information to get
785  *
786  * RETURNS
787  *  Success: 0. IoStatusBlock and FileInformation are updated.
788  *  Failure: An NTSTATUS error code describing the error.
789  */
790 NTSTATUS WINAPI NtQueryInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io_status,
791                                        PVOID ptr, LONG len,
792                                        FILE_INFORMATION_CLASS class)
793 {
794     NTSTATUS    status;
795     LONG        used = 0;
796     BYTE        answer[256];
797     time_t      ct = 0, wt = 0, at = 0;
798
799     TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", hFile, io_status, ptr, len, class);
800
801     switch (class)
802     {
803     case FileBasicInformation:
804         {
805             FILE_BASIC_INFORMATION*  fbi = (FILE_BASIC_INFORMATION*)answer;
806             if (sizeof(answer) < sizeof(*fbi)) goto too_small;
807
808             SERVER_START_REQ( get_file_info )
809             {
810                 req->handle = hFile;
811                 if (!(status = wine_server_call( req )))
812                 {
813                     /* FIXME: which file types are supported ?
814                      * Serial ports (FILE_TYPE_CHAR) are not,
815                      * and MSDN also says that pipes are not supported.
816                      * FILE_TYPE_REMOTE seems to be supported according to
817                      * MSDN q234741.txt */
818                     if ((reply->type == FILE_TYPE_DISK) ||
819                         (reply->type == FILE_TYPE_REMOTE))
820                     {
821                         at = reply->access_time;
822                         wt = reply->write_time;
823                         ct = reply->change_time;
824                         fbi->FileAttributes = reply->attr;
825                         used = sizeof(*fbi);
826                     }
827                     else status = STATUS_INVALID_HANDLE; /* FIXME ??? */
828                 }
829             }
830             SERVER_END_REQ;
831             if (used)
832             {
833                 RtlSecondsSince1970ToTime(wt, &fbi->CreationTime);
834                 RtlSecondsSince1970ToTime(wt, &fbi->LastWriteTime);
835                 RtlSecondsSince1970ToTime(ct, &fbi->ChangeTime);
836                 RtlSecondsSince1970ToTime(at, &fbi->LastAccessTime);
837             }
838         }
839         break;
840     case FileStandardInformation:
841         {
842             FILE_STANDARD_INFORMATION*  fsi = (FILE_STANDARD_INFORMATION*)answer;
843             if (sizeof(answer) < sizeof(*fsi)) goto too_small;
844
845             SERVER_START_REQ( get_file_info )
846             {
847                 req->handle = hFile;
848                 if (!(status = wine_server_call( req )))
849                 {
850                     /* FIXME: which file types are supported ?
851                      * Serial ports (FILE_TYPE_CHAR) are not,
852                      * and MSDN also says that pipes are not supported.
853                      * FILE_TYPE_REMOTE seems to be supported according to
854                      * MSDN q234741.txt */
855                     if ((reply->type == FILE_TYPE_DISK) ||
856                         (reply->type == FILE_TYPE_REMOTE))
857                     {
858                         fsi->AllocationSize.s.HighPart = reply->alloc_high;
859                         fsi->AllocationSize.s.LowPart  = reply->alloc_low;
860                         fsi->EndOfFile.s.HighPart      = reply->size_high;
861                         fsi->EndOfFile.s.LowPart       = reply->size_low;
862                         fsi->NumberOfLinks             = reply->links;
863                         fsi->DeletePending             = FALSE; /* FIXME */
864                         fsi->Directory                 = (reply->attr & FILE_ATTRIBUTE_DIRECTORY);
865                         used = sizeof(*fsi);
866                     }
867                     else status = STATUS_INVALID_HANDLE; /* FIXME ??? */
868                 }
869             }
870             SERVER_END_REQ;
871         }
872         break;
873     case FilePositionInformation:
874         {
875             FILE_POSITION_INFORMATION*  fpi = (FILE_POSITION_INFORMATION*)answer;
876             if (sizeof(answer) < sizeof(*fpi)) goto too_small;
877
878             SERVER_START_REQ( set_file_pointer )
879             {
880                 req->handle = hFile;
881                 req->low = 0;
882                 req->high = 0;
883                 req->whence = SEEK_CUR;
884                 if (!(status = wine_server_call( req )))
885                 {
886                     fpi->CurrentByteOffset.s.HighPart = reply->new_high;
887                     fpi->CurrentByteOffset.s.LowPart  = reply->new_low;
888                     used = sizeof(*fpi);
889                 }
890             }
891             SERVER_END_REQ;
892         }
893         break;
894     default:
895         FIXME("Unsupported class (%d)\n", class);
896         return io_status->u.Status = STATUS_NOT_IMPLEMENTED;
897     }
898     if (used) memcpy(ptr, answer, min(used, len));
899     io_status->u.Status = status;
900     io_status->Information = len;
901     return status;
902  too_small:
903     io_status->Information = 0;
904     return io_status->u.Status = STATUS_BUFFER_TOO_SMALL;
905 }
906
907 /******************************************************************************
908  *  NtSetInformationFile                [NTDLL.@]
909  *  ZwSetInformationFile                [NTDLL.@]
910  *
911  * Set information about an open file handle.
912  *
913  * PARAMS
914  *  FileHandle           [I] Handle returned from ZwOpenFile() or ZwCreateFile()
915  *  IoStatusBlock        [O] Receives information about the operation on return
916  *  FileInformation      [I] Source for file information
917  *  Length               [I] Size of FileInformation
918  *  FileInformationClass [I] Type of file information to set
919  *
920  * RETURNS
921  *  Success: 0. IoStatusBlock is updated.
922  *  Failure: An NTSTATUS error code describing the error.
923  */
924 NTSTATUS WINAPI NtSetInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io_status,
925                                      PVOID ptr, ULONG len,
926                                      FILE_INFORMATION_CLASS class)
927 {
928     NTSTATUS    status = STATUS_INVALID_PARAMETER_3;
929
930     TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", hFile, io_status, ptr, len, class);
931
932     switch (class)
933     {
934     case FilePositionInformation:
935         if (len >= sizeof(FILE_POSITION_INFORMATION))
936         {
937             FILE_POSITION_INFORMATION*  fpi = (FILE_POSITION_INFORMATION*)ptr;
938
939             SERVER_START_REQ( set_file_pointer )
940             {
941                 req->handle = hFile;
942                 req->low = fpi->CurrentByteOffset.s.LowPart;
943                 req->high = fpi->CurrentByteOffset.s.HighPart;
944                 req->whence = SEEK_SET;
945                 status = wine_server_call( req );
946             }
947             SERVER_END_REQ;
948             status = STATUS_SUCCESS;
949         }
950         break;
951     default:
952         FIXME("Unsupported class (%d)\n", class);
953         return STATUS_NOT_IMPLEMENTED;
954     }
955     io_status->u.Status = status;
956     io_status->Information = 0;
957     return status;
958 }
959
960 /******************************************************************************
961  *  NtQueryDirectoryFile        [NTDLL.@]
962  *  ZwQueryDirectoryFile        [NTDLL.@]
963  */
964 NTSTATUS WINAPI NtQueryDirectoryFile(
965         IN HANDLE FileHandle,
966         IN HANDLE Event OPTIONAL,
967         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
968         IN PVOID ApcContext OPTIONAL,
969         OUT PIO_STATUS_BLOCK IoStatusBlock,
970         OUT PVOID FileInformation,
971         IN ULONG Length,
972         IN FILE_INFORMATION_CLASS FileInformationClass,
973         IN BOOLEAN ReturnSingleEntry,
974         IN PUNICODE_STRING FileName OPTIONAL,
975         IN BOOLEAN RestartScan)
976 {
977         FIXME("(%p %p %p %p %p %p 0x%08lx 0x%08x 0x%08x %p 0x%08x\n",
978         FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation,
979         Length, FileInformationClass, ReturnSingleEntry,
980         debugstr_us(FileName),RestartScan);
981         return 0;
982 }
983
984 /******************************************************************************
985  *  NtQueryVolumeInformationFile                [NTDLL.@]
986  *  ZwQueryVolumeInformationFile                [NTDLL.@]
987  *
988  * Get volume information for an open file handle.
989  *
990  * PARAMS
991  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
992  *  IoStatusBlock      [O] Receives information about the operation on return
993  *  FsInformation      [O] Destination for volume information
994  *  Length             [I] Size of FsInformation
995  *  FsInformationClass [I] Type of volume information to set
996  *
997  * RETURNS
998  *  Success: 0. IoStatusBlock and FsInformation are updated.
999  *  Failure: An NTSTATUS error code describing the error.
1000  */
1001 NTSTATUS WINAPI NtQueryVolumeInformationFile (
1002         IN HANDLE FileHandle,
1003         OUT PIO_STATUS_BLOCK IoStatusBlock,
1004         OUT PVOID FSInformation,
1005         IN ULONG Length,
1006         IN FS_INFORMATION_CLASS FSInformationClass)
1007 {
1008         ULONG len = 0;
1009
1010         FIXME("(%p %p %p 0x%08lx 0x%08x) stub!\n",
1011         FileHandle, IoStatusBlock, FSInformation, Length, FSInformationClass);
1012
1013         switch ( FSInformationClass )
1014         {
1015           case FileFsVolumeInformation:
1016             len = sizeof( FILE_FS_VOLUME_INFORMATION );
1017             break;
1018           case FileFsLabelInformation:
1019             len = 0;
1020             break;
1021
1022           case FileFsSizeInformation:
1023             len = sizeof( FILE_FS_SIZE_INFORMATION );
1024             break;
1025
1026           case FileFsDeviceInformation:
1027             len = sizeof( FILE_FS_DEVICE_INFORMATION );
1028             break;
1029           case FileFsAttributeInformation:
1030             len = sizeof( FILE_FS_ATTRIBUTE_INFORMATION );
1031             break;
1032
1033           case FileFsControlInformation:
1034             len = 0;
1035             break;
1036
1037           case FileFsFullSizeInformation:
1038             len = 0;
1039             break;
1040
1041           case FileFsObjectIdInformation:
1042             len = 0;
1043             break;
1044
1045           case FileFsMaximumInformation:
1046             len = 0;
1047             break;
1048         }
1049
1050         if (Length < len)
1051           return STATUS_BUFFER_TOO_SMALL;
1052
1053         switch ( FSInformationClass )
1054         {
1055           case FileFsVolumeInformation:
1056             break;
1057           case FileFsLabelInformation:
1058             break;
1059
1060           case FileFsSizeInformation:
1061             break;
1062
1063           case FileFsDeviceInformation:
1064             if (FSInformation)
1065             {
1066               FILE_FS_DEVICE_INFORMATION * DeviceInfo = FSInformation;
1067               DeviceInfo->DeviceType = FILE_DEVICE_DISK;
1068               DeviceInfo->Characteristics = 0;
1069               break;
1070             };
1071           case FileFsAttributeInformation:
1072             break;
1073
1074           case FileFsControlInformation:
1075             break;
1076
1077           case FileFsFullSizeInformation:
1078             break;
1079
1080           case FileFsObjectIdInformation:
1081             break;
1082
1083           case FileFsMaximumInformation:
1084             break;
1085         }
1086         IoStatusBlock->u.Status = STATUS_SUCCESS;
1087         IoStatusBlock->Information = len;
1088         return STATUS_SUCCESS;
1089 }
1090
1091 /******************************************************************
1092  *              NtFlushBuffersFile  (NTDLL.@)
1093  *
1094  * Flush any buffered data on an open file handle.
1095  *
1096  * PARAMS
1097  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1098  *  IoStatusBlock      [O] Receives information about the operation on return
1099  *
1100  * RETURNS
1101  *  Success: 0. IoStatusBlock is updated.
1102  *  Failure: An NTSTATUS error code describing the error.
1103  */
1104 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
1105 {
1106     NTSTATUS ret;
1107     HANDLE hEvent = NULL;
1108
1109     SERVER_START_REQ( flush_file )
1110     {
1111         req->handle = hFile;
1112         ret = wine_server_call( req );
1113         hEvent = reply->event;
1114     }
1115     SERVER_END_REQ;
1116     if (!ret && hEvent)
1117     {
1118         ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
1119         NtClose( hEvent );
1120     }
1121     return ret;
1122 }
1123
1124 /******************************************************************
1125  *              NtLockFile       (NTDLL.@)
1126  *
1127  *
1128  */
1129 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
1130                             PIO_APC_ROUTINE apc, void* apc_user,
1131                             PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
1132                             PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
1133                             BOOLEAN exclusive )
1134 {
1135     NTSTATUS    ret;
1136     HANDLE      handle;
1137     BOOLEAN     async;
1138
1139     if (apc || io_status || key)
1140     {
1141         FIXME("Unimplemented yet parameter\n");
1142         return STATUS_NOT_IMPLEMENTED;
1143     }
1144
1145     for (;;)
1146     {
1147         SERVER_START_REQ( lock_file )
1148         {
1149             req->handle      = hFile;
1150             req->offset_low  = offset->s.LowPart;
1151             req->offset_high = offset->s.HighPart;
1152             req->count_low   = count->s.LowPart;
1153             req->count_high  = count->s.HighPart;
1154             req->shared      = !exclusive;
1155             req->wait        = !dont_wait;
1156             ret = wine_server_call( req );
1157             handle = reply->handle;
1158             async  = reply->overlapped;
1159         }
1160         SERVER_END_REQ;
1161         if (ret != STATUS_PENDING)
1162         {
1163             if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
1164             return ret;
1165         }
1166
1167         if (async)
1168         {
1169             FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
1170             if (handle) NtClose( handle );
1171             return STATUS_PENDING;
1172         }
1173         if (handle)
1174         {
1175             NtWaitForSingleObject( handle, FALSE, NULL );
1176             NtClose( handle );
1177         }
1178         else
1179         {
1180             LARGE_INTEGER time;
1181     
1182             /* Unix lock conflict, sleep a bit and retry */
1183             time.QuadPart = 100 * (ULONGLONG)10000;
1184             time.QuadPart = -time.QuadPart;
1185             NtDelayExecution( FALSE, &time );
1186         }
1187     }
1188 }
1189
1190
1191 /******************************************************************
1192  *              NtUnlockFile    (NTDLL.@)
1193  *
1194  *
1195  */
1196 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
1197                               PLARGE_INTEGER offset, PLARGE_INTEGER count,
1198                               PULONG key )
1199 {
1200     NTSTATUS status;
1201
1202     TRACE( "%p %lx%08lx %lx%08lx\n",
1203            hFile, offset->s.HighPart, offset->s.LowPart, count->s.HighPart, count->s.LowPart );
1204
1205     if (io_status || key)
1206     {
1207         FIXME("Unimplemented yet parameter\n");
1208         return STATUS_NOT_IMPLEMENTED;
1209     }
1210
1211     SERVER_START_REQ( unlock_file )
1212     {
1213         req->handle      = hFile;
1214         req->offset_low  = offset->s.LowPart;
1215         req->offset_high = offset->s.HighPart;
1216         req->count_low   = count->s.LowPart;
1217         req->count_high  = count->s.HighPart;
1218         status = wine_server_call( req );
1219     }
1220     SERVER_END_REQ;
1221     return status;
1222 }