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