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