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