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