GetCPInfo should return FALSE if called with NULL info buffer.
[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 | S_IWGRP | S_IWOTH)))
970                     info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
971                 RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime);
972                 RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime);
973                 RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime);
974                 RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime);
975             }
976         }
977         break;
978     case FileStandardInformation:
979         {
980             FILE_STANDARD_INFORMATION *info = ptr;
981
982             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
983             else
984             {
985                 if ((info->Directory = S_ISDIR(st.st_mode)))
986                 {
987                     info->AllocationSize.QuadPart = 0;
988                     info->EndOfFile.QuadPart      = 0;
989                     info->NumberOfLinks           = 1;
990                     info->DeletePending           = FALSE;
991                 }
992                 else
993                 {
994                     info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
995                     info->EndOfFile.QuadPart      = st.st_size;
996                     info->NumberOfLinks           = st.st_nlink;
997                     info->DeletePending           = FALSE; /* FIXME */
998                 }
999             }
1000         }
1001         break;
1002     case FilePositionInformation:
1003         {
1004             FILE_POSITION_INFORMATION *info = ptr;
1005             off_t res = lseek( fd, 0, SEEK_CUR );
1006             if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
1007             else info->CurrentByteOffset.QuadPart = res;
1008         }
1009         break;
1010     case FileInternalInformation:
1011         {
1012             FILE_INTERNAL_INFORMATION *info = ptr;
1013
1014             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1015             else info->IndexNumber.QuadPart = st.st_ino;
1016         }
1017         break;
1018     case FileEaInformation:
1019         {
1020             FILE_EA_INFORMATION *info = ptr;
1021             info->EaSize = 0;
1022         }
1023         break;
1024     case FileEndOfFileInformation:
1025         {
1026             FILE_END_OF_FILE_INFORMATION *info = ptr;
1027
1028             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1029             else info->EndOfFile.QuadPart = S_ISDIR(st.st_mode) ? 0 : st.st_size;
1030         }
1031         break;
1032     case FileAllInformation:
1033         {
1034             FILE_ALL_INFORMATION *info = ptr;
1035
1036             if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1037             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1038                 io->u.Status = STATUS_INVALID_INFO_CLASS;
1039             else
1040             {
1041                 if ((info->StandardInformation.Directory = S_ISDIR(st.st_mode)))
1042                 {
1043                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1044                     info->StandardInformation.AllocationSize.QuadPart = 0;
1045                     info->StandardInformation.EndOfFile.QuadPart      = 0;
1046                     info->StandardInformation.NumberOfLinks           = 1;
1047                     info->StandardInformation.DeletePending           = FALSE;
1048                 }
1049                 else
1050                 {
1051                     info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1052                     info->StandardInformation.AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1053                     info->StandardInformation.EndOfFile.QuadPart      = st.st_size;
1054                     info->StandardInformation.NumberOfLinks           = st.st_nlink;
1055                     info->StandardInformation.DeletePending           = FALSE; /* FIXME */
1056                 }
1057                 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1058                     info->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_READONLY;
1059                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.CreationTime);
1060                 RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.LastWriteTime);
1061                 RtlSecondsSince1970ToTime( st.st_ctime, &info->BasicInformation.ChangeTime);
1062                 RtlSecondsSince1970ToTime( st.st_atime, &info->BasicInformation.LastAccessTime);
1063                 info->InternalInformation.IndexNumber.QuadPart = st.st_ino;
1064                 info->EaInformation.EaSize = 0;
1065                 info->AccessInformation.AccessFlags = 0;  /* FIXME */
1066                 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
1067                 info->ModeInformation.Mode = 0;  /* FIXME */
1068                 info->AlignmentInformation.AlignmentRequirement = 1;  /* FIXME */
1069                 info->NameInformation.FileNameLength = 0;
1070                 io->Information = sizeof(*info) - sizeof(WCHAR);
1071             }
1072         }
1073         break;
1074     default:
1075         FIXME("Unsupported class (%d)\n", class);
1076         io->u.Status = STATUS_NOT_IMPLEMENTED;
1077         break;
1078     }
1079     wine_server_release_fd( hFile, fd );
1080     if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
1081     return io->u.Status;
1082 }
1083
1084 /******************************************************************************
1085  *  NtSetInformationFile                [NTDLL.@]
1086  *  ZwSetInformationFile                [NTDLL.@]
1087  *
1088  * Set information about an open file handle.
1089  *
1090  * PARAMS
1091  *  handle  [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1092  *  io      [O] Receives information about the operation on return
1093  *  ptr     [I] Source for file information
1094  *  len     [I] Size of FileInformation
1095  *  class   [I] Type of file information to set
1096  *
1097  * RETURNS
1098  *  Success: 0. io is updated.
1099  *  Failure: An NTSTATUS error code describing the error.
1100  */
1101 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
1102                                      PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
1103 {
1104     int fd;
1105
1106     TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", handle, io, ptr, len, class);
1107
1108     if ((io->u.Status = wine_server_handle_to_fd( handle, 0, &fd, NULL )))
1109         return io->u.Status;
1110
1111     io->u.Status = STATUS_SUCCESS;
1112     switch (class)
1113     {
1114     case FileBasicInformation:
1115         if (len >= sizeof(FILE_BASIC_INFORMATION))
1116         {
1117             struct stat st;
1118             const FILE_BASIC_INFORMATION *info = ptr;
1119
1120             if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
1121             {
1122                 ULONGLONG sec, nsec;
1123                 struct timeval tv[2];
1124
1125                 if (!info->LastAccessTime.QuadPart || !info->LastWriteTime.QuadPart)
1126                 {
1127
1128                     tv[0].tv_sec = tv[0].tv_usec = 0;
1129                     tv[1].tv_sec = tv[1].tv_usec = 0;
1130                     if (!fstat( fd, &st ))
1131                     {
1132                         tv[0].tv_sec = st.st_atime;
1133                         tv[1].tv_sec = st.st_mtime;
1134                     }
1135                 }
1136                 if (info->LastAccessTime.QuadPart)
1137                 {
1138                     sec = RtlLargeIntegerDivide( info->LastAccessTime.QuadPart, 10000000, &nsec );
1139                     tv[0].tv_sec = sec - SECS_1601_TO_1970;
1140                     tv[0].tv_usec = (UINT)nsec / 10;
1141                 }
1142                 if (info->LastWriteTime.QuadPart)
1143                 {
1144                     sec = RtlLargeIntegerDivide( info->LastWriteTime.QuadPart, 10000000, &nsec );
1145                     tv[1].tv_sec = sec - SECS_1601_TO_1970;
1146                     tv[1].tv_usec = (UINT)nsec / 10;
1147                 }
1148                 if (futimes( fd, tv ) == -1) io->u.Status = FILE_GetNtStatus();
1149             }
1150
1151             if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
1152             {
1153                 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
1154                 else
1155                 {
1156                     if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
1157                     {
1158                         if (S_ISDIR( st.st_mode))
1159                             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
1160                         else
1161                             st.st_mode &= ~0222; /* clear write permission bits */
1162                     }
1163                     else
1164                     {
1165                         /* add write permission only where we already have read permission */
1166                         st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
1167                     }
1168                     if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
1169                 }
1170             }
1171         }
1172         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1173         break;
1174
1175     case FilePositionInformation:
1176         if (len >= sizeof(FILE_POSITION_INFORMATION))
1177         {
1178             const FILE_POSITION_INFORMATION *info = ptr;
1179
1180             if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
1181                 io->u.Status = FILE_GetNtStatus();
1182         }
1183         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1184         break;
1185
1186     case FileEndOfFileInformation:
1187         if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
1188         {
1189             struct stat st;
1190             const FILE_END_OF_FILE_INFORMATION *info = ptr;
1191
1192             /* first try normal truncate */
1193             if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1194
1195             /* now check for the need to extend the file */
1196             if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
1197             {
1198                 static const char zero;
1199
1200                 /* extend the file one byte beyond the requested size and then truncate it */
1201                 /* this should work around ftruncate implementations that can't extend files */
1202                 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
1203                     ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
1204             }
1205             io->u.Status = FILE_GetNtStatus();
1206         }
1207         else io->u.Status = STATUS_INVALID_PARAMETER_3;
1208         break;
1209
1210     default:
1211         FIXME("Unsupported class (%d)\n", class);
1212         io->u.Status = STATUS_NOT_IMPLEMENTED;
1213         break;
1214     }
1215     wine_server_release_fd( handle, fd );
1216     io->Information = 0;
1217     return io->u.Status;
1218 }
1219
1220
1221 /******************************************************************************
1222  *              NtQueryFullAttributesFile   (NTDLL.@)
1223  */
1224 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
1225                                            FILE_NETWORK_OPEN_INFORMATION *info )
1226 {
1227     ANSI_STRING unix_name;
1228     NTSTATUS status;
1229
1230     if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN,
1231                                               !(attr->Attributes & OBJ_CASE_INSENSITIVE) )))
1232     {
1233         struct stat st;
1234
1235         if (stat( unix_name.Buffer, &st ) == -1)
1236             status = FILE_GetNtStatus();
1237         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1238             status = STATUS_INVALID_INFO_CLASS;
1239         else
1240         {
1241             if (S_ISDIR(st.st_mode))
1242             {
1243                 info->FileAttributes          = FILE_ATTRIBUTE_DIRECTORY;
1244                 info->AllocationSize.QuadPart = 0;
1245                 info->EndOfFile.QuadPart      = 0;
1246             }
1247             else
1248             {
1249                 info->FileAttributes          = FILE_ATTRIBUTE_ARCHIVE;
1250                 info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512;
1251                 info->EndOfFile.QuadPart      = st.st_size;
1252             }
1253             if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1254                 info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
1255             RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime );
1256             RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime );
1257             RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime );
1258             RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime );
1259             if (DIR_is_hidden_file( attr->ObjectName ))
1260                 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1261         }
1262         RtlFreeAnsiString( &unix_name );
1263     }
1264     else WARN("%s not found (%lx)\n", debugstr_us(attr->ObjectName), status );
1265     return status;
1266 }
1267
1268
1269 /******************************************************************************
1270  *              NtQueryAttributesFile   (NTDLL.@)
1271  *              ZwQueryAttributesFile   (NTDLL.@)
1272  */
1273 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
1274 {
1275     FILE_NETWORK_OPEN_INFORMATION full_info;
1276     NTSTATUS status;
1277
1278     if (!(status = NtQueryFullAttributesFile( attr, &full_info )))
1279     {
1280         info->CreationTime.QuadPart   = full_info.CreationTime.QuadPart;
1281         info->LastAccessTime.QuadPart = full_info.LastAccessTime.QuadPart;
1282         info->LastWriteTime.QuadPart  = full_info.LastWriteTime.QuadPart;
1283         info->ChangeTime.QuadPart     = full_info.ChangeTime.QuadPart;
1284         info->FileAttributes          = full_info.FileAttributes;
1285     }
1286     return status;
1287 }
1288
1289
1290 /******************************************************************************
1291  *  NtQueryVolumeInformationFile                [NTDLL.@]
1292  *  ZwQueryVolumeInformationFile                [NTDLL.@]
1293  *
1294  * Get volume information for an open file handle.
1295  *
1296  * PARAMS
1297  *  handle      [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1298  *  io          [O] Receives information about the operation on return
1299  *  buffer      [O] Destination for volume information
1300  *  length      [I] Size of FsInformation
1301  *  info_class  [I] Type of volume information to set
1302  *
1303  * RETURNS
1304  *  Success: 0. io and buffer are updated.
1305  *  Failure: An NTSTATUS error code describing the error.
1306  */
1307 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
1308                                               PVOID buffer, ULONG length,
1309                                               FS_INFORMATION_CLASS info_class )
1310 {
1311     int fd;
1312     struct stat st;
1313
1314     if ((io->u.Status = wine_server_handle_to_fd( handle, 0, &fd, NULL )) != STATUS_SUCCESS)
1315         return io->u.Status;
1316
1317     io->u.Status = STATUS_NOT_IMPLEMENTED;
1318     io->Information = 0;
1319
1320     switch( info_class )
1321     {
1322     case FileFsVolumeInformation:
1323         FIXME( "%p: volume info not supported\n", handle );
1324         break;
1325     case FileFsLabelInformation:
1326         FIXME( "%p: label info not supported\n", handle );
1327         break;
1328     case FileFsSizeInformation:
1329         if (length < sizeof(FILE_FS_SIZE_INFORMATION))
1330             io->u.Status = STATUS_BUFFER_TOO_SMALL;
1331         else
1332         {
1333             FILE_FS_SIZE_INFORMATION *info = buffer;
1334
1335             if (fstat( fd, &st ) < 0)
1336             {
1337                 io->u.Status = FILE_GetNtStatus();
1338                 break;
1339             }
1340             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1341             {
1342                 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
1343             }
1344             else
1345             {
1346                 /* Linux's fstatvfs is buggy */
1347 #if !defined(linux) || !defined(HAVE_FSTATFS)
1348                 struct statvfs stfs;
1349
1350                 if (fstatvfs( fd, &stfs ) < 0)
1351                 {
1352                     io->u.Status = FILE_GetNtStatus();
1353                     break;
1354                 }
1355                 info->BytesPerSector = stfs.f_frsize;
1356 #else
1357                 struct statfs stfs;
1358                 if (fstatfs( fd, &stfs ) < 0)
1359                 {
1360                     io->u.Status = FILE_GetNtStatus();
1361                     break;
1362                 }
1363                 info->BytesPerSector = stfs.f_bsize;
1364 #endif
1365                 info->TotalAllocationUnits.QuadPart = stfs.f_blocks;
1366                 info->AvailableAllocationUnits.QuadPart = stfs.f_bavail;
1367                 info->SectorsPerAllocationUnit = 1;
1368                 io->Information = sizeof(*info);
1369                 io->u.Status = STATUS_SUCCESS;
1370             }
1371         }
1372         break;
1373     case FileFsDeviceInformation:
1374         if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
1375             io->u.Status = STATUS_BUFFER_TOO_SMALL;
1376         else
1377         {
1378             FILE_FS_DEVICE_INFORMATION *info = buffer;
1379
1380             info->Characteristics = 0;
1381             if (fstat( fd, &st ) < 0)
1382             {
1383                 io->u.Status = FILE_GetNtStatus();
1384                 break;
1385             }
1386             if (S_ISCHR( st.st_mode ))
1387             {
1388                 info->DeviceType = FILE_DEVICE_UNKNOWN;
1389 #ifdef linux
1390                 switch(major(st.st_rdev))
1391                 {
1392                 case MEM_MAJOR:
1393                     info->DeviceType = FILE_DEVICE_NULL;
1394                     break;
1395                 case TTY_MAJOR:
1396                     info->DeviceType = FILE_DEVICE_SERIAL_PORT;
1397                     break;
1398                 case LP_MAJOR:
1399                     info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
1400                     break;
1401                 }
1402 #endif
1403             }
1404             else if (S_ISBLK( st.st_mode ))
1405             {
1406                 info->DeviceType = FILE_DEVICE_DISK;
1407             }
1408             else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
1409             {
1410                 info->DeviceType = FILE_DEVICE_NAMED_PIPE;
1411             }
1412             else  /* regular file or directory */
1413             {
1414 #if defined(linux) && defined(HAVE_FSTATFS)
1415                 struct statfs stfs;
1416
1417                 /* check for floppy disk */
1418                 if (major(st.st_dev) == FLOPPY_MAJOR)
1419                     info->Characteristics |= FILE_REMOVABLE_MEDIA;
1420
1421                 if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
1422                 switch (stfs.f_type)
1423                 {
1424                 case 0x9660:      /* iso9660 */
1425                 case 0x15013346:  /* udf */
1426                     info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
1427                     info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
1428                     break;
1429                 case 0x6969:  /* nfs */
1430                 case 0x517B:  /* smbfs */
1431                 case 0x564c:  /* ncpfs */
1432                     info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
1433                     info->Characteristics |= FILE_REMOTE_DEVICE;
1434                     break;
1435                 case 0x01021994:  /* tmpfs */
1436                 case 0x28cd3d45:  /* cramfs */
1437                 case 0x1373:      /* devfs */
1438                 case 0x9fa0:      /* procfs */
1439                     info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
1440                     break;
1441                 default:
1442                     info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1443                     break;
1444                 }
1445 #elif defined (__APPLE__)
1446 # include <IOKit/IOKitLib.h>
1447 # include <CoreFoundation/CFNumber.h> /* for kCFBooleanTrue, kCFBooleanFalse */
1448 # include <paths.h>
1449                 struct statfs stfs;
1450                 
1451                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1452                 
1453                 if (fstatfs( fd, &stfs ) < 0) break;
1454
1455                 /* stfs.f_type is reserved (always set to 0) so use IOKit */
1456                 kern_return_t kernResult = KERN_FAILURE; 
1457                 mach_port_t masterPort;
1458                 
1459                 char bsdName[6]; /* disk#\0 */
1460                 
1461                 strncpy(bsdName, stfs.f_mntfromname+strlen(_PATH_DEV) , 5);
1462                 bsdName[5] = 0;
1463
1464                 kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
1465
1466                 if (kernResult == KERN_SUCCESS)
1467                 {
1468                     CFMutableDictionaryRef matching = IOBSDNameMatching(masterPort, 0, bsdName);
1469                     
1470                     if (matching)
1471                     {
1472                         CFMutableDictionaryRef properties;
1473                         io_service_t devService = IOServiceGetMatchingService(masterPort, matching);
1474                         
1475                         if (IORegistryEntryCreateCFProperties(devService, 
1476                                                                 &properties,
1477                                                                 kCFAllocatorDefault, 0) != KERN_SUCCESS)
1478                                                                     break;
1479                         if ( CFEqual(
1480                                         CFDictionaryGetValue(properties, CFSTR("Removable")),
1481                                         kCFBooleanTrue)
1482                             ) info->Characteristics |= FILE_REMOVABLE_MEDIA;
1483                             
1484                         if ( CFEqual(
1485                                         CFDictionaryGetValue(properties, CFSTR("Writable")),
1486                                         kCFBooleanFalse)
1487                             ) info->Characteristics |= FILE_READ_ONLY_DEVICE;
1488
1489                         /*
1490                             NB : mounted disk image (.img/.dmg) don't provide specific type
1491                         */
1492                         CFStringRef type;
1493                         if ( (type = CFDictionaryGetValue(properties, CFSTR("Type"))) )
1494                         {
1495                             if ( CFStringCompare(type, CFSTR("CD-ROM"), 0) == kCFCompareEqualTo
1496                                 || CFStringCompare(type, CFSTR("DVD-ROM"), 0) == kCFCompareEqualTo
1497                             )
1498                             {
1499                                 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
1500                             }
1501                         } 
1502                         
1503                         if (properties)
1504                             CFRelease(properties);
1505                     }
1506                 }
1507 #else
1508                 static int warned;
1509                 if (!warned++) FIXME( "device info not properly supported on this platform\n" );
1510                 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1511 #endif
1512                 info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
1513             }
1514             io->Information = sizeof(*info);
1515             io->u.Status = STATUS_SUCCESS;
1516         }
1517         break;
1518     case FileFsAttributeInformation:
1519         FIXME( "%p: attribute info not supported\n", handle );
1520         break;
1521     case FileFsControlInformation:
1522         FIXME( "%p: control info not supported\n", handle );
1523         break;
1524     case FileFsFullSizeInformation:
1525         FIXME( "%p: full size info not supported\n", handle );
1526         break;
1527     case FileFsObjectIdInformation:
1528         FIXME( "%p: object id info not supported\n", handle );
1529         break;
1530     case FileFsMaximumInformation:
1531         FIXME( "%p: maximum info not supported\n", handle );
1532         break;
1533     default:
1534         io->u.Status = STATUS_INVALID_PARAMETER;
1535         break;
1536     }
1537     wine_server_release_fd( handle, fd );
1538     return io->u.Status;
1539 }
1540
1541
1542 /******************************************************************
1543  *              NtFlushBuffersFile  (NTDLL.@)
1544  *
1545  * Flush any buffered data on an open file handle.
1546  *
1547  * PARAMS
1548  *  FileHandle         [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1549  *  IoStatusBlock      [O] Receives information about the operation on return
1550  *
1551  * RETURNS
1552  *  Success: 0. IoStatusBlock is updated.
1553  *  Failure: An NTSTATUS error code describing the error.
1554  */
1555 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
1556 {
1557     NTSTATUS ret;
1558     HANDLE hEvent = NULL;
1559
1560     SERVER_START_REQ( flush_file )
1561     {
1562         req->handle = hFile;
1563         ret = wine_server_call( req );
1564         hEvent = reply->event;
1565     }
1566     SERVER_END_REQ;
1567     if (!ret && hEvent)
1568     {
1569         ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
1570         NtClose( hEvent );
1571     }
1572     return ret;
1573 }
1574
1575 /******************************************************************
1576  *              NtLockFile       (NTDLL.@)
1577  *
1578  *
1579  */
1580 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
1581                             PIO_APC_ROUTINE apc, void* apc_user,
1582                             PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
1583                             PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
1584                             BOOLEAN exclusive )
1585 {
1586     NTSTATUS    ret;
1587     HANDLE      handle;
1588     BOOLEAN     async;
1589
1590     if (apc || io_status || key)
1591     {
1592         FIXME("Unimplemented yet parameter\n");
1593         return STATUS_NOT_IMPLEMENTED;
1594     }
1595
1596     for (;;)
1597     {
1598         SERVER_START_REQ( lock_file )
1599         {
1600             req->handle      = hFile;
1601             req->offset_low  = offset->u.LowPart;
1602             req->offset_high = offset->u.HighPart;
1603             req->count_low   = count->u.LowPart;
1604             req->count_high  = count->u.HighPart;
1605             req->shared      = !exclusive;
1606             req->wait        = !dont_wait;
1607             ret = wine_server_call( req );
1608             handle = reply->handle;
1609             async  = reply->overlapped;
1610         }
1611         SERVER_END_REQ;
1612         if (ret != STATUS_PENDING)
1613         {
1614             if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
1615             return ret;
1616         }
1617
1618         if (async)
1619         {
1620             FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
1621             if (handle) NtClose( handle );
1622             return STATUS_PENDING;
1623         }
1624         if (handle)
1625         {
1626             NtWaitForSingleObject( handle, FALSE, NULL );
1627             NtClose( handle );
1628         }
1629         else
1630         {
1631             LARGE_INTEGER time;
1632     
1633             /* Unix lock conflict, sleep a bit and retry */
1634             time.QuadPart = 100 * (ULONGLONG)10000;
1635             time.QuadPart = -time.QuadPart;
1636             NtDelayExecution( FALSE, &time );
1637         }
1638     }
1639 }
1640
1641
1642 /******************************************************************
1643  *              NtUnlockFile    (NTDLL.@)
1644  *
1645  *
1646  */
1647 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
1648                               PLARGE_INTEGER offset, PLARGE_INTEGER count,
1649                               PULONG key )
1650 {
1651     NTSTATUS status;
1652
1653     TRACE( "%p %lx%08lx %lx%08lx\n",
1654            hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
1655
1656     if (io_status || key)
1657     {
1658         FIXME("Unimplemented yet parameter\n");
1659         return STATUS_NOT_IMPLEMENTED;
1660     }
1661
1662     SERVER_START_REQ( unlock_file )
1663     {
1664         req->handle      = hFile;
1665         req->offset_low  = offset->u.LowPart;
1666         req->offset_high = offset->u.HighPart;
1667         req->count_low   = count->u.LowPart;
1668         req->count_high  = count->u.HighPart;
1669         status = wine_server_call( req );
1670     }
1671     SERVER_END_REQ;
1672     return status;
1673 }
1674
1675 /******************************************************************
1676  *              NtCreateNamedPipeFile    (NTDLL.@)
1677  *
1678  *
1679  */
1680 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE FileHandle, ULONG DesiredAccess,
1681      POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock,
1682      ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions,
1683      ULONG NamedPipeType, ULONG ReadMode, ULONG CompletionMode,
1684      ULONG MaximumInstances, ULONG InboundQuota, ULONG OutboundQuota,
1685      PLARGE_INTEGER DefaultTimeout)
1686 {
1687     FIXME("(%p %lx %p %p %lx %ld %lx %ld %ld %ld %ld %ld %ld %p): stub\n",
1688           FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock,
1689           ShareAccess, CreateDisposition, CreateOptions, NamedPipeType,
1690           ReadMode, CompletionMode, MaximumInstances, InboundQuota,
1691           OutboundQuota, DefaultTimeout);
1692     return STATUS_NOT_IMPLEMENTED;
1693 }
1694
1695 /******************************************************************
1696  *              NtDeleteFile    (NTDLL.@)
1697  *
1698  *
1699  */
1700 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
1701 {
1702     NTSTATUS status;
1703     HANDLE hFile;
1704     IO_STATUS_BLOCK io;
1705
1706     TRACE("%p\n", ObjectAttributes);
1707     status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE, ObjectAttributes, 
1708                            &io, NULL, 0,
1709                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
1710                            FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
1711     if (status == STATUS_SUCCESS) status = NtClose(hFile);
1712     return status;
1713 }
1714
1715 /******************************************************************
1716  *              NtCancelIoFile    (NTDLL.@)
1717  *
1718  *
1719  */
1720 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
1721 {
1722     LARGE_INTEGER timeout;
1723
1724     TRACE("%p %p\n", hFile, io_status );
1725
1726     SERVER_START_REQ( cancel_async )
1727     {
1728         req->handle = hFile;
1729         wine_server_call( req );
1730     }
1731     SERVER_END_REQ;
1732     /* Let some APC be run, so that we can run the remaining APCs on hFile
1733      * either the cancelation of the pending one, but also the execution
1734      * of the queued APC, but not yet run. This is needed to ensure proper
1735      * clean-up of allocated data.
1736      */
1737     timeout.u.LowPart = timeout.u.HighPart = 0;
1738     return io_status->u.Status = NtDelayExecution( TRUE, &timeout );
1739 }