Better support for device handles in NtQueryVolumeInformationFile.
[wine/multimedia.git] / dlls / ntdll / file.c
blob7d1e633607f9a01399c576992a6667225cd8885e
1 /*
2 * Copyright 1999, 2000 Juergen Schmied
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.
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.
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
19 #include "config.h"
20 #include "wine/port.h"
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 STATFS_DEFINED_BY_SYS_VFS
43 # include <sys/vfs.h>
44 #else
45 # ifdef STATFS_DEFINED_BY_SYS_MOUNT
46 # include <sys/mount.h>
47 # else
48 # ifdef STATFS_DEFINED_BY_SYS_STATFS
49 # include <sys/statfs.h>
50 # endif
51 # endif
52 #endif
54 #define NONAMELESSUNION
55 #define NONAMELESSSTRUCT
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
58 #include "wine/server.h"
59 #include "async.h"
60 #include "ntdll_misc.h"
62 #include "winternl.h"
63 #include "winioctl.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
67 /**************************************************************************
68 * NtOpenFile [NTDLL.@]
69 * ZwOpenFile [NTDLL.@]
71 * Open a file.
73 * PARAMS
74 * FileHandle [O] Variable that receives the file handle on return
75 * DesiredAccess [I] Access desired by the caller to the file
76 * ObjectAttributes [I] Structue describing the file to be opened
77 * IoStatusBlock [O] Receives details about the result of the operation
78 * ShareAccess [I] Type of shared access the caller requires
79 * OpenOptions [I] Options for the file open
81 * RETURNS
82 * Success: 0. FileHandle and IoStatusBlock are updated.
83 * Failure: An NTSTATUS error code describing the error.
85 NTSTATUS WINAPI NtOpenFile(
86 OUT PHANDLE FileHandle,
87 ACCESS_MASK DesiredAccess,
88 POBJECT_ATTRIBUTES ObjectAttributes,
89 OUT PIO_STATUS_BLOCK IoStatusBlock,
90 ULONG ShareAccess,
91 ULONG OpenOptions)
93 LPWSTR filename;
94 static const WCHAR szDosDevices[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0};
96 FIXME("(%p,0x%08lx,%p,%p,0x%08lx,0x%08lx) partial stub\n",
97 FileHandle, DesiredAccess, ObjectAttributes,
98 IoStatusBlock, ShareAccess, OpenOptions);
100 dump_ObjectAttributes (ObjectAttributes);
102 if(ObjectAttributes->RootDirectory)
104 FIXME("Object root directory unknown %p\n",
105 ObjectAttributes->RootDirectory);
106 return STATUS_OBJECT_NAME_NOT_FOUND;
109 filename = ObjectAttributes->ObjectName->Buffer;
111 /* FIXME: DOSFS stuff should call here, not vice-versa */
112 if(strncmpW(filename, szDosDevices, strlenW(szDosDevices)))
113 return STATUS_OBJECT_NAME_NOT_FOUND;
115 /* FIXME: this calls SetLastError() -> bad */
116 *FileHandle = pCreateFileW( &filename[strlenW(szDosDevices)], DesiredAccess, ShareAccess,
117 NULL, OPEN_EXISTING, 0, 0 );
118 if (*FileHandle == INVALID_HANDLE_VALUE) return STATUS_OBJECT_NAME_NOT_FOUND;
119 return STATUS_SUCCESS;
122 /**************************************************************************
123 * NtCreateFile [NTDLL.@]
124 * ZwCreateFile [NTDLL.@]
126 * Either create a new file or directory, or open an existing file, device,
127 * directory or volume.
129 * PARAMS
130 * FileHandle [O] Points to a variable which receives the file handle on return
131 * DesiredAccess [I] Desired access to the file
132 * ObjectAttributes [I] Structure describing the file
133 * IoStatusBlock [O] Receives information about the operation on return
134 * AllocationSize [I] Initial size of the file in bytes
135 * FileAttributes [I] Attributes to create the file with
136 * ShareAccess [I] Type of shared access the caller would like to the file
137 * CreateDisposition [I] Specifies what to do, depending on whether the file already exists
138 * CreateOptions [I] Options for creating a new file
139 * EaBuffer [I] Undocumented
140 * EaLength [I] Undocumented
142 * RETURNS
143 * Success: 0. FileHandle and IoStatusBlock are updated.
144 * Failure: An NTSTATUS error code describing the error.
146 NTSTATUS WINAPI NtCreateFile(
147 OUT PHANDLE FileHandle,
148 ACCESS_MASK DesiredAccess,
149 POBJECT_ATTRIBUTES ObjectAttributes,
150 OUT PIO_STATUS_BLOCK IoStatusBlock,
151 PLARGE_INTEGER AllocateSize,
152 ULONG FileAttributes,
153 ULONG ShareAccess,
154 ULONG CreateDisposition,
155 ULONG CreateOptions,
156 PVOID EaBuffer,
157 ULONG EaLength)
159 FIXME("(%p,0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx) stub\n",
160 FileHandle,DesiredAccess,ObjectAttributes,
161 IoStatusBlock,AllocateSize,FileAttributes,
162 ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
163 dump_ObjectAttributes (ObjectAttributes);
164 return 0;
167 /***********************************************************************
168 * Asynchronous file I/O *
170 static DWORD fileio_get_async_count(const async_private *ovp);
171 static void CALLBACK fileio_call_completion_func(ULONG_PTR data);
172 static void fileio_async_cleanup(async_private *ovp);
174 static async_ops fileio_async_ops =
176 fileio_get_async_count, /* get_count */
177 fileio_call_completion_func, /* call_completion */
178 fileio_async_cleanup /* cleanup */
181 static async_ops fileio_nocomp_async_ops =
183 fileio_get_async_count, /* get_count */
184 NULL, /* call_completion */
185 fileio_async_cleanup /* cleanup */
188 typedef struct async_fileio
190 struct async_private async;
191 PIO_APC_ROUTINE apc;
192 void* apc_user;
193 char *buffer;
194 unsigned int count;
195 unsigned long offset;
196 enum fd_type fd_type;
197 } async_fileio;
199 static DWORD fileio_get_async_count(const struct async_private *ovp)
201 async_fileio *fileio = (async_fileio*) ovp;
203 if (fileio->count < fileio->async.iosb->Information)
204 return 0;
205 return fileio->count - fileio->async.iosb->Information;
208 static void CALLBACK fileio_call_completion_func(ULONG_PTR data)
210 async_fileio *ovp = (async_fileio*) data;
211 TRACE("data: %p\n", ovp);
213 ovp->apc( ovp->apc_user, ovp->async.iosb, ovp->async.iosb->Information );
215 fileio_async_cleanup( &ovp->async );
218 static void fileio_async_cleanup( struct async_private *ovp )
220 RtlFreeHeap( GetProcessHeap(), 0, ovp );
223 /***********************************************************************
224 * FILE_GetNtStatus(void)
226 * Retrieve the Nt Status code from errno.
227 * Try to be consistent with FILE_SetDosError().
229 NTSTATUS FILE_GetNtStatus(void)
231 int err = errno;
232 DWORD nt;
234 TRACE( "errno = %d\n", errno );
235 switch (err)
237 case EAGAIN: nt = STATUS_SHARING_VIOLATION; break;
238 case EBADF: nt = STATUS_INVALID_HANDLE; break;
239 case ENOSPC: nt = STATUS_DISK_FULL; break;
240 case EPERM:
241 case EROFS:
242 case EACCES: nt = STATUS_ACCESS_DENIED; break;
243 case ENOENT: nt = STATUS_SHARING_VIOLATION; break;
244 case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break;
245 case EMFILE:
246 case ENFILE: nt = STATUS_NO_MORE_FILES; break;
247 case EINVAL:
248 case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
249 case EPIPE: nt = STATUS_PIPE_BROKEN; break;
250 case EIO: nt = STATUS_DEVICE_NOT_READY; break;
251 case ENOEXEC: /* ?? */
252 case ESPIPE: /* ?? */
253 case EEXIST: /* ?? */
254 default:
255 FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
256 nt = STATUS_UNSUCCESSFUL;
258 return nt;
261 /***********************************************************************
262 * FILE_AsyncReadService (INTERNAL)
264 * This function is called while the client is waiting on the
265 * server, so we can't make any server calls here.
267 static void FILE_AsyncReadService(async_private *ovp)
269 async_fileio *fileio = (async_fileio*) ovp;
270 IO_STATUS_BLOCK* io_status = fileio->async.iosb;
271 int result;
272 int already = io_status->Information;
274 TRACE("%p %p\n", io_status, fileio->buffer );
276 /* check to see if the data is ready (non-blocking) */
278 if ( fileio->fd_type == FD_TYPE_SOCKET )
279 result = read(ovp->fd, &fileio->buffer[already], fileio->count - already);
280 else
282 result = pread(ovp->fd, &fileio->buffer[already], fileio->count - already,
283 fileio->offset + already);
284 if ((result < 0) && (errno == ESPIPE))
285 result = read(ovp->fd, &fileio->buffer[already], fileio->count - already);
288 if ((result < 0) && ((errno == EAGAIN) || (errno == EINTR)))
290 TRACE("Deferred read %d\n",errno);
291 io_status->u.Status = STATUS_PENDING;
292 return;
295 /* check to see if the transfer is complete */
296 if (result < 0)
298 io_status->u.Status = FILE_GetNtStatus();
299 return;
301 else if (result == 0)
303 io_status->u.Status = io_status->Information ? STATUS_SUCCESS : STATUS_END_OF_FILE;
304 return;
307 io_status->Information += result;
308 if (io_status->Information >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
309 io_status->u.Status = STATUS_SUCCESS;
310 else
311 io_status->u.Status = STATUS_PENDING;
313 TRACE("read %d more bytes %ld/%d so far\n",
314 result, io_status->Information, fileio->count);
318 /******************************************************************************
319 * NtReadFile [NTDLL.@]
320 * ZwReadFile [NTDLL.@]
322 * Read from an open file handle.
324 * PARAMS
325 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
326 * Event [I] Event to signal upon completion (or NULL)
327 * ApcRoutine [I] Callback to call upon completion (or NULL)
328 * ApcContext [I] Context for ApcRoutine (or NULL)
329 * IoStatusBlock [O] Receives information about the operation on return
330 * Buffer [O] Destination for the data read
331 * Length [I] Size of Buffer
332 * ByteOffset [O] Destination for the new file pointer position (or NULL)
333 * Key [O] Function unknown (may be NULL)
335 * RETURNS
336 * Success: 0. IoStatusBlock is updated, and the Information member contains
337 * The number of bytes read.
338 * Failure: An NTSTATUS error code describing the error.
340 NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
341 PIO_APC_ROUTINE apc, void* apc_user,
342 PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
343 PLARGE_INTEGER offset, PULONG key)
345 int unix_handle, flags;
346 enum fd_type type;
348 TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n",
349 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
351 io_status->Information = 0;
352 io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_READ, &unix_handle, &type, &flags );
353 if (io_status->u.Status) return io_status->u.Status;
355 if (flags & FD_FLAG_RECV_SHUTDOWN)
357 wine_server_release_fd( hFile, unix_handle );
358 return STATUS_PIPE_DISCONNECTED;
361 if (flags & FD_FLAG_TIMEOUT)
363 if (hEvent)
365 /* this shouldn't happen, but check it */
366 FIXME("NIY-hEvent\n");
367 wine_server_release_fd( hFile, unix_handle );
368 return STATUS_NOT_IMPLEMENTED;
370 io_status->u.Status = NtCreateEvent(&hEvent, SYNCHRONIZE, NULL, 0, 0);
371 if (io_status->u.Status)
373 wine_server_release_fd( hFile, unix_handle );
374 return io_status->u.Status;
378 if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
380 async_fileio* ovp;
381 NTSTATUS ret;
383 if (!(ovp = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
385 wine_server_release_fd( hFile, unix_handle );
386 return STATUS_NO_MEMORY;
388 ovp->async.ops = (apc ? &fileio_async_ops : &fileio_nocomp_async_ops );
389 ovp->async.handle = hFile;
390 ovp->async.fd = unix_handle; /* FIXME */
391 ovp->async.type = ASYNC_TYPE_READ;
392 ovp->async.func = FILE_AsyncReadService;
393 ovp->async.event = hEvent;
394 ovp->async.iosb = io_status;
395 ovp->count = length;
396 if ( offset == NULL )
397 ovp->offset = 0;
398 else
400 ovp->offset = offset->u.LowPart;
401 if (offset->u.HighPart) FIXME("NIY-high part\n");
403 ovp->apc = apc;
404 ovp->apc_user = apc_user;
405 ovp->buffer = buffer;
406 ovp->fd_type = type;
408 io_status->Information = 0;
409 ret = register_new_async(&ovp->async);
410 if (ret != STATUS_SUCCESS)
411 return ret;
412 if (flags & FD_FLAG_TIMEOUT)
414 NtWaitForSingleObject(hEvent, TRUE, NULL);
415 NtClose(hEvent);
417 else
419 LARGE_INTEGER timeout;
421 /* let some APC be run, this will read some already pending data */
422 timeout.u.LowPart = timeout.u.HighPart = 0;
423 NtDelayExecution( TRUE, &timeout );
425 return io_status->u.Status;
427 switch (type)
429 case FD_TYPE_SMB:
430 FIXME("NIY-SMB\n");
431 /* FIXME */
432 /* return SMB_ReadFile(hFile, unix_handle, buffer, length, io_status); */
433 wine_server_release_fd( hFile, unix_handle );
434 return STATUS_INVALID_HANDLE;
436 case FD_TYPE_DEFAULT:
437 /* normal unix file */
438 break;
440 default:
441 FIXME("Unsupported type of fd %d\n", type);
442 wine_server_release_fd( hFile, unix_handle );
443 return STATUS_INVALID_HANDLE;
446 if (offset)
448 FILE_POSITION_INFORMATION fpi;
450 fpi.CurrentByteOffset = *offset;
451 io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi),
452 FilePositionInformation);
453 if (io_status->u.Status)
455 wine_server_release_fd( hFile, unix_handle );
456 return io_status->u.Status;
459 /* code for synchronous reads */
460 while ((io_status->Information = read( unix_handle, buffer, length )) == -1)
462 if ((errno == EAGAIN) || (errno == EINTR)) continue;
463 if (errno == EFAULT) FIXME( "EFAULT handling broken for now\n" );
464 io_status->u.Status = FILE_GetNtStatus();
465 break;
467 wine_server_release_fd( hFile, unix_handle );
468 return io_status->u.Status;
471 /***********************************************************************
472 * FILE_AsyncWriteService (INTERNAL)
474 * This function is called while the client is waiting on the
475 * server, so we can't make any server calls here.
477 static void FILE_AsyncWriteService(struct async_private *ovp)
479 async_fileio *fileio = (async_fileio *) ovp;
480 PIO_STATUS_BLOCK io_status = fileio->async.iosb;
481 int result;
482 int already = io_status->Information;
484 TRACE("(%p %p)\n",io_status,fileio->buffer);
486 /* write some data (non-blocking) */
488 if ( fileio->fd_type == FD_TYPE_SOCKET )
489 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
490 else
492 result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
493 fileio->offset + already);
494 if ((result < 0) && (errno == ESPIPE))
495 result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
498 if ((result < 0) && ((errno == EAGAIN) || (errno == EINTR)))
500 io_status->u.Status = STATUS_PENDING;
501 return;
504 /* check to see if the transfer is complete */
505 if (result < 0)
507 io_status->u.Status = FILE_GetNtStatus();
508 return;
511 io_status->Information += result;
512 io_status->u.Status = (io_status->Information < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
513 TRACE("wrote %d more bytes %ld/%d so far\n",result,io_status->Information,fileio->count);
516 /******************************************************************************
517 * NtWriteFile [NTDLL.@]
518 * ZwWriteFile [NTDLL.@]
520 * Write to an open file handle.
522 * PARAMS
523 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
524 * Event [I] Event to signal upon completion (or NULL)
525 * ApcRoutine [I] Callback to call upon completion (or NULL)
526 * ApcContext [I] Context for ApcRoutine (or NULL)
527 * IoStatusBlock [O] Receives information about the operation on return
528 * Buffer [I] Source for the data to write
529 * Length [I] Size of Buffer
530 * ByteOffset [O] Destination for the new file pointer position (or NULL)
531 * Key [O] Function unknown (may be NULL)
533 * RETURNS
534 * Success: 0. IoStatusBlock is updated, and the Information member contains
535 * The number of bytes written.
536 * Failure: An NTSTATUS error code describing the error.
538 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
539 PIO_APC_ROUTINE apc, void* apc_user,
540 PIO_STATUS_BLOCK io_status,
541 const void* buffer, ULONG length,
542 PLARGE_INTEGER offset, PULONG key)
544 int unix_handle, flags;
545 enum fd_type type;
547 TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p)!\n",
548 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
550 TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n",
551 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
553 io_status->Information = 0;
554 io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_WRITE, &unix_handle, &type, &flags );
555 if (io_status->u.Status) return io_status->u.Status;
557 if (flags & FD_FLAG_SEND_SHUTDOWN)
559 wine_server_release_fd( hFile, unix_handle );
560 return STATUS_PIPE_DISCONNECTED;
563 if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
565 async_fileio* ovp;
566 NTSTATUS ret;
568 if (!(ovp = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
570 wine_server_release_fd( hFile, unix_handle );
571 return STATUS_NO_MEMORY;
573 ovp->async.ops = (apc ? &fileio_async_ops : &fileio_nocomp_async_ops );
574 ovp->async.handle = hFile;
575 ovp->async.fd = unix_handle; /* FIXME */
576 ovp->async.type = ASYNC_TYPE_WRITE;
577 ovp->async.func = FILE_AsyncWriteService;
578 ovp->async.event = hEvent;
579 ovp->async.iosb = io_status;
580 ovp->count = length;
581 if (offset) {
582 ovp->offset = offset->u.LowPart;
583 if (offset->u.HighPart) FIXME("NIY-high part\n");
584 } else {
585 ovp->offset = 0;
587 ovp->apc = apc;
588 ovp->apc_user = apc_user;
589 ovp->buffer = (void*)buffer;
590 ovp->fd_type = type;
592 io_status->Information = 0;
593 ret = register_new_async(&ovp->async);
594 if (ret != STATUS_SUCCESS)
595 return ret;
596 if (flags & FD_FLAG_TIMEOUT)
598 NtWaitForSingleObject(hEvent, TRUE, NULL);
599 NtClose(hEvent);
601 else
603 LARGE_INTEGER timeout;
605 /* let some APC be run, this will write as much data as possible */
606 timeout.u.LowPart = timeout.u.HighPart = 0;
607 NtDelayExecution( TRUE, &timeout );
609 return io_status->u.Status;
611 switch (type)
613 case FD_TYPE_SMB:
614 FIXME("NIY-SMB\n");
615 wine_server_release_fd( hFile, unix_handle );
616 return STATUS_NOT_IMPLEMENTED;
618 case FD_TYPE_DEFAULT:
619 /* normal unix files */
620 if (unix_handle == -1) return STATUS_INVALID_HANDLE;
621 break;
623 default:
624 FIXME("Unsupported type of fd %d\n", type);
625 wine_server_release_fd( hFile, unix_handle );
626 return STATUS_INVALID_HANDLE;
629 if (offset)
631 FILE_POSITION_INFORMATION fpi;
633 fpi.CurrentByteOffset = *offset;
634 io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi),
635 FilePositionInformation);
636 if (io_status->u.Status)
638 wine_server_release_fd( hFile, unix_handle );
639 return io_status->u.Status;
643 /* synchronous file write */
644 while ((io_status->Information = write( unix_handle, buffer, length )) == -1)
646 if ((errno == EAGAIN) || (errno == EINTR)) continue;
647 if (errno == EFAULT) FIXME( "EFAULT handling broken for now\n" );
648 if (errno == ENOSPC) io_status->u.Status = STATUS_DISK_FULL;
649 else io_status->u.Status = FILE_GetNtStatus();
650 break;
652 wine_server_release_fd( hFile, unix_handle );
653 return io_status->u.Status;
656 /**************************************************************************
657 * NtDeviceIoControlFile [NTDLL.@]
658 * ZwDeviceIoControlFile [NTDLL.@]
660 * Perform an I/O control operation on an open file handle.
662 * PARAMS
663 * DeviceHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
664 * Event [I] Event to signal upon completion (or NULL)
665 * ApcRoutine [I] Callback to call upon completion (or NULL)
666 * ApcContext [I] Context for ApcRoutine (or NULL)
667 * IoStatusBlock [O] Receives information about the operation on return
668 * IoControlCode [I] Control code for the operation to perform
669 * InputBuffer [I] Source for any input data required (or NULL)
670 * InputBufferSize [I] Size of InputBuffer
671 * OutputBuffer [O] Source for any output data returned (or NULL)
672 * OutputBufferSize [I] Size of OutputBuffer
674 * RETURNS
675 * Success: 0. IoStatusBlock is updated.
676 * Failure: An NTSTATUS error code describing the error.
678 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE DeviceHandle, HANDLE hEvent,
679 PIO_APC_ROUTINE UserApcRoutine,
680 PVOID UserApcContext,
681 PIO_STATUS_BLOCK IoStatusBlock,
682 ULONG IoControlCode,
683 PVOID InputBuffer,
684 ULONG InputBufferSize,
685 PVOID OutputBuffer,
686 ULONG OutputBufferSize)
688 TRACE("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx)\n",
689 DeviceHandle, hEvent, UserApcRoutine, UserApcContext,
690 IoStatusBlock, IoControlCode,
691 InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize);
693 if (CDROM_DeviceIoControl(DeviceHandle, hEvent,
694 UserApcRoutine, UserApcContext,
695 IoStatusBlock, IoControlCode,
696 InputBuffer, InputBufferSize,
697 OutputBuffer, OutputBufferSize) == STATUS_NO_SUCH_DEVICE)
699 /* it wasn't a CDROM */
700 FIXME("Unimplemented dwIoControlCode=%08lx\n", IoControlCode);
701 IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
702 IoStatusBlock->Information = 0;
703 if (hEvent) NtSetEvent(hEvent, NULL);
705 return IoStatusBlock->u.Status;
708 /******************************************************************************
709 * NtFsControlFile [NTDLL.@]
710 * ZwFsControlFile [NTDLL.@]
712 NTSTATUS WINAPI NtFsControlFile(
713 IN HANDLE DeviceHandle,
714 IN HANDLE Event OPTIONAL,
715 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
716 IN PVOID ApcContext OPTIONAL,
717 OUT PIO_STATUS_BLOCK IoStatusBlock,
718 IN ULONG IoControlCode,
719 IN PVOID InputBuffer,
720 IN ULONG InputBufferSize,
721 OUT PVOID OutputBuffer,
722 IN ULONG OutputBufferSize)
724 FIXME("(%p,%p,%p,%p,%p,0x%08lx,%p,0x%08lx,%p,0x%08lx): stub\n",
725 DeviceHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,IoControlCode,
726 InputBuffer,InputBufferSize,OutputBuffer,OutputBufferSize);
727 return 0;
730 /******************************************************************************
731 * NtSetVolumeInformationFile [NTDLL.@]
732 * ZwSetVolumeInformationFile [NTDLL.@]
734 * Set volume information for an open file handle.
736 * PARAMS
737 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
738 * IoStatusBlock [O] Receives information about the operation on return
739 * FsInformation [I] Source for volume information
740 * Length [I] Size of FsInformation
741 * FsInformationClass [I] Type of volume information to set
743 * RETURNS
744 * Success: 0. IoStatusBlock is updated.
745 * Failure: An NTSTATUS error code describing the error.
747 NTSTATUS WINAPI NtSetVolumeInformationFile(
748 IN HANDLE FileHandle,
749 PIO_STATUS_BLOCK IoStatusBlock,
750 PVOID FsInformation,
751 ULONG Length,
752 FS_INFORMATION_CLASS FsInformationClass)
754 FIXME("(%p,%p,%p,0x%08lx,0x%08x) stub\n",
755 FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
756 return 0;
759 /******************************************************************************
760 * NtQueryInformationFile [NTDLL.@]
761 * ZwQueryInformationFile [NTDLL.@]
763 * Get information about an open file handle.
765 * PARAMS
766 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
767 * IoStatusBlock [O] Receives information about the operation on return
768 * FileInformation [O] Destination for file information
769 * Length [I] Size of FileInformation
770 * FileInformationClass [I] Type of file information to get
772 * RETURNS
773 * Success: 0. IoStatusBlock and FileInformation are updated.
774 * Failure: An NTSTATUS error code describing the error.
776 NTSTATUS WINAPI NtQueryInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io_status,
777 PVOID ptr, LONG len,
778 FILE_INFORMATION_CLASS class)
780 NTSTATUS status;
781 LONG used = 0;
782 BYTE answer[256];
783 time_t ct = 0, wt = 0, at = 0;
785 TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", hFile, io_status, ptr, len, class);
787 switch (class)
789 case FileBasicInformation:
791 FILE_BASIC_INFORMATION* fbi = (FILE_BASIC_INFORMATION*)answer;
792 if (sizeof(answer) < sizeof(*fbi)) goto too_small;
794 SERVER_START_REQ( get_file_info )
796 req->handle = hFile;
797 if (!(status = wine_server_call( req )))
799 /* FIXME: which file types are supported ?
800 * Serial ports (FILE_TYPE_CHAR) are not,
801 * and MSDN also says that pipes are not supported.
802 * FILE_TYPE_REMOTE seems to be supported according to
803 * MSDN q234741.txt */
804 if ((reply->type == FILE_TYPE_DISK) ||
805 (reply->type == FILE_TYPE_REMOTE))
807 at = reply->access_time;
808 wt = reply->write_time;
809 ct = reply->change_time;
810 fbi->FileAttributes = reply->attr;
811 used = sizeof(*fbi);
813 else status = STATUS_INVALID_HANDLE; /* FIXME ??? */
816 SERVER_END_REQ;
817 if (used)
819 RtlSecondsSince1970ToTime(wt, &fbi->CreationTime);
820 RtlSecondsSince1970ToTime(wt, &fbi->LastWriteTime);
821 RtlSecondsSince1970ToTime(ct, &fbi->ChangeTime);
822 RtlSecondsSince1970ToTime(at, &fbi->LastAccessTime);
825 break;
826 case FileStandardInformation:
828 FILE_STANDARD_INFORMATION* fsi = (FILE_STANDARD_INFORMATION*)answer;
829 if (sizeof(answer) < sizeof(*fsi)) goto too_small;
831 SERVER_START_REQ( get_file_info )
833 req->handle = hFile;
834 if (!(status = wine_server_call( req )))
836 /* FIXME: which file types are supported ?
837 * Serial ports (FILE_TYPE_CHAR) are not,
838 * and MSDN also says that pipes are not supported.
839 * FILE_TYPE_REMOTE seems to be supported according to
840 * MSDN q234741.txt */
841 if ((reply->type == FILE_TYPE_DISK) ||
842 (reply->type == FILE_TYPE_REMOTE))
844 fsi->AllocationSize.u.HighPart = reply->alloc_high;
845 fsi->AllocationSize.u.LowPart = reply->alloc_low;
846 fsi->EndOfFile.u.HighPart = reply->size_high;
847 fsi->EndOfFile.u.LowPart = reply->size_low;
848 fsi->NumberOfLinks = reply->links;
849 fsi->DeletePending = FALSE; /* FIXME */
850 fsi->Directory = (reply->attr & FILE_ATTRIBUTE_DIRECTORY);
851 used = sizeof(*fsi);
853 else status = STATUS_INVALID_HANDLE; /* FIXME ??? */
856 SERVER_END_REQ;
858 break;
859 case FilePositionInformation:
861 FILE_POSITION_INFORMATION* fpi = (FILE_POSITION_INFORMATION*)answer;
862 if (sizeof(answer) < sizeof(*fpi)) goto too_small;
864 SERVER_START_REQ( set_file_pointer )
866 req->handle = hFile;
867 req->low = 0;
868 req->high = 0;
869 req->whence = SEEK_CUR;
870 if (!(status = wine_server_call( req )))
872 fpi->CurrentByteOffset.u.HighPart = reply->new_high;
873 fpi->CurrentByteOffset.u.LowPart = reply->new_low;
874 used = sizeof(*fpi);
877 SERVER_END_REQ;
879 break;
880 default:
881 FIXME("Unsupported class (%d)\n", class);
882 return io_status->u.Status = STATUS_NOT_IMPLEMENTED;
884 if (used) memcpy(ptr, answer, min(used, len));
885 io_status->u.Status = status;
886 io_status->Information = len;
887 return status;
888 too_small:
889 io_status->Information = 0;
890 return io_status->u.Status = STATUS_BUFFER_TOO_SMALL;
893 /******************************************************************************
894 * NtSetInformationFile [NTDLL.@]
895 * ZwSetInformationFile [NTDLL.@]
897 * Set information about an open file handle.
899 * PARAMS
900 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
901 * IoStatusBlock [O] Receives information about the operation on return
902 * FileInformation [I] Source for file information
903 * Length [I] Size of FileInformation
904 * FileInformationClass [I] Type of file information to set
906 * RETURNS
907 * Success: 0. IoStatusBlock is updated.
908 * Failure: An NTSTATUS error code describing the error.
910 NTSTATUS WINAPI NtSetInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io_status,
911 PVOID ptr, ULONG len,
912 FILE_INFORMATION_CLASS class)
914 NTSTATUS status = STATUS_INVALID_PARAMETER_3;
916 TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", hFile, io_status, ptr, len, class);
918 switch (class)
920 case FilePositionInformation:
921 if (len >= sizeof(FILE_POSITION_INFORMATION))
923 FILE_POSITION_INFORMATION* fpi = (FILE_POSITION_INFORMATION*)ptr;
925 SERVER_START_REQ( set_file_pointer )
927 req->handle = hFile;
928 req->low = fpi->CurrentByteOffset.u.LowPart;
929 req->high = fpi->CurrentByteOffset.u.HighPart;
930 req->whence = SEEK_SET;
931 status = wine_server_call( req );
933 SERVER_END_REQ;
934 status = STATUS_SUCCESS;
936 break;
937 default:
938 FIXME("Unsupported class (%d)\n", class);
939 return STATUS_NOT_IMPLEMENTED;
941 io_status->u.Status = status;
942 io_status->Information = 0;
943 return status;
947 /******************************************************************************
948 * NtQueryVolumeInformationFile [NTDLL.@]
949 * ZwQueryVolumeInformationFile [NTDLL.@]
951 * Get volume information for an open file handle.
953 * PARAMS
954 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
955 * io [O] Receives information about the operation on return
956 * buffer [O] Destination for volume information
957 * length [I] Size of FsInformation
958 * info_class [I] Type of volume information to set
960 * RETURNS
961 * Success: 0. io and buffer are updated.
962 * Failure: An NTSTATUS error code describing the error.
964 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
965 PVOID buffer, ULONG length,
966 FS_INFORMATION_CLASS info_class )
968 int fd;
969 struct stat st;
971 if ((io->u.Status = wine_server_handle_to_fd( handle, 0, &fd, NULL, NULL )) != STATUS_SUCCESS)
972 return io->u.Status;
974 io->u.Status = STATUS_NOT_IMPLEMENTED;
975 io->Information = 0;
977 switch( info_class )
979 case FileFsVolumeInformation:
980 FIXME( "%p: volume info not supported\n", handle );
981 break;
982 case FileFsLabelInformation:
983 FIXME( "%p: label info not supported\n", handle );
984 break;
985 case FileFsSizeInformation:
986 if (length < sizeof(FILE_FS_SIZE_INFORMATION))
987 io->u.Status = STATUS_BUFFER_TOO_SMALL;
988 else
990 FILE_FS_SIZE_INFORMATION *info = buffer;
991 struct statvfs stvfs;
993 if (fstat( fd, &st ) < 0)
995 io->u.Status = FILE_GetNtStatus();
996 break;
998 if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
1000 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
1001 break;
1003 if (fstatvfs( fd, &stvfs ) < 0) io->u.Status = FILE_GetNtStatus();
1004 else
1006 info->TotalAllocationUnits.QuadPart = stvfs.f_blocks;
1007 info->AvailableAllocationUnits.QuadPart = stvfs.f_bavail;
1008 info->SectorsPerAllocationUnit = 1;
1009 info->BytesPerSector = stvfs.f_frsize;
1010 io->Information = sizeof(*info);
1011 io->u.Status = STATUS_SUCCESS;
1014 break;
1015 case FileFsDeviceInformation:
1016 if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
1017 io->u.Status = STATUS_BUFFER_TOO_SMALL;
1018 else
1020 FILE_FS_DEVICE_INFORMATION *info = buffer;
1022 #if defined(linux) && defined(HAVE_FSTATFS)
1023 struct statfs stfs;
1025 info->Characteristics = 0;
1027 if (fstat( fd, &st ) < 0)
1029 io->u.Status = FILE_GetNtStatus();
1030 break;
1032 if (S_ISCHR( st.st_mode ))
1034 switch(major(st.st_rdev))
1036 case MEM_MAJOR:
1037 info->DeviceType = FILE_DEVICE_NULL;
1038 break;
1039 case TTY_MAJOR:
1040 info->DeviceType = FILE_DEVICE_SERIAL_PORT;
1041 break;
1042 case LP_MAJOR:
1043 info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
1044 break;
1045 default:
1046 info->DeviceType = FILE_DEVICE_UNKNOWN;
1047 break;
1050 else if (S_ISBLK( st.st_mode ))
1052 info->DeviceType = FILE_DEVICE_DISK;
1054 else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
1056 info->DeviceType = FILE_DEVICE_NAMED_PIPE;
1058 else /* regular file or directory */
1060 info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
1062 /* check for floppy disk */
1063 if (major(st.st_dev) == FLOPPY_MAJOR)
1064 info->Characteristics |= FILE_REMOVABLE_MEDIA;
1066 if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
1067 switch (stfs.f_type)
1069 case 0x9660: /* iso9660 */
1070 case 0x15013346: /* udf */
1071 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
1072 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
1073 break;
1074 case 0x6969: /* nfs */
1075 case 0x517B: /* smbfs */
1076 case 0x564c: /* ncpfs */
1077 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
1078 info->Characteristics |= FILE_REMOTE_DEVICE;
1079 break;
1080 case 0x01021994: /* tmpfs */
1081 case 0x28cd3d45: /* cramfs */
1082 case 0x1373: /* devfs */
1083 case 0x9fa0: /* procfs */
1084 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
1085 break;
1086 default:
1087 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1088 break;
1091 #else
1092 static int warned;
1093 if (!warned++) FIXME( "device info not supported on this platform\n" );
1094 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
1095 info->Characteristics = 0;
1096 #endif
1097 io->Information = sizeof(*info);
1098 io->u.Status = STATUS_SUCCESS;
1100 break;
1101 case FileFsAttributeInformation:
1102 FIXME( "%p: attribute info not supported\n", handle );
1103 break;
1104 case FileFsControlInformation:
1105 FIXME( "%p: control info not supported\n", handle );
1106 break;
1107 case FileFsFullSizeInformation:
1108 FIXME( "%p: full size info not supported\n", handle );
1109 break;
1110 case FileFsObjectIdInformation:
1111 FIXME( "%p: object id info not supported\n", handle );
1112 break;
1113 case FileFsMaximumInformation:
1114 FIXME( "%p: maximum info not supported\n", handle );
1115 break;
1116 default:
1117 io->u.Status = STATUS_INVALID_PARAMETER;
1118 break;
1120 wine_server_release_fd( handle, fd );
1121 return io->u.Status;
1125 /******************************************************************
1126 * NtFlushBuffersFile (NTDLL.@)
1128 * Flush any buffered data on an open file handle.
1130 * PARAMS
1131 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1132 * IoStatusBlock [O] Receives information about the operation on return
1134 * RETURNS
1135 * Success: 0. IoStatusBlock is updated.
1136 * Failure: An NTSTATUS error code describing the error.
1138 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
1140 NTSTATUS ret;
1141 HANDLE hEvent = NULL;
1143 SERVER_START_REQ( flush_file )
1145 req->handle = hFile;
1146 ret = wine_server_call( req );
1147 hEvent = reply->event;
1149 SERVER_END_REQ;
1150 if (!ret && hEvent)
1152 ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
1153 NtClose( hEvent );
1155 return ret;
1158 /******************************************************************
1159 * NtLockFile (NTDLL.@)
1163 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
1164 PIO_APC_ROUTINE apc, void* apc_user,
1165 PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
1166 PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
1167 BOOLEAN exclusive )
1169 NTSTATUS ret;
1170 HANDLE handle;
1171 BOOLEAN async;
1173 if (apc || io_status || key)
1175 FIXME("Unimplemented yet parameter\n");
1176 return STATUS_NOT_IMPLEMENTED;
1179 for (;;)
1181 SERVER_START_REQ( lock_file )
1183 req->handle = hFile;
1184 req->offset_low = offset->u.LowPart;
1185 req->offset_high = offset->u.HighPart;
1186 req->count_low = count->u.LowPart;
1187 req->count_high = count->u.HighPart;
1188 req->shared = !exclusive;
1189 req->wait = !dont_wait;
1190 ret = wine_server_call( req );
1191 handle = reply->handle;
1192 async = reply->overlapped;
1194 SERVER_END_REQ;
1195 if (ret != STATUS_PENDING)
1197 if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
1198 return ret;
1201 if (async)
1203 FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
1204 if (handle) NtClose( handle );
1205 return STATUS_PENDING;
1207 if (handle)
1209 NtWaitForSingleObject( handle, FALSE, NULL );
1210 NtClose( handle );
1212 else
1214 LARGE_INTEGER time;
1216 /* Unix lock conflict, sleep a bit and retry */
1217 time.QuadPart = 100 * (ULONGLONG)10000;
1218 time.QuadPart = -time.QuadPart;
1219 NtDelayExecution( FALSE, &time );
1225 /******************************************************************
1226 * NtUnlockFile (NTDLL.@)
1230 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
1231 PLARGE_INTEGER offset, PLARGE_INTEGER count,
1232 PULONG key )
1234 NTSTATUS status;
1236 TRACE( "%p %lx%08lx %lx%08lx\n",
1237 hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
1239 if (io_status || key)
1241 FIXME("Unimplemented yet parameter\n");
1242 return STATUS_NOT_IMPLEMENTED;
1245 SERVER_START_REQ( unlock_file )
1247 req->handle = hFile;
1248 req->offset_low = offset->u.LowPart;
1249 req->offset_high = offset->u.HighPart;
1250 req->count_low = count->u.LowPart;
1251 req->count_high = count->u.HighPart;
1252 status = wine_server_call( req );
1254 SERVER_END_REQ;
1255 return status;