Improve parameter checking in NtCreateFile.
[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 HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 #endif
45 #ifdef HAVE_UTIME_H
46 # include <utime.h>
47 #endif
48 #ifdef STATFS_DEFINED_BY_SYS_VFS
49 # include <sys/vfs.h>
50 #else
51 # ifdef STATFS_DEFINED_BY_SYS_MOUNT
52 #  include <sys/mount.h>
53 # else
54 #  ifdef STATFS_DEFINED_BY_SYS_STATFS
55 #   include <sys/statfs.h>
56 #  endif
57 # endif
58 #endif
59
60 #define NONAMELESSUNION
61 #define NONAMELESSSTRUCT
62 #include "wine/unicode.h"
63 #include "wine/debug.h"
64 #include "wine/server.h"
65 #include "ntdll_misc.h"
66
67 #include "winternl.h"
68 #include "winioctl.h"
69
70 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
71
72 mode_t FILE_umask = 0;
73
74 #define SECSPERDAY         86400
75 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
76
77 /**************************************************************************
78  *                 NtOpenFile                           [NTDLL.@]
79  *                 ZwOpenFile                           [NTDLL.@]
80  *
81  * Open a file.
82  *
83  * PARAMS
84  *  handle    [O] Variable that receives the file handle on return
85  *  access    [I] Access desired by the caller to the file
86  *  attr      [I] Structure describing the file to be opened
87  *  io        [O] Receives details about the result of the operation
88  *  sharing   [I] Type of shared access the caller requires
89  *  options   [I] Options for the file open
90  *
91  * RETURNS
92  *  Success: 0. FileHandle and IoStatusBlock are updated.
93  *  Failure: An NTSTATUS error code describing the error.
94  */
95 NTSTATUS WINAPI NtOpenFile( PHANDLE handle, ACCESS_MASK access,
96                             POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK io,
97                             ULONG sharing, ULONG options )
98 {
99     return NtCreateFile( handle, access, attr, io, NULL, 0,
100                          sharing, FILE_OPEN, options, NULL, 0 );
101 }
102
103 /**************************************************************************
104  *              NtCreateFile                            [NTDLL.@]
105  *              ZwCreateFile                            [NTDLL.@]
106  *
107  * Either create a new file or directory, or open an existing file, device,
108  * directory or volume.
109  *
110  * PARAMS
111  *      handle       [O] Points to a variable which receives the file handle on return
112  *      access       [I] Desired access to the file
113  *      attr         [I] Structure describing the file
114  *      io           [O] Receives information about the operation on return
115  *      alloc_size   [I] Initial size of the file in bytes
116  *      attributes   [I] Attributes to create the file with
117  *      sharing      [I] Type of shared access the caller would like to the file
118  *      disposition  [I] Specifies what to do, depending on whether the file already exists
119  *      options      [I] Options for creating a new file
120  *      ea_buffer    [I] Pointer to a extended attributes buffer
121  *      ea_length    [I] Length of ea_buffer
122  *
123  * RETURNS
124  *  Success: 0. handle and io are updated.
125  *  Failure: An NTSTATUS error code describing the error.
126  */
127 NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
128                               PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
129                               ULONG attributes, ULONG sharing, ULONG disposition,
130                               ULONG options, PVOID ea_buffer, ULONG ea_length )
131 {
132     static const WCHAR pipeW[] = {'\\','?','?','\\','p','i','p','e','\\'};
133     ANSI_STRING unix_name;
134     int created = FALSE;
135
136     TRACE("handle=%p access=%08lx name=%s objattr=%08lx root=%p sec=%p io=%p alloc_size=%p\n"
137           "attr=%08lx sharing=%08lx disp=%ld options=%08lx ea=%p.0x%08lx\n",
138           handle, access, debugstr_us(attr->ObjectName), attr->Attributes,
139           attr->RootDirectory, attr->SecurityDescriptor, io, alloc_size,
140           attributes, sharing, disposition, options, ea_buffer, ea_length );
141
142     if (!attr || !attr->ObjectName) return STATUS_INVALID_PARAMETER;
143
144     if (attr->RootDirectory)
145     {
146         FIXME( "RootDirectory %p not supported\n", attr->RootDirectory );
147         return STATUS_OBJECT_NAME_NOT_FOUND;
148     }
149     if (alloc_size) FIXME( "alloc_size not supported\n" );
150
151     /* check for named pipe */
152
153     if (attr->ObjectName->Length > sizeof(pipeW) &&
154         !memicmpW( attr->ObjectName->Buffer, pipeW, sizeof(pipeW)/sizeof(WCHAR) ))
155     {
156         SERVER_START_REQ( open_named_pipe )
157         {
158             req->access = access;
159             req->inherit = (attr->Attributes & OBJ_INHERIT) != 0;
160             wine_server_add_data( req, attr->ObjectName->Buffer + 4,
161                                   attr->ObjectName->Length - 4*sizeof(WCHAR) );
162             io->u.Status = wine_server_call( req );
163             *handle = reply->handle;
164         }
165         SERVER_END_REQ;
166         return io->u.Status;
167     }
168
169     io->u.Status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, disposition,
170                                               !(attr->Attributes & OBJ_CASE_INSENSITIVE) );
171
172     if (io->u.Status == STATUS_NO_SUCH_FILE &&
173         disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
174     {
175         created = TRUE;
176         io->u.Status = STATUS_SUCCESS;
177     }
178
179     if (io->u.Status == STATUS_SUCCESS)
180     {
181         SERVER_START_REQ( create_file )
182         {
183             req->access     = access;
184             req->inherit    = (attr->Attributes & OBJ_INHERIT) != 0;
185             req->sharing    = sharing;
186             req->create     = disposition;
187             req->options    = options;
188             req->attrs      = attributes;
189             wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
190             io->u.Status = wine_server_call( req );
191             *handle = reply->handle;
192         }
193         SERVER_END_REQ;
194         RtlFreeAnsiString( &unix_name );
195     }
196     else WARN("%s not found (%lx)\n", debugstr_us(attr->ObjectName), io->u.Status );
197
198     if (io->u.Status == STATUS_SUCCESS)
199     {
200         if (created) io->Information = FILE_CREATED;
201         else switch(disposition)
202         {
203         case FILE_SUPERSEDE:
204             io->Information = FILE_SUPERSEDED;
205             break;
206         case FILE_CREATE:
207             io->Information = FILE_CREATED;
208             break;
209         case FILE_OPEN:
210         case FILE_OPEN_IF:
211             io->Information = FILE_OPENED;
212             break;
213         case FILE_OVERWRITE:
214         case FILE_OVERWRITE_IF:
215             io->Information = FILE_OVERWRITTEN;
216             break;
217         }
218     }
219
220     return io->u.Status;
221 }
222
223 /***********************************************************************
224  *                  Asynchronous file I/O                              *
225  */
226 static void WINAPI FILE_AsyncReadService(void*, PIO_STATUS_BLOCK, ULONG);
227 static void WINAPI FILE_AsyncWriteService(void*, PIO_STATUS_BLOCK, ULONG);
228
229 typedef struct async_fileio
230 {
231     HANDLE              handle;
232     PIO_APC_ROUTINE     apc;
233     void*               apc_user;
234     char*               buffer;
235     unsigned int        count;
236     off_t               offset;
237     int                 queue_apc_on_error;
238     BOOL                avail_mode;
239     int                 fd;
240     HANDLE              event;
241 } async_fileio;
242
243 static void fileio_terminate(async_fileio *fileio, IO_STATUS_BLOCK* iosb)
244 {
245     TRACE("data: %p\n", fileio);
246
247     wine_server_release_fd( fileio->handle, fileio->fd );
248     if ( fileio->event != INVALID_HANDLE_VALUE )
249         NtSetEvent( fileio->event, NULL );
250
251     if (fileio->apc && 
252         (iosb->u.Status == STATUS_SUCCESS || fileio->queue_apc_on_error))
253         fileio->apc( fileio->apc_user, iosb, iosb->Information );
254
255     RtlFreeHeap( GetProcessHeap(), 0, fileio );
256 }
257
258
259 static ULONG fileio_queue_async(async_fileio* fileio, IO_STATUS_BLOCK* iosb, 
260                                 BOOL do_read)
261 {
262     PIO_APC_ROUTINE     apc = do_read ? FILE_AsyncReadService : FILE_AsyncWriteService;
263     NTSTATUS            status;
264
265     SERVER_START_REQ( register_async )
266     {
267         req->handle = fileio->handle;
268         req->io_apc = apc;
269         req->io_sb = iosb;
270         req->io_user = fileio;
271         req->type = do_read ? ASYNC_TYPE_READ : ASYNC_TYPE_WRITE;
272         req->count = (fileio->count < iosb->Information) ? 
273             0 : fileio->count - iosb->Information;
274         status = wine_server_call( req );
275     }
276     SERVER_END_REQ;
277
278     if ( status ) iosb->u.Status = status;
279     if ( iosb->u.Status != STATUS_PENDING )
280     {
281         (apc)( fileio, iosb, iosb->u.Status );
282         return iosb->u.Status;
283     }
284     NtCurrentTeb()->num_async_io++;
285     return STATUS_SUCCESS;
286 }
287
288 /***********************************************************************
289  *           FILE_GetNtStatus(void)
290  *
291  * Retrieve the Nt Status code from errno.
292  * Try to be consistent with FILE_SetDosError().
293  */
294 NTSTATUS FILE_GetNtStatus(void)
295 {
296     int err = errno;
297
298     TRACE( "errno = %d\n", errno );
299     switch (err)
300     {
301     case EAGAIN:    return STATUS_SHARING_VIOLATION;
302     case EBADF:     return STATUS_INVALID_HANDLE;
303     case ENOSPC:    return STATUS_DISK_FULL;
304     case EPERM:
305     case EROFS:
306     case EACCES:    return STATUS_ACCESS_DENIED;
307     case ENOTDIR:   return STATUS_OBJECT_PATH_NOT_FOUND;
308     case ENOENT:    return STATUS_OBJECT_NAME_NOT_FOUND;
309     case EISDIR:    return STATUS_FILE_IS_A_DIRECTORY;
310     case EMFILE:
311     case ENFILE:    return STATUS_TOO_MANY_OPENED_FILES;
312     case EINVAL:    return STATUS_INVALID_PARAMETER;
313     case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
314     case EPIPE:     return STATUS_PIPE_BROKEN;
315     case EIO:       return STATUS_DEVICE_NOT_READY;
316 #ifdef ENOMEDIUM
317     case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE;
318 #endif
319     case ENOTTY:
320     case EOPNOTSUPP:return STATUS_NOT_SUPPORTED;
321     case ECONNRESET:return STATUS_PIPE_DISCONNECTED;
322     case ENOEXEC:   /* ?? */
323     case ESPIPE:    /* ?? */
324     case EEXIST:    /* ?? */
325     default:
326         FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
327         return STATUS_UNSUCCESSFUL;
328     }
329 }
330
331 /***********************************************************************
332  *             FILE_AsyncReadService      (INTERNAL)
333  *
334  *  This function is called while the client is waiting on the
335  *  server, so we can't make any server calls here.
336  */
337 static void WINAPI FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, ULONG status)
338 {
339     async_fileio *fileio = (async_fileio*)user;
340     int result;
341     int already = iosb->Information;
342
343     TRACE("%p %p %lu\n", iosb, fileio->buffer, status);
344
345     switch (status)
346     {
347     case STATUS_ALERTED: /* got some new data */
348         if (iosb->u.Status != STATUS_PENDING) FIXME("unexpected status %08lx\n", iosb->u.Status);
349         /* check to see if the data is ready (non-blocking) */
350         if ( fileio->avail_mode )
351             result = read(fileio->fd, &fileio->buffer[already], 
352                           fileio->count - already);
353         else
354         {
355             result = pread(fileio->fd, &fileio->buffer[already],
356                            fileio->count - already,
357                            fileio->offset + already);
358             if ((result < 0) && (errno == ESPIPE))
359                 result = read(fileio->fd, &fileio->buffer[already], 
360                               fileio->count - already);
361         }
362
363         if (result < 0)
364         {
365             if (errno == EAGAIN || errno == EINTR)
366             {
367                 TRACE("Deferred read %d\n", errno);
368                 iosb->u.Status = STATUS_PENDING;
369             }
370             else /* check to see if the transfer is complete */
371                 iosb->u.Status = FILE_GetNtStatus();
372         }
373         else if (result == 0)
374         {
375             iosb->u.Status = iosb->Information ? STATUS_SUCCESS : STATUS_END_OF_FILE;
376         }
377         else
378         {
379             iosb->Information += result;
380             if (iosb->Information >= fileio->count || fileio->avail_mode)
381                 iosb->u.Status = STATUS_SUCCESS;
382             else
383             {
384                 /* if we only have to read the available data, and none is available,
385                  * simply cancel the request. If data was available, it has been read
386                  * while in by previous call (NtDelayExecution)
387                  */
388                 iosb->u.Status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING;
389             }
390
391             TRACE("read %d more bytes %ld/%d so far (%s)\n",
392                   result, iosb->Information, fileio->count, 
393                   (iosb->u.Status == STATUS_SUCCESS) ? "success" : "pending");
394         }
395         /* queue another async operation ? */
396         if (iosb->u.Status == STATUS_PENDING)
397             fileio_queue_async(fileio, iosb, TRUE);
398         else
399             fileio_terminate(fileio, iosb);
400         break;
401     default:
402         iosb->u.Status = status;
403         fileio_terminate(fileio, iosb);
404         break;
405     }
406 }
407
408
409 /******************************************************************************
410  *  NtReadFile                                  [NTDLL.@]
411  *  ZwReadFile                                  [NTDLL.@]
412  *
413  * Read from an open file handle.
414  *
415  * PARAMS
416  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
417  *  Event         [I] Event to signal upon completion (or NULL)
418  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
419  *  ApcContext    [I] Context for ApcRoutine (or NULL)
420  *  IoStatusBlock [O] Receives information about the operation on return
421  *  Buffer        [O] Destination for the data read
422  *  Length        [I] Size of Buffer
423  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
424  *  Key           [O] Function unknown (may be NULL)
425  *
426  * RETURNS
427  *  Success: 0. IoStatusBlock is updated, and the Information member contains
428  *           The number of bytes read.
429  *  Failure: An NTSTATUS error code describing the error.
430  */
431 NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
432                            PIO_APC_ROUTINE apc, void* apc_user,
433                            PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
434                            PLARGE_INTEGER offset, PULONG key)
435 {
436     int unix_handle, flags;
437
438     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n",
439           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
440
441     io_status->Information = 0;
442     io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_READ, &unix_handle, &flags );
443     if (io_status->u.Status) return io_status->u.Status;
444
445     if (flags & FD_FLAG_RECV_SHUTDOWN)
446     {
447         wine_server_release_fd( hFile, unix_handle );
448         return STATUS_PIPE_DISCONNECTED;
449     }
450
451     if (flags & FD_FLAG_TIMEOUT)
452     {
453         if (hEvent)
454         {
455             /* this shouldn't happen, but check it */
456             FIXME("NIY-hEvent\n");
457             wine_server_release_fd( hFile, unix_handle );
458             return STATUS_NOT_IMPLEMENTED;
459         }
460         io_status->u.Status = NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, NULL, 0, 0);
461         if (io_status->u.Status)
462         {
463             wine_server_release_fd( hFile, unix_handle );
464             return io_status->u.Status;
465         }
466     }
467
468     if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
469     {
470         async_fileio*   fileio;
471         NTSTATUS ret;
472
473         if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
474         {
475             wine_server_release_fd( hFile, unix_handle );
476             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
477             return STATUS_NO_MEMORY;
478         }
479         fileio->handle = hFile;
480         fileio->count = length;
481         if ( offset == NULL ) 
482             fileio->offset = 0;
483         else
484         {
485             fileio->offset = offset->QuadPart;
486             if (offset->u.HighPart && fileio->offset == offset->u.LowPart)
487                 FIXME("High part of offset is lost\n");
488         } 
489         fileio->apc = apc;
490         fileio->apc_user = apc_user;
491         fileio->buffer = buffer;
492         fileio->queue_apc_on_error = 0;
493         fileio->avail_mode = (flags & FD_FLAG_AVAILABLE);
494         fileio->fd = unix_handle;  /* FIXME */
495         fileio->event = hEvent;
496         NtResetEvent(hEvent, NULL);
497
498         io_status->u.Status = STATUS_PENDING;
499         ret = fileio_queue_async(fileio, io_status, TRUE);
500         if (ret != STATUS_SUCCESS)
501         {
502             wine_server_release_fd( hFile, unix_handle );
503             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
504             RtlFreeHeap(GetProcessHeap(), 0, fileio);
505             return ret;
506         }
507         if (flags & FD_FLAG_TIMEOUT)
508         {
509             ret = NtWaitForSingleObject(hEvent, TRUE, NULL);
510             NtClose(hEvent);
511             if (ret != STATUS_USER_APC)
512                 fileio->queue_apc_on_error = 1;
513         }
514         else
515         {
516             LARGE_INTEGER   timeout;
517
518             /* let some APC be run, this will read some already pending data */
519             timeout.u.LowPart = timeout.u.HighPart = 0;
520             ret = NtDelayExecution( TRUE, &timeout );
521             /* the apc didn't run and therefore the completion routine now
522              * needs to be sent errors.
523              * Note that there is no race between setting this flag and
524              * returning errors because apc's are run only during alertable
525              * waits */
526             if (ret != STATUS_USER_APC)
527                 fileio->queue_apc_on_error = 1;
528         }
529         TRACE("= 0x%08lx\n", io_status->u.Status);
530         return io_status->u.Status;
531     }
532
533     if (offset)
534     {
535         FILE_POSITION_INFORMATION   fpi;
536
537         fpi.CurrentByteOffset = *offset;
538         io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi), 
539                                                    FilePositionInformation);
540         if (io_status->u.Status)
541         {
542             wine_server_release_fd( hFile, unix_handle );
543             return io_status->u.Status;
544         }
545     }
546     /* code for synchronous reads */
547     while ((io_status->Information = read( unix_handle, buffer, length )) == -1)
548     {
549         if ((errno == EAGAIN) || (errno == EINTR)) continue;
550         if (errno == EFAULT)
551         {
552             io_status->Information = 0;
553             io_status->u.Status = STATUS_ACCESS_VIOLATION;
554         }
555         else io_status->u.Status = FILE_GetNtStatus();
556         break;
557     }
558     wine_server_release_fd( hFile, unix_handle );
559     TRACE("= 0x%08lx\n", io_status->u.Status);
560     return io_status->u.Status;
561 }
562
563 /***********************************************************************
564  *             FILE_AsyncWriteService      (INTERNAL)
565  *
566  *  This function is called while the client is waiting on the
567  *  server, so we can't make any server calls here.
568  */
569 static void WINAPI FILE_AsyncWriteService(void *ovp, IO_STATUS_BLOCK *iosb, ULONG status)
570 {
571     async_fileio *fileio = (async_fileio *) ovp;
572     int result;
573     int already = iosb->Information;
574
575     TRACE("(%p %p %lu)\n",iosb, fileio->buffer, status);
576
577     switch (status)
578     {
579     case STATUS_ALERTED:
580         /* write some data (non-blocking) */
581         if ( fileio->avail_mode )
582             result = write(fileio->fd, &fileio->buffer[already], 
583                            fileio->count - already);
584         else
585         {
586             result = pwrite(fileio->fd, &fileio->buffer[already], 
587                             fileio->count - already, fileio->offset + already);
588             if ((result < 0) && (errno == ESPIPE))
589                 result = write(fileio->fd, &fileio->buffer[already], 
590                                fileio->count - already);
591         }
592
593         if (result < 0)
594         {
595             if (errno == EAGAIN || errno == EINTR) iosb->u.Status = STATUS_PENDING;
596             else iosb->u.Status = FILE_GetNtStatus();
597         }
598         else
599         {
600             iosb->Information += result;
601             iosb->u.Status = (iosb->Information < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
602             TRACE("wrote %d more bytes %ld/%d so far\n", 
603                   result, iosb->Information, fileio->count);
604         }
605         if (iosb->u.Status == STATUS_PENDING)
606             fileio_queue_async(fileio, iosb, FALSE);
607         break;
608     default:
609         iosb->u.Status = status;
610         fileio_terminate(fileio, iosb);
611         break;
612     }
613 }
614
615 /******************************************************************************
616  *  NtWriteFile                                 [NTDLL.@]
617  *  ZwWriteFile                                 [NTDLL.@]
618  *
619  * Write to an open file handle.
620  *
621  * PARAMS
622  *  FileHandle    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
623  *  Event         [I] Event to signal upon completion (or NULL)
624  *  ApcRoutine    [I] Callback to call upon completion (or NULL)
625  *  ApcContext    [I] Context for ApcRoutine (or NULL)
626  *  IoStatusBlock [O] Receives information about the operation on return
627  *  Buffer        [I] Source for the data to write
628  *  Length        [I] Size of Buffer
629  *  ByteOffset    [O] Destination for the new file pointer position (or NULL)
630  *  Key           [O] Function unknown (may be NULL)
631  *
632  * RETURNS
633  *  Success: 0. IoStatusBlock is updated, and the Information member contains
634  *           The number of bytes written.
635  *  Failure: An NTSTATUS error code describing the error.
636  */
637 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
638                             PIO_APC_ROUTINE apc, void* apc_user,
639                             PIO_STATUS_BLOCK io_status, 
640                             const void* buffer, ULONG length,
641                             PLARGE_INTEGER offset, PULONG key)
642 {
643     int unix_handle, flags;
644
645     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p)!\n",
646           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
647
648     io_status->Information = 0;
649     io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_WRITE, &unix_handle, &flags );
650     if (io_status->u.Status) return io_status->u.Status;
651
652     if (flags & FD_FLAG_SEND_SHUTDOWN)
653     {
654         wine_server_release_fd( hFile, unix_handle );
655         return STATUS_PIPE_DISCONNECTED;
656     }
657
658     if (flags & FD_FLAG_TIMEOUT)
659     {
660         if (hEvent)
661         {
662             /* this shouldn't happen, but check it */
663             FIXME("NIY-hEvent\n");
664             wine_server_release_fd( hFile, unix_handle );
665             return STATUS_NOT_IMPLEMENTED;
666         }
667         io_status->u.Status = NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, NULL, 0, 0);
668         if (io_status->u.Status)
669         {
670             wine_server_release_fd( hFile, unix_handle );
671             return io_status->u.Status;
672         }
673     }
674
675     if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
676     {
677         async_fileio*   fileio;
678         NTSTATUS ret;
679
680         if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
681         {
682             wine_server_release_fd( hFile, unix_handle );
683             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
684             return STATUS_NO_MEMORY;
685         }
686         fileio->handle = hFile;
687         fileio->count = length;
688         if (offset)
689         {
690             fileio->offset = offset->QuadPart;
691             if (offset->u.HighPart && fileio->offset == offset->u.LowPart)
692                 FIXME("High part of offset is lost\n");
693         }
694         else  
695         {
696             fileio->offset = 0;
697         }
698         fileio->apc = apc;
699         fileio->apc_user = apc_user;
700         fileio->buffer = (void*)buffer;
701         fileio->queue_apc_on_error = 0;
702         fileio->avail_mode = (flags & FD_FLAG_AVAILABLE);
703         fileio->fd = unix_handle;  /* FIXME */
704         fileio->event = hEvent;
705         NtResetEvent(hEvent, NULL);
706
707         io_status->Information = 0;
708         io_status->u.Status = STATUS_PENDING;
709         ret = fileio_queue_async(fileio, io_status, FALSE);
710         if (ret != STATUS_SUCCESS)
711         {
712             wine_server_release_fd( hFile, unix_handle );
713             if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
714             RtlFreeHeap(GetProcessHeap(), 0, fileio);
715             return ret;
716         }
717         if (flags & FD_FLAG_TIMEOUT)
718         {
719             ret = NtWaitForSingleObject(hEvent, TRUE, NULL);
720             NtClose(hEvent);
721             if (ret != STATUS_USER_APC)
722                 fileio->queue_apc_on_error = 1;
723         }
724         else
725         {
726             LARGE_INTEGER   timeout;
727
728             /* let some APC be run, this will write as much data as possible */
729             timeout.u.LowPart = timeout.u.HighPart = 0;
730             ret = NtDelayExecution( TRUE, &timeout );
731             /* the apc didn't run and therefore the completion routine now
732              * needs to be sent errors.
733              * Note that there is no race between setting this flag and
734              * returning errors because apc's are run only during alertable
735              * waits */
736             if (ret != STATUS_USER_APC)
737                 fileio->queue_apc_on_error = 1;
738         }
739         return io_status->u.Status;
740     }
741
742     if (offset)
743     {
744         FILE_POSITION_INFORMATION   fpi;
745
746         fpi.CurrentByteOffset = *offset;
747         io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi),
748                                                    FilePositionInformation);
749         if (io_status->u.Status)
750         {
751             wine_server_release_fd( hFile, unix_handle );
752             return io_status->u.Status;
753         }
754     }
755
756     /* synchronous file write */
757     while ((io_status->Information = write( unix_handle, buffer, length )) == -1)
758     {
759         if ((errno == EAGAIN) || (errno == EINTR)) continue;
760         if (errno == EFAULT)
761         {
762             io_status->Information = 0;
763             io_status->u.Status = STATUS_INVALID_USER_BUFFER;
764         }
765         else if (errno == ENOSPC) io_status->u.Status = STATUS_DISK_FULL;
766         else io_status->u.Status = FILE_GetNtStatus();
767         break;
768     }
769     wine_server_release_fd( hFile, unix_handle );
770     return io_status->u.Status;
771 }
772
773 /**************************************************************************
774  *              NtDeviceIoControlFile                   [NTDLL.@]
775  *              ZwDeviceIoControlFile                   [NTDLL.@]
776  *
777  * Perform an I/O control operation on an open file handle.
778  *
779  * PARAMS
780  *  DeviceHandle     [I] Handle returned from ZwOpenFile() or ZwCreateFile()
781  *  Event            [I] Event to signal upon completion (or NULL)
782  *  ApcRoutine       [I] Callback to call upon completion (or NULL)
783  *  ApcContext       [I] Context for ApcRoutine (or NULL)
784  *  IoStatusBlock    [O] Receives information about the operation on return
785  *  IoControlCode    [I] Control code for the operation to perform
786  *  InputBuffer      [I] Source for any input data required (or NULL)
787  *  InputBufferSize  [I] Size of InputBuffer
788  *  OutputBuffer     [O] Source for any output data returned (or NULL)
789  *  OutputBufferSize [I] Size of OutputBuffer
790  *
791  * RETURNS
792  *  Success: 0. IoStatusBlock is updated.
793  *  Failure: An NTSTATUS error code describing the error.
794  */
795 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE DeviceHandle, HANDLE hEvent,
796                                       PIO_APC_ROUTINE UserApcRoutine, 
797                                       PVOID UserApcContext,
798                                       PIO_STATUS_BLOCK IoStatusBlock,
799                                       ULONG IoControlCode,
800                                       PVOID InputBuffer,
801                                       ULONG InputBufferSize,
802                                       PVOID OutputBuffer,
803                                       ULONG OutputBufferSize)
804 {
805     TRACE("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx)\n",
806           DeviceHandle, hEvent, UserApcRoutine, UserApcContext,
807           IoStatusBlock, IoControlCode, 
808           InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize);
809
810     if (CDROM_DeviceIoControl(DeviceHandle, hEvent,
811                               UserApcRoutine, UserApcContext,
812                               IoStatusBlock, IoControlCode,
813                               InputBuffer, InputBufferSize,
814                               OutputBuffer, OutputBufferSize) == STATUS_NO_SUCH_DEVICE)
815     {
816         /* it wasn't a CDROM */
817         FIXME("Unimplemented dwIoControlCode=%08lx\n", IoControlCode);
818         IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
819         IoStatusBlock->Information = 0;
820         if (hEvent) NtSetEvent(hEvent, NULL);
821     }
822     return IoStatusBlock->u.Status;
823 }
824
825 /******************************************************************************
826  * NtFsControlFile [NTDLL.@]
827  * ZwFsControlFile [NTDLL.@]
828  */
829 NTSTATUS WINAPI NtFsControlFile(
830         IN HANDLE DeviceHandle,
831         IN HANDLE Event OPTIONAL,
832         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
833         IN PVOID ApcContext OPTIONAL,
834         OUT PIO_STATUS_BLOCK IoStatusBlock,
835         IN ULONG IoControlCode,
836         IN PVOID InputBuffer,
837         IN ULONG InputBufferSize,
838         OUT PVOID OutputBuffer,
839         IN ULONG OutputBufferSize)
840 {
841         FIXME("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx): stub\n",
842         DeviceHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,IoControlCode,
843         InputBuffer,InputBufferSize,OutputBuffer,OutputBufferSize);
844         return 0;
845 }
846
847 /******************************************************************************
848  *  NtSetVolumeInformationFile          [NTDLL.@]
849  *  ZwSetVolumeInformationFile          [NTDLL.@]
850  *
851  * Set volume information for an open file handle.
852  *
853  * PARAMS
854  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
855  *  IoStatusBlock      [O] Receives information about the operation on return
856  *  FsInformation      [I] Source for volume information
857  *  Length             [I] Size of FsInformation
858  *  FsInformationClass [I] Type of volume information to set
859  *
860  * RETURNS
861  *  Success: 0. IoStatusBlock is updated.
862  *  Failure: An NTSTATUS error code describing the error.
863  */
864 NTSTATUS WINAPI NtSetVolumeInformationFile(
865         IN HANDLE FileHandle,
866         PIO_STATUS_BLOCK IoStatusBlock,
867         PVOID FsInformation,
868         ULONG Length,
869         FS_INFORMATION_CLASS FsInformationClass)
870 {
871         FIXME("(%p,%p,%p,0x%08lx,0x%08x) stub\n",
872         FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
873         return 0;
874 }
875
876 /******************************************************************************
877  *  NtQueryInformationFile              [NTDLL.@]
878  *  ZwQueryInformationFile              [NTDLL.@]
879  *
880  * Get information about an open file handle.
881  *
882  * PARAMS
883  *  hFile    [I] Handle returned from ZwOpenFile() or ZwCreateFile()
884  *  io       [O] Receives information about the operation on return
885  *  ptr      [O] Destination for file information
886  *  len      [I] Size of FileInformation
887  *  class    [I] Type of file information to get
888  *
889  * RETURNS
890  *  Success: 0. IoStatusBlock and FileInformation are updated.
891  *  Failure: An NTSTATUS error code describing the error.
892  */
893 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
894                                         PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
895 {
896     static const size_t info_sizes[] =
897     {
898         0,
899         sizeof(FILE_DIRECTORY_INFORMATION),            /* FileDirectoryInformation */
900         sizeof(FILE_FULL_DIRECTORY_INFORMATION),       /* FileFullDirectoryInformation */
901         sizeof(FILE_BOTH_DIRECTORY_INFORMATION),       /* FileBothDirectoryInformation */
902         sizeof(FILE_BASIC_INFORMATION),                /* FileBasicInformation */
903         sizeof(FILE_STANDARD_INFORMATION),             /* FileStandardInformation */
904         sizeof(FILE_INTERNAL_INFORMATION),             /* FileInternalInformation */
905         sizeof(FILE_EA_INFORMATION),                   /* FileEaInformation */
906         sizeof(FILE_ACCESS_INFORMATION),               /* FileAccessInformation */
907         sizeof(FILE_NAME_INFORMATION)-sizeof(WCHAR),   /* FileNameInformation */
908         sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
909         0,                                             /* FileLinkInformation */
910         sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR),  /* FileNamesInformation */
911         sizeof(FILE_DISPOSITION_INFORMATION),          /* FileDispositionInformation */
912         sizeof(FILE_POSITION_INFORMATION),             /* FilePositionInformation */
913         sizeof(FILE_FULL_EA_INFORMATION),              /* FileFullEaInformation */
914         sizeof(FILE_MODE_INFORMATION),                 /* FileModeInformation */
915         sizeof(FILE_ALIGNMENT_INFORMATION),            /* FileAlignmentInformation */
916         sizeof(FILE_ALL_INFORMATION)-sizeof(WCHAR),    /* FileAllInformation */
917         sizeof(FILE_ALLOCATION_INFORMATION),           /* FileAllocationInformation */
918         sizeof(FILE_END_OF_FILE_INFORMATION),          /* FileEndOfFileInformation */
919         0,                                             /* FileAlternateNameInformation */
920         sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
921         0,                                             /* FilePipeInformation */
922         0,                                             /* FilePipeLocalInformation */
923         0,                                             /* FilePipeRemoteInformation */
924         0,                                             /* FileMailslotQueryInformation */
925         0,                                             /* FileMailslotSetInformation */
926         0,                                             /* FileCompressionInformation */
927         0,                                             /* FileObjectIdInformation */
928         0,                                             /* FileCompletionInformation */
929         0,                                             /* FileMoveClusterInformation */
930         0,                                             /* FileQuotaInformation */
931         0,                                             /* FileReparsePointInformation */
932         0,                                             /* FileNetworkOpenInformation */
933         0,                                             /* FileAttributeTagInformation */
934         0                                              /* FileTrackingInformation */
935     };
936
937     struct stat st;
938     int fd;
939
940     TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", hFile, io, ptr, len, class);
941
942     io->Information = 0;
943
944     if (class <= 0 || class >= FileMaximumInformation)
945         return io->u.Status = STATUS_INVALID_INFO_CLASS;
946     if (!info_sizes[class])
947     {
948         FIXME("Unsupported class (%d)\n", class);
949         return io->u.Status = STATUS_NOT_IMPLEMENTED;
950     }
951     if (len < info_sizes[class])
952         return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
953
954     if ((io->u.Status = wine_server_handle_to_fd( hFile, 0, &fd, NULL )))
955         return io->u.Status;
956
957     switch (class)
958     {
959     case FileBasicInformation:
960         {
961             FILE_BASIC_INFORMATION *info = ptr;
962
963             if (fstat( fd, &st ) == -1)
964                 io->u.Status = FILE_GetNtStatus();
965             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
966                 io->u.Status = STATUS_INVALID_INFO_CLASS;
967             else
968             {
969                 if (S_ISDIR(st.st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
970                 else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
971                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
972                     info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
973                 RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime);
974                 RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime);
975                 RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime);
976                 RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime);
977             }
978         }
979         break;
980     case FileStandardInformation:
981         {
982             FILE_STANDARD_INFORMATION *info = ptr;
983
984             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
985             else
986             {
987                 if ((info->Directory = S_ISDIR(st.st_mode)))
988                 {
989                     info->AllocationSize.QuadPart = 0;
990                     info->EndOfFile.QuadPart      = 0;
991                     info->NumberOfLinks           = 1;
992                     info->DeletePending           = FALSE;
993                 }
994                 else
995                 {
996                     info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
997                     info->EndOfFile.QuadPart      = st.st_size;
998                     info->NumberOfLinks           = st.st_nlink;
999                     info->DeletePending           = FALSE; /* FIXME */
1000                 }
1001             }
1002         }
1003         break;
1004     case FilePositionInformation:
1005         {
1006             FILE_POSITION_INFORMATION *info = ptr;
1007             off_t res = lseek( fd, 0, SEEK_CUR );
1008             if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
1009             else info->CurrentByteOffset.QuadPart = res;
1010         }
1011         break;
1012     case FileInternalInformation:
1013         {
1014             FILE_INTERNAL_INFORMATION *info = ptr;
1015
1016             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1017             else info->IndexNumber.QuadPart = st.st_ino;
1018         }
1019         break;
1020     case FileEaInformation:
1021         {
1022             FILE_EA_INFORMATION *info = ptr;
1023             info->EaSize = 0;
1024         }
1025         break;
1026     case FileEndOfFileInformation:
1027         {
1028             FILE_END_OF_FILE_INFORMATION *info = ptr;
1029
1030             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1031             else info->EndOfFile.QuadPart = S_ISDIR(st.st_mode) ? 0 : st.st_size;
1032         }
1033         break;
1034     case FileAllInformation:
1035         {
1036             FILE_ALL_INFORMATION *info = ptr;
1037
1038             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1039             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1040                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1041             else
1042             {
1043                 if ((info->StandardInformation.Directory = S_ISDIR(st.st_mode)))
1044                 {
1045                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1046                     info->StandardInformation.AllocationSize.QuadPart = 0;
1047                     info->StandardInformation.EndOfFile.QuadPart      = 0;
1048                     info->StandardInformation.NumberOfLinks           = 1;
1049                     info->StandardInformation.DeletePending           = FALSE;
1050                 }
1051                 else
1052                 {
1053                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1054                     info->StandardInformation.AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1055                     info->StandardInformation.EndOfFile.QuadPart      = st.st_size;
1056                     info->StandardInformation.NumberOfLinks           = st.st_nlink;
1057                     info->StandardInformation.DeletePending           = FALSE; /* FIXME */
1058                 }
1059                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1060                     info->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_READONLY;
1061                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.CreationTime);
1062                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.LastWriteTime);
1063                 RtlSecondsSince1970ToTime( st.st_ctime, &info->BasicInformation.ChangeTime);
1064                 RtlSecondsSince1970ToTime( st.st_atime, &info->BasicInformation.LastAccessTime);
1065                 info->InternalInformation.IndexNumber.QuadPart = st.st_ino;
1066                 info->EaInformation.EaSize = 0;
1067                 info->AccessInformation.AccessFlags = 0;  /* FIXME */
1068                 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
1069                 info->ModeInformation.Mode = 0;  /* FIXME */
1070                 info->AlignmentInformation.AlignmentRequirement = 1;  /* FIXME */
1071                 info->NameInformation.FileNameLength = 0;
1072                 io->Information = sizeof(*info) - sizeof(WCHAR);
1073             }
1074         }
1075         break;
1076     default:
1077         FIXME("Unsupported class (%d)\n", class);
1078         io->u.Status = STATUS_NOT_IMPLEMENTED;
1079         break;
1080     }
1081     wine_server_release_fd( hFile, fd );
1082     if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
1083     return io->u.Status;
1084 }
1085
1086 /******************************************************************************
1087  *  NtSetInformationFile                [NTDLL.@]
1088  *  ZwSetInformationFile                [NTDLL.@]
1089  *
1090  * Set information about an open file handle.
1091  *
1092  * PARAMS
1093  *  handle  [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1094  *  io      [O] Receives information about the operation on return
1095  *  ptr     [I] Source for file information
1096  *  len     [I] Size of FileInformation
1097  *  class   [I] Type of file information to set
1098  *
1099  * RETURNS
1100  *  Success: 0. io is updated.
1101  *  Failure: An NTSTATUS error code describing the error.
1102  */
1103 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
1104                                      PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
1105 {
1106     int fd;
1107
1108     TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", handle, io, ptr, len, class);
1109
1110     if ((io->u.Status = wine_server_handle_to_fd( handle, 0, &fd, NULL )))
1111         return io->u.Status;
1112
1113     io->u.Status = STATUS_SUCCESS;
1114     switch (class)
1115     {
1116     case FileBasicInformation:
1117         if (len >= sizeof(FILE_BASIC_INFORMATION))
1118         {
1119             struct stat st;
1120             const FILE_BASIC_INFORMATION *info = ptr;
1121
1122             if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
1123             {
1124                 ULONGLONG sec, nsec;
1125                 struct timeval tv[2];
1126
1127                 if (!info->LastAccessTime.QuadPart || !info->LastWriteTime.QuadPart)
1128                 {
1129
1130                     tv[0].tv_sec = tv[0].tv_usec = 0;
1131                     tv[1].tv_sec = tv[1].tv_usec = 0;
1132                     if (!fstat( fd, &st ))
1133                     {
1134                         tv[0].tv_sec = st.st_atime;
1135                         tv[1].tv_sec = st.st_mtime;
1136                     }
1137                 }
1138                 if (info->LastAccessTime.QuadPart)
1139                 {
1140                     sec = RtlLargeIntegerDivide( info->LastAccessTime.QuadPart, 10000000, &nsec );
1141                     tv[0].tv_sec = sec - SECS_1601_TO_1970;
1142                     tv[0].tv_usec = (UINT)nsec / 10;
1143                 }
1144                 if (info->LastWriteTime.QuadPart)
1145                 {
1146                     sec = RtlLargeIntegerDivide( info->LastWriteTime.QuadPart, 10000000, &nsec );
1147                     tv[1].tv_sec = sec - SECS_1601_TO_1970;
1148                     tv[1].tv_usec = (UINT)nsec / 10;
1149                 }
1150                 if (futimes( fd, tv ) == -1) io->u.Status = FILE_GetNtStatus();
1151             }
1152
1153             if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
1154             {
1155                 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1156                 else
1157                 {
1158                     if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
1159                     {
1160                         if (S_ISDIR( st.st_mode))
1161                             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
1162                         else
1163                             st.st_mode &= ~0222; /* clear write permission bits */
1164                     }
1165                     else
1166                     {
1167                         /* add write permission only where we already have read permission */
1168                         st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
1169                     }
1170                     if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
1171                 }
1172             }
1173         }
1174         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1175         break;
1176
1177     case FilePositionInformation:
1178         if (len >= sizeof(FILE_POSITION_INFORMATION))
1179         {
1180             const FILE_POSITION_INFORMATION *info = ptr;
1181
1182             if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
1183                 io->u.Status = FILE_GetNtStatus();
1184         }
1185         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1186         break;
1187
1188     case FileEndOfFileInformation:
1189         if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
1190         {
1191             struct stat st;
1192             const FILE_END_OF_FILE_INFORMATION *info = ptr;
1193
1194             /* first try normal truncate */
1195             if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1196
1197             /* now check for the need to extend the file */
1198             if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
1199             {
1200                 static const char zero;
1201
1202                 /* extend the file one byte beyond the requested size and then truncate it */
1203                 /* this should work around ftruncate implementations that can't extend files */
1204                 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
1205                     ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1206             }
1207             io->u.Status = FILE_GetNtStatus();
1208         }
1209         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1210         break;
1211
1212     default:
1213         FIXME("Unsupported class (%d)\n", class);
1214         io->u.Status = STATUS_NOT_IMPLEMENTED;
1215         break;
1216     }
1217     wine_server_release_fd( handle, fd );
1218     io->Information = 0;
1219     return io->u.Status;
1220 }
1221
1222
1223 /******************************************************************************
1224  *              NtQueryFullAttributesFile   (NTDLL.@)
1225  */
1226 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
1227                                            FILE_NETWORK_OPEN_INFORMATION *info )
1228 {
1229     ANSI_STRING unix_name;
1230     NTSTATUS status;
1231
1232     if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN,
1233                                               !(attr->Attributes & OBJ_CASE_INSENSITIVE) )))
1234     {
1235         struct stat st;
1236
1237         if (stat( unix_name.Buffer, &st ) == -1)
1238             status = FILE_GetNtStatus();
1239         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1240             status = STATUS_INVALID_INFO_CLASS;
1241         else
1242         {
1243             if (S_ISDIR(st.st_mode))
1244             {
1245                 info->FileAttributes          = FILE_ATTRIBUTE_DIRECTORY;
1246                 info->AllocationSize.QuadPart = 0;
1247                 info->EndOfFile.QuadPart      = 0;
1248             }
1249             else
1250             {
1251                 info->FileAttributes          = FILE_ATTRIBUTE_ARCHIVE;
1252                 info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1253                 info->EndOfFile.QuadPart      = st.st_size;
1254             }
1255             if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1256                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1257             RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime );
1258             RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime );
1259             RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime );
1260             RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime );
1261             if (DIR_is_hidden_file( attr->ObjectName ))
1262                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1263         }
1264         RtlFreeAnsiString( &unix_name );
1265     }
1266     else WARN("%s not found (%lx)\n", debugstr_us(attr->ObjectName), status );
1267     return status;
1268 }
1269
1270
1271 /******************************************************************************
1272  *              NtQueryAttributesFile   (NTDLL.@)
1273  *              ZwQueryAttributesFile   (NTDLL.@)
1274  */
1275 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
1276 {
1277     FILE_NETWORK_OPEN_INFORMATION full_info;
1278     NTSTATUS status;
1279
1280     if (!(status = NtQueryFullAttributesFile( attr, &full_info )))
1281     {
1282         info->CreationTime.QuadPart   = full_info.CreationTime.QuadPart;
1283         info->LastAccessTime.QuadPart = full_info.LastAccessTime.QuadPart;
1284         info->LastWriteTime.QuadPart  = full_info.LastWriteTime.QuadPart;
1285         info->ChangeTime.QuadPart     = full_info.ChangeTime.QuadPart;
1286         info->FileAttributes          = full_info.FileAttributes;
1287     }
1288     return status;
1289 }
1290
1291
1292 /******************************************************************************
1293  *  NtQueryVolumeInformationFile                [NTDLL.@]
1294  *  ZwQueryVolumeInformationFile                [NTDLL.@]
1295  *
1296  * Get volume information for an open file handle.
1297  *
1298  * PARAMS
1299  *  handle      [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1300  *  io          [O] Receives information about the operation on return
1301  *  buffer      [O] Destination for volume information
1302  *  length      [I] Size of FsInformation
1303  *  info_class  [I] Type of volume information to set
1304  *
1305  * RETURNS
1306  *  Success: 0. io and buffer are updated.
1307  *  Failure: An NTSTATUS error code describing the error.
1308  */
1309 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
1310                                               PVOID buffer, ULONG length,
1311                                               FS_INFORMATION_CLASS info_class )
1312 {
1313     int fd;
1314     struct stat st;
1315
1316     if ((io->u.Status = wine_server_handle_to_fd( handle, 0, &fd, NULL )) != STATUS_SUCCESS)
1317         return io->u.Status;
1318
1319     io->u.Status = STATUS_NOT_IMPLEMENTED;
1320     io->Information = 0;
1321
1322     switch( info_class )
1323     {
1324     case FileFsVolumeInformation:
1325         FIXME( "%p: volume info not supported\n", handle );
1326         break;
1327     case FileFsLabelInformation:
1328         FIXME( "%p: label info not supported\n", handle );
1329         break;
1330     case FileFsSizeInformation:
1331         if (length < sizeof(FILE_FS_SIZE_INFORMATION))
1332             io->u.Status = STATUS_BUFFER_TOO_SMALL;
1333         else
1334         {
1335             FILE_FS_SIZE_INFORMATION *info = buffer;
1336
1337             if (fstat( fd, &st ) < 0)
1338             {
1339                 io->u.Status = FILE_GetNtStatus();
1340                 break;
1341             }
1342             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1343             {
1344                 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
1345             }
1346             else
1347             {
1348                 /* Linux's fstatvfs is buggy */
1349 #if !defined(linux) || !defined(HAVE_FSTATFS)
1350                 struct statvfs stfs;
1351
1352                 if (fstatvfs( fd, &stfs ) < 0)
1353                 {
1354                     io->u.Status = FILE_GetNtStatus();
1355                     break;
1356                 }
1357                 info->BytesPerSector = stfs.f_frsize;
1358 #else
1359                 struct statfs stfs;
1360                 if (fstatfs( fd, &stfs ) < 0)
1361                 {
1362                     io->u.Status = FILE_GetNtStatus();
1363                     break;
1364                 }
1365                 info->BytesPerSector = stfs.f_bsize;
1366 #endif
1367                 info->TotalAllocationUnits.QuadPart = stfs.f_blocks;
1368                 info->AvailableAllocationUnits.QuadPart = stfs.f_bavail;
1369                 info->SectorsPerAllocationUnit = 1;
1370                 io->Information = sizeof(*info);
1371                 io->u.Status = STATUS_SUCCESS;
1372             }
1373         }
1374         break;
1375     case FileFsDeviceInformation:
1376         if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
1377             io->u.Status = STATUS_BUFFER_TOO_SMALL;
1378         else
1379         {
1380             FILE_FS_DEVICE_INFORMATION *info = buffer;
1381
1382             info->Characteristics = 0;
1383             if (fstat( fd, &st ) < 0)
1384             {
1385                 io->u.Status = FILE_GetNtStatus();
1386                 break;
1387             }
1388             if (S_ISCHR( st.st_mode ))
1389             {
1390                 info->DeviceType = FILE_DEVICE_UNKNOWN;
1391 #ifdef linux
1392                 switch(major(st.st_rdev))
1393                 {
1394                 case MEM_MAJOR:
1395                     info->DeviceType = FILE_DEVICE_NULL;
1396                     break;
1397                 case TTY_MAJOR:
1398                     info->DeviceType = FILE_DEVICE_SERIAL_PORT;
1399                     break;
1400                 case LP_MAJOR:
1401                     info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
1402                     break;
1403                 }
1404 #endif
1405             }
1406             else if (S_ISBLK( st.st_mode ))
1407             {
1408                 info->DeviceType = FILE_DEVICE_DISK;
1409             }
1410             else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
1411             {
1412                 info->DeviceType = FILE_DEVICE_NAMED_PIPE;
1413             }
1414             else  /* regular file or directory */
1415             {
1416 #if defined(linux) && defined(HAVE_FSTATFS)
1417                 struct statfs stfs;
1418
1419                 /* check for floppy disk */
1420                 if (major(st.st_dev) == FLOPPY_MAJOR)
1421                     info->Characteristics |= FILE_REMOVABLE_MEDIA;
1422
1423                 if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
1424                 switch (stfs.f_type)
1425                 {
1426                 case 0x9660:      /* iso9660 */
1427                 case 0x15013346:  /* udf */
1428                     info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
1429                     info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
1430                     break;
1431                 case 0x6969:  /* nfs */
1432                 case 0x517B:  /* smbfs */
1433                 case 0x564c:  /* ncpfs */
1434                     info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
1435                     info->Characteristics |= FILE_REMOTE_DEVICE;
1436                     break;
1437                 case 0x01021994:  /* tmpfs */
1438                 case 0x28cd3d45:  /* cramfs */
1439                 case 0x1373:      /* devfs */
1440                 case 0x9fa0:      /* procfs */
1441                     info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
1442                     break;
1443                 default:
1444                     info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1445                     break;
1446                 }
1447 #elif defined (__APPLE__)
1448 # include <IOKit/IOKitLib.h>
1449 # include <CoreFoundation/CFNumber.h> /* for kCFBooleanTrue, kCFBooleanFalse */
1450 # include <paths.h>
1451                 struct statfs stfs;
1452                 
1453                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1454                 
1455                 if (fstatfs( fd, &stfs ) < 0) break;
1456
1457                 /* stfs.f_type is reserved (always set to 0) so use IOKit */
1458                 kern_return_t kernResult = KERN_FAILURE; 
1459                 mach_port_t masterPort;
1460                 
1461                 char bsdName[6]; /* disk#\0 */
1462                 
1463                 strncpy(bsdName, stfs.f_mntfromname+strlen(_PATH_DEV) , 5);
1464                 bsdName[5] = 0;
1465
1466                 kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
1467
1468                 if (kernResult == KERN_SUCCESS)
1469                 {
1470                     CFMutableDictionaryRef matching = IOBSDNameMatching(masterPort, 0, bsdName);
1471                     
1472                     if (matching)
1473                     {
1474                         CFMutableDictionaryRef properties;
1475                         io_service_t devService = IOServiceGetMatchingService(masterPort, matching);
1476                         
1477                         if (IORegistryEntryCreateCFProperties(devService, 
1478                                                                 &properties,
1479                                                                 kCFAllocatorDefault, 0) != KERN_SUCCESS)
1480                                                                     break;
1481                         if ( CFEqual(
1482                                         CFDictionaryGetValue(properties, CFSTR("Removable")),
1483                                         kCFBooleanTrue)
1484                             ) info->Characteristics |= FILE_REMOVABLE_MEDIA;
1485                             
1486                         if ( CFEqual(
1487                                         CFDictionaryGetValue(properties, CFSTR("Writable")),
1488                                         kCFBooleanFalse)
1489                             ) info->Characteristics |= FILE_READ_ONLY_DEVICE;
1490
1491                         /*
1492                             NB : mounted disk image (.img/.dmg) don't provide specific type
1493                         */
1494                         CFStringRef type;
1495                         if ( (type = CFDictionaryGetValue(properties, CFSTR("Type"))) )
1496                         {
1497                             if ( CFStringCompare(type, CFSTR("CD-ROM"), 0) == kCFCompareEqualTo
1498                                 || CFStringCompare(type, CFSTR("DVD-ROM"), 0) == kCFCompareEqualTo
1499                             )
1500                             {
1501                                 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
1502                             }
1503                         } 
1504                         
1505                         if (properties)
1506                             CFRelease(properties);
1507                     }
1508                 }
1509 #else
1510                 static int warned;
1511                 if (!warned++) FIXME( "device info not properly supported on this platform\n" );
1512                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1513 #endif
1514                 info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
1515             }
1516             io->Information = sizeof(*info);
1517             io->u.Status = STATUS_SUCCESS;
1518         }
1519         break;
1520     case FileFsAttributeInformation:
1521         FIXME( "%p: attribute info not supported\n", handle );
1522         break;
1523     case FileFsControlInformation:
1524         FIXME( "%p: control info not supported\n", handle );
1525         break;
1526     case FileFsFullSizeInformation:
1527         FIXME( "%p: full size info not supported\n", handle );
1528         break;
1529     case FileFsObjectIdInformation:
1530         FIXME( "%p: object id info not supported\n", handle );
1531         break;
1532     case FileFsMaximumInformation:
1533         FIXME( "%p: maximum info not supported\n", handle );
1534         break;
1535     default:
1536         io->u.Status = STATUS_INVALID_PARAMETER;
1537         break;
1538     }
1539     wine_server_release_fd( handle, fd );
1540     return io->u.Status;
1541 }
1542
1543
1544 /******************************************************************
1545  *              NtFlushBuffersFile  (NTDLL.@)
1546  *
1547  * Flush any buffered data on an open file handle.
1548  *
1549  * PARAMS
1550  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1551  *  IoStatusBlock      [O] Receives information about the operation on return
1552  *
1553  * RETURNS
1554  *  Success: 0. IoStatusBlock is updated.
1555  *  Failure: An NTSTATUS error code describing the error.
1556  */
1557 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
1558 {
1559     NTSTATUS ret;
1560     HANDLE hEvent = NULL;
1561
1562     SERVER_START_REQ( flush_file )
1563     {
1564         req->handle = hFile;
1565         ret = wine_server_call( req );
1566         hEvent = reply->event;
1567     }
1568     SERVER_END_REQ;
1569     if (!ret && hEvent)
1570     {
1571         ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
1572         NtClose( hEvent );
1573     }
1574     return ret;
1575 }
1576
1577 /******************************************************************
1578  *              NtLockFile       (NTDLL.@)
1579  *
1580  *
1581  */
1582 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
1583                             PIO_APC_ROUTINE apc, void* apc_user,
1584                             PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
1585                             PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
1586                             BOOLEAN exclusive )
1587 {
1588     NTSTATUS    ret;
1589     HANDLE      handle;
1590     BOOLEAN     async;
1591
1592     if (apc || io_status || key)
1593     {
1594         FIXME("Unimplemented yet parameter\n");
1595         return STATUS_NOT_IMPLEMENTED;
1596     }
1597
1598     for (;;)
1599     {
1600         SERVER_START_REQ( lock_file )
1601         {
1602             req->handle      = hFile;
1603             req->offset_low  = offset->u.LowPart;
1604             req->offset_high = offset->u.HighPart;
1605             req->count_low   = count->u.LowPart;
1606             req->count_high  = count->u.HighPart;
1607             req->shared      = !exclusive;
1608             req->wait        = !dont_wait;
1609             ret = wine_server_call( req );
1610             handle = reply->handle;
1611             async  = reply->overlapped;
1612         }
1613         SERVER_END_REQ;
1614         if (ret != STATUS_PENDING)
1615         {
1616             if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
1617             return ret;
1618         }
1619
1620         if (async)
1621         {
1622             FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
1623             if (handle) NtClose( handle );
1624             return STATUS_PENDING;
1625         }
1626         if (handle)
1627         {
1628             NtWaitForSingleObject( handle, FALSE, NULL );
1629             NtClose( handle );
1630         }
1631         else
1632         {
1633             LARGE_INTEGER time;
1634     
1635             /* Unix lock conflict, sleep a bit and retry */
1636             time.QuadPart = 100 * (ULONGLONG)10000;
1637             time.QuadPart = -time.QuadPart;
1638             NtDelayExecution( FALSE, &time );
1639         }
1640     }
1641 }
1642
1643
1644 /******************************************************************
1645  *              NtUnlockFile    (NTDLL.@)
1646  *
1647  *
1648  */
1649 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
1650                               PLARGE_INTEGER offset, PLARGE_INTEGER count,
1651                               PULONG key )
1652 {
1653     NTSTATUS status;
1654
1655     TRACE( "%p %lx%08lx %lx%08lx\n",
1656            hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
1657
1658     if (io_status || key)
1659     {
1660         FIXME("Unimplemented yet parameter\n");
1661         return STATUS_NOT_IMPLEMENTED;
1662     }
1663
1664     SERVER_START_REQ( unlock_file )
1665     {
1666         req->handle      = hFile;
1667         req->offset_low  = offset->u.LowPart;
1668         req->offset_high = offset->u.HighPart;
1669         req->count_low   = count->u.LowPart;
1670         req->count_high  = count->u.HighPart;
1671         status = wine_server_call( req );
1672     }
1673     SERVER_END_REQ;
1674     return status;
1675 }
1676
1677 /******************************************************************
1678  *              NtCreateNamedPipeFile    (NTDLL.@)
1679  *
1680  *
1681  */
1682 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE FileHandle, ULONG DesiredAccess,
1683      POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock,
1684      ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions,
1685      ULONG NamedPipeType, ULONG ReadMode, ULONG CompletionMode,
1686      ULONG MaximumInstances, ULONG InboundQuota, ULONG OutboundQuota,
1687      PLARGE_INTEGER DefaultTimeout)
1688 {
1689     FIXME("(%p %lx %p %p %lx %ld %lx %ld %ld %ld %ld %ld %ld %p): stub\n",
1690           FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock,
1691           ShareAccess, CreateDisposition, CreateOptions, NamedPipeType,
1692           ReadMode, CompletionMode, MaximumInstances, InboundQuota,
1693           OutboundQuota, DefaultTimeout);
1694     return STATUS_NOT_IMPLEMENTED;
1695 }
1696
1697 /******************************************************************
1698  *              NtDeleteFile    (NTDLL.@)
1699  *
1700  *
1701  */
1702 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
1703 {
1704     NTSTATUS status;
1705     HANDLE hFile;
1706     IO_STATUS_BLOCK io;
1707
1708     TRACE("%p\n", ObjectAttributes);
1709     status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE, ObjectAttributes, 
1710                            &io, NULL, 0,
1711                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
1712                            FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
1713     if (status == STATUS_SUCCESS) status = NtClose(hFile);
1714     return status;
1715 }
1716
1717 /******************************************************************
1718  *              NtCancelIoFile    (NTDLL.@)
1719  *
1720  *
1721  */
1722 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
1723 {
1724     LARGE_INTEGER timeout;
1725
1726     TRACE("%p %p\n", hFile, io_status );
1727
1728     SERVER_START_REQ( cancel_async )
1729     {
1730         req->handle = hFile;
1731         wine_server_call( req );
1732     }
1733     SERVER_END_REQ;
1734     /* Let some APC be run, so that we can run the remaining APCs on hFile
1735      * either the cancelation of the pending one, but also the execution
1736      * of the queued APC, but not yet run. This is needed to ensure proper
1737      * clean-up of allocated data.
1738      */
1739     timeout.u.LowPart = timeout.u.HighPart = 0;
1740     return io_status->u.Status = NtDelayExecution( TRUE, &timeout );
1741 }