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