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