ntdll: Use the fileio structure and callback also for ioctl calls.
[wine.git] / dlls / ntdll / file.c
blob6e3825fcb058216dc82980e75bfcd2eac24c617d
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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_LINUX_MAJOR_H
31 # include <linux/major.h>
32 #endif
33 #ifdef HAVE_SYS_STATVFS_H
34 # include <sys/statvfs.h>
35 #endif
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
39 #ifdef HAVE_SYS_SYSCALL_H
40 # include <sys/syscall.h>
41 #endif
42 #ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 #endif
45 #ifdef HAVE_SYS_IOCTL_H
46 #include <sys/ioctl.h>
47 #endif
48 #ifdef HAVE_SYS_FILIO_H
49 # include <sys/filio.h>
50 #endif
51 #ifdef HAVE_POLL_H
52 #include <poll.h>
53 #endif
54 #ifdef HAVE_SYS_POLL_H
55 #include <sys/poll.h>
56 #endif
57 #ifdef HAVE_SYS_SOCKET_H
58 #include <sys/socket.h>
59 #endif
60 #ifdef HAVE_UTIME_H
61 # include <utime.h>
62 #endif
63 #ifdef HAVE_SYS_VFS_H
64 # include <sys/vfs.h>
65 #endif
66 #ifdef HAVE_SYS_MOUNT_H
67 # include <sys/mount.h>
68 #endif
69 #ifdef HAVE_SYS_STATFS_H
70 # include <sys/statfs.h>
71 #endif
72 #ifdef HAVE_TERMIOS_H
73 #include <termios.h>
74 #endif
75 #ifdef HAVE_VALGRIND_MEMCHECK_H
76 # include <valgrind/memcheck.h>
77 #endif
79 #define NONAMELESSUNION
80 #define NONAMELESSSTRUCT
81 #include "ntstatus.h"
82 #define WIN32_NO_STATUS
83 #include "wine/unicode.h"
84 #include "wine/debug.h"
85 #include "wine/server.h"
86 #include "ntdll_misc.h"
88 #include "winternl.h"
89 #include "winioctl.h"
90 #include "ddk/ntddk.h"
91 #include "ddk/ntddser.h"
93 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
94 WINE_DECLARE_DEBUG_CHANNEL(winediag);
96 mode_t FILE_umask = 0;
98 #define SECSPERDAY 86400
99 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
101 #define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1)
102 #define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
104 static const WCHAR ntfsW[] = {'N','T','F','S'};
106 /* fetch the attributes of a file */
107 static inline ULONG get_file_attributes( const struct stat *st )
109 ULONG attr;
111 if (S_ISDIR(st->st_mode))
112 attr = FILE_ATTRIBUTE_DIRECTORY;
113 else
114 attr = FILE_ATTRIBUTE_ARCHIVE;
115 if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
116 attr |= FILE_ATTRIBUTE_READONLY;
117 return attr;
120 /* get the stat info and file attributes for a file (by file descriptor) */
121 int fd_get_file_info( int fd, struct stat *st, ULONG *attr )
123 int ret;
125 *attr = 0;
126 ret = fstat( fd, st );
127 if (ret == -1) return ret;
128 *attr |= get_file_attributes( st );
129 return ret;
132 /* get the stat info and file attributes for a file (by name) */
133 int get_file_info( const char *path, struct stat *st, ULONG *attr )
135 int ret;
137 *attr = 0;
138 ret = lstat( path, st );
139 if (ret == -1) return ret;
140 if (S_ISLNK( st->st_mode ))
142 ret = stat( path, st );
143 if (ret == -1) return ret;
144 /* is a symbolic link and a directory, consider these "reparse points" */
145 if (S_ISDIR( st->st_mode )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
147 *attr |= get_file_attributes( st );
148 return ret;
151 /**************************************************************************
152 * FILE_CreateFile (internal)
153 * Open a file.
155 * Parameter set fully identical with NtCreateFile
157 static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
158 PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
159 ULONG attributes, ULONG sharing, ULONG disposition,
160 ULONG options, PVOID ea_buffer, ULONG ea_length )
162 ANSI_STRING unix_name;
163 BOOL created = FALSE;
165 TRACE("handle=%p access=%08x name=%s objattr=%08x root=%p sec=%p io=%p alloc_size=%p "
166 "attr=%08x sharing=%08x disp=%d options=%08x ea=%p.0x%08x\n",
167 handle, access, debugstr_us(attr->ObjectName), attr->Attributes,
168 attr->RootDirectory, attr->SecurityDescriptor, io, alloc_size,
169 attributes, sharing, disposition, options, ea_buffer, ea_length );
171 if (!attr || !attr->ObjectName) return STATUS_INVALID_PARAMETER;
173 if (alloc_size) FIXME( "alloc_size not supported\n" );
175 if (options & FILE_OPEN_BY_FILE_ID)
176 io->u.Status = file_id_to_unix_file_name( attr, &unix_name );
177 else
178 io->u.Status = nt_to_unix_file_name_attr( attr, &unix_name, disposition );
180 if (io->u.Status == STATUS_BAD_DEVICE_TYPE)
182 SERVER_START_REQ( open_file_object )
184 req->access = access;
185 req->attributes = attr->Attributes;
186 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
187 req->sharing = sharing;
188 req->options = options;
189 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
190 io->u.Status = wine_server_call( req );
191 *handle = wine_server_ptr_handle( reply->handle );
193 SERVER_END_REQ;
194 if (io->u.Status == STATUS_SUCCESS) io->Information = FILE_OPENED;
195 return io->u.Status;
198 if (io->u.Status == STATUS_NO_SUCH_FILE &&
199 disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
201 created = TRUE;
202 io->u.Status = STATUS_SUCCESS;
205 if (io->u.Status == STATUS_SUCCESS)
207 struct security_descriptor *sd;
208 struct object_attributes objattr;
210 objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
211 objattr.name_len = 0;
212 io->u.Status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
213 if (io->u.Status != STATUS_SUCCESS)
215 RtlFreeAnsiString( &unix_name );
216 return io->u.Status;
219 SERVER_START_REQ( create_file )
221 req->access = access;
222 req->attributes = attr->Attributes;
223 req->sharing = sharing;
224 req->create = disposition;
225 req->options = options;
226 req->attrs = attributes;
227 wine_server_add_data( req, &objattr, sizeof(objattr) );
228 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
229 wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
230 io->u.Status = wine_server_call( req );
231 *handle = wine_server_ptr_handle( reply->handle );
233 SERVER_END_REQ;
234 NTDLL_free_struct_sd( sd );
235 RtlFreeAnsiString( &unix_name );
237 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
239 if (io->u.Status == STATUS_SUCCESS)
241 if (created) io->Information = FILE_CREATED;
242 else switch(disposition)
244 case FILE_SUPERSEDE:
245 io->Information = FILE_SUPERSEDED;
246 break;
247 case FILE_CREATE:
248 io->Information = FILE_CREATED;
249 break;
250 case FILE_OPEN:
251 case FILE_OPEN_IF:
252 io->Information = FILE_OPENED;
253 break;
254 case FILE_OVERWRITE:
255 case FILE_OVERWRITE_IF:
256 io->Information = FILE_OVERWRITTEN;
257 break;
260 else if (io->u.Status == STATUS_TOO_MANY_OPENED_FILES)
262 static int once;
263 if (!once++) ERR_(winediag)( "Too many open files, ulimit -n probably needs to be increased\n" );
266 return io->u.Status;
269 /**************************************************************************
270 * NtOpenFile [NTDLL.@]
271 * ZwOpenFile [NTDLL.@]
273 * Open a file.
275 * PARAMS
276 * handle [O] Variable that receives the file handle on return
277 * access [I] Access desired by the caller to the file
278 * attr [I] Structure describing the file to be opened
279 * io [O] Receives details about the result of the operation
280 * sharing [I] Type of shared access the caller requires
281 * options [I] Options for the file open
283 * RETURNS
284 * Success: 0. FileHandle and IoStatusBlock are updated.
285 * Failure: An NTSTATUS error code describing the error.
287 NTSTATUS WINAPI NtOpenFile( PHANDLE handle, ACCESS_MASK access,
288 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK io,
289 ULONG sharing, ULONG options )
291 return FILE_CreateFile( handle, access, attr, io, NULL, 0,
292 sharing, FILE_OPEN, options, NULL, 0 );
295 /**************************************************************************
296 * NtCreateFile [NTDLL.@]
297 * ZwCreateFile [NTDLL.@]
299 * Either create a new file or directory, or open an existing file, device,
300 * directory or volume.
302 * PARAMS
303 * handle [O] Points to a variable which receives the file handle on return
304 * access [I] Desired access to the file
305 * attr [I] Structure describing the file
306 * io [O] Receives information about the operation on return
307 * alloc_size [I] Initial size of the file in bytes
308 * attributes [I] Attributes to create the file with
309 * sharing [I] Type of shared access the caller would like to the file
310 * disposition [I] Specifies what to do, depending on whether the file already exists
311 * options [I] Options for creating a new file
312 * ea_buffer [I] Pointer to an extended attributes buffer
313 * ea_length [I] Length of ea_buffer
315 * RETURNS
316 * Success: 0. handle and io are updated.
317 * Failure: An NTSTATUS error code describing the error.
319 NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
320 PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
321 ULONG attributes, ULONG sharing, ULONG disposition,
322 ULONG options, PVOID ea_buffer, ULONG ea_length )
324 return FILE_CreateFile( handle, access, attr, io, alloc_size, attributes,
325 sharing, disposition, options, ea_buffer, ea_length );
328 /***********************************************************************
329 * Asynchronous file I/O *
332 struct async_fileio
334 HANDLE handle;
335 PIO_APC_ROUTINE apc;
336 void *apc_arg;
339 struct async_fileio_read
341 struct async_fileio io;
342 char* buffer;
343 unsigned int already;
344 unsigned int count;
345 BOOL avail_mode;
348 struct async_fileio_write
350 struct async_fileio io;
351 const char *buffer;
352 unsigned int already;
353 unsigned int count;
357 /* callback for file I/O user APC */
358 static void WINAPI fileio_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved )
360 struct async_fileio *async = arg;
361 if (async->apc) async->apc( async->apc_arg, io, reserved );
362 RtlFreeHeap( GetProcessHeap(), 0, async );
365 /***********************************************************************
366 * FILE_GetNtStatus(void)
368 * Retrieve the Nt Status code from errno.
369 * Try to be consistent with FILE_SetDosError().
371 NTSTATUS FILE_GetNtStatus(void)
373 int err = errno;
375 TRACE( "errno = %d\n", errno );
376 switch (err)
378 case EAGAIN: return STATUS_SHARING_VIOLATION;
379 case EBADF: return STATUS_INVALID_HANDLE;
380 case EBUSY: return STATUS_DEVICE_BUSY;
381 case ENOSPC: return STATUS_DISK_FULL;
382 case EPERM:
383 case EROFS:
384 case EACCES: return STATUS_ACCESS_DENIED;
385 case ENOTDIR: return STATUS_OBJECT_PATH_NOT_FOUND;
386 case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND;
387 case EISDIR: return STATUS_FILE_IS_A_DIRECTORY;
388 case EMFILE:
389 case ENFILE: return STATUS_TOO_MANY_OPENED_FILES;
390 case EINVAL: return STATUS_INVALID_PARAMETER;
391 case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
392 case EPIPE: return STATUS_PIPE_DISCONNECTED;
393 case EIO: return STATUS_DEVICE_NOT_READY;
394 #ifdef ENOMEDIUM
395 case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE;
396 #endif
397 case ENXIO: return STATUS_NO_SUCH_DEVICE;
398 case ENOTTY:
399 case EOPNOTSUPP:return STATUS_NOT_SUPPORTED;
400 case ECONNRESET:return STATUS_PIPE_DISCONNECTED;
401 case EFAULT: return STATUS_ACCESS_VIOLATION;
402 case ESPIPE: return STATUS_ILLEGAL_FUNCTION;
403 #ifdef ETIME /* Missing on FreeBSD */
404 case ETIME: return STATUS_IO_TIMEOUT;
405 #endif
406 case ENOEXEC: /* ?? */
407 case EEXIST: /* ?? */
408 default:
409 FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
410 return STATUS_UNSUCCESSFUL;
414 /***********************************************************************
415 * FILE_AsyncReadService (INTERNAL)
417 static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc)
419 struct async_fileio_read *fileio = user;
420 int fd, needs_close, result;
422 switch (status)
424 case STATUS_ALERTED: /* got some new data */
425 /* check to see if the data is ready (non-blocking) */
426 if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
427 &needs_close, NULL, NULL )))
428 break;
430 result = read(fd, &fileio->buffer[fileio->already], fileio->count - fileio->already);
431 if (needs_close) close( fd );
433 if (result < 0)
435 if (errno == EAGAIN || errno == EINTR)
436 status = STATUS_PENDING;
437 else /* check to see if the transfer is complete */
438 status = FILE_GetNtStatus();
440 else if (result == 0)
442 status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN;
444 else
446 fileio->already += result;
447 if (fileio->already >= fileio->count || fileio->avail_mode)
448 status = STATUS_SUCCESS;
449 else
451 /* if we only have to read the available data, and none is available,
452 * simply cancel the request. If data was available, it has been read
453 * while in by previous call (NtDelayExecution)
455 status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING;
458 break;
460 case STATUS_TIMEOUT:
461 case STATUS_IO_TIMEOUT:
462 if (fileio->already) status = STATUS_SUCCESS;
463 break;
465 if (status != STATUS_PENDING)
467 iosb->u.Status = status;
468 iosb->Information = fileio->already;
469 *apc = fileio_apc;
471 return status;
474 struct io_timeouts
476 int interval; /* max interval between two bytes */
477 int total; /* total timeout for the whole operation */
478 int end_time; /* absolute time of end of operation */
481 /* retrieve the I/O timeouts to use for a given handle */
482 static NTSTATUS get_io_timeouts( HANDLE handle, enum server_fd_type type, ULONG count, BOOL is_read,
483 struct io_timeouts *timeouts )
485 NTSTATUS status = STATUS_SUCCESS;
487 timeouts->interval = timeouts->total = -1;
489 switch(type)
491 case FD_TYPE_SERIAL:
493 /* GetCommTimeouts */
494 SERIAL_TIMEOUTS st;
495 IO_STATUS_BLOCK io;
497 status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
498 IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
499 if (status) break;
501 if (is_read)
503 if (st.ReadIntervalTimeout)
504 timeouts->interval = st.ReadIntervalTimeout;
506 if (st.ReadTotalTimeoutMultiplier || st.ReadTotalTimeoutConstant)
508 timeouts->total = st.ReadTotalTimeoutConstant;
509 if (st.ReadTotalTimeoutMultiplier != MAXDWORD)
510 timeouts->total += count * st.ReadTotalTimeoutMultiplier;
512 else if (st.ReadIntervalTimeout == MAXDWORD)
513 timeouts->interval = timeouts->total = 0;
515 else /* write */
517 if (st.WriteTotalTimeoutMultiplier || st.WriteTotalTimeoutConstant)
519 timeouts->total = st.WriteTotalTimeoutConstant;
520 if (st.WriteTotalTimeoutMultiplier != MAXDWORD)
521 timeouts->total += count * st.WriteTotalTimeoutMultiplier;
525 break;
526 case FD_TYPE_MAILSLOT:
527 if (is_read)
529 timeouts->interval = 0; /* return as soon as we got something */
530 SERVER_START_REQ( set_mailslot_info )
532 req->handle = wine_server_obj_handle( handle );
533 req->flags = 0;
534 if (!(status = wine_server_call( req )) &&
535 reply->read_timeout != TIMEOUT_INFINITE)
536 timeouts->total = reply->read_timeout / -10000;
538 SERVER_END_REQ;
540 break;
541 case FD_TYPE_SOCKET:
542 case FD_TYPE_PIPE:
543 case FD_TYPE_CHAR:
544 if (is_read) timeouts->interval = 0; /* return as soon as we got something */
545 break;
546 default:
547 break;
549 if (timeouts->total != -1) timeouts->end_time = NtGetTickCount() + timeouts->total;
550 return STATUS_SUCCESS;
554 /* retrieve the timeout for the next wait, in milliseconds */
555 static inline int get_next_io_timeout( const struct io_timeouts *timeouts, ULONG already )
557 int ret = -1;
559 if (timeouts->total != -1)
561 ret = timeouts->end_time - NtGetTickCount();
562 if (ret < 0) ret = 0;
564 if (already && timeouts->interval != -1)
566 if (ret == -1 || ret > timeouts->interval) ret = timeouts->interval;
568 return ret;
572 /* retrieve the avail_mode flag for async reads */
573 static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL *avail_mode )
575 NTSTATUS status = STATUS_SUCCESS;
577 switch(type)
579 case FD_TYPE_SERIAL:
581 /* GetCommTimeouts */
582 SERIAL_TIMEOUTS st;
583 IO_STATUS_BLOCK io;
585 status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
586 IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
587 if (status) break;
588 *avail_mode = (!st.ReadTotalTimeoutMultiplier &&
589 !st.ReadTotalTimeoutConstant &&
590 st.ReadIntervalTimeout == MAXDWORD);
592 break;
593 case FD_TYPE_MAILSLOT:
594 case FD_TYPE_SOCKET:
595 case FD_TYPE_PIPE:
596 case FD_TYPE_CHAR:
597 *avail_mode = TRUE;
598 break;
599 default:
600 *avail_mode = FALSE;
601 break;
603 return status;
607 /******************************************************************************
608 * NtReadFile [NTDLL.@]
609 * ZwReadFile [NTDLL.@]
611 * Read from an open file handle.
613 * PARAMS
614 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
615 * Event [I] Event to signal upon completion (or NULL)
616 * ApcRoutine [I] Callback to call upon completion (or NULL)
617 * ApcContext [I] Context for ApcRoutine (or NULL)
618 * IoStatusBlock [O] Receives information about the operation on return
619 * Buffer [O] Destination for the data read
620 * Length [I] Size of Buffer
621 * ByteOffset [O] Destination for the new file pointer position (or NULL)
622 * Key [O] Function unknown (may be NULL)
624 * RETURNS
625 * Success: 0. IoStatusBlock is updated, and the Information member contains
626 * The number of bytes read.
627 * Failure: An NTSTATUS error code describing the error.
629 NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
630 PIO_APC_ROUTINE apc, void* apc_user,
631 PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
632 PLARGE_INTEGER offset, PULONG key)
634 int result, unix_handle, needs_close;
635 unsigned int options;
636 struct io_timeouts timeouts;
637 NTSTATUS status;
638 ULONG total = 0;
639 enum server_fd_type type;
640 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
641 BOOL send_completion = FALSE, async_read, timeout_init_done = FALSE;
643 TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
644 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
646 if (!io_status) return STATUS_ACCESS_VIOLATION;
648 status = server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
649 &needs_close, &type, &options );
650 if (status) return status;
652 async_read = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
654 if (!virtual_check_buffer_for_write( buffer, length ))
656 status = STATUS_ACCESS_VIOLATION;
657 goto done;
660 if (type == FD_TYPE_FILE)
662 if (async_read && (!offset || offset->QuadPart < 0))
664 status = STATUS_INVALID_PARAMETER;
665 goto done;
668 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
670 /* async I/O doesn't make sense on regular files */
671 while ((result = pread( unix_handle, buffer, length, offset->QuadPart )) == -1)
673 if (errno != EINTR)
675 status = FILE_GetNtStatus();
676 goto done;
679 if (!async_read)
680 /* update file pointer position */
681 lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
683 total = result;
684 status = (total || !length) ? STATUS_SUCCESS : STATUS_END_OF_FILE;
685 goto done;
688 else if (type == FD_TYPE_SERIAL)
690 if (async_read && (!offset || offset->QuadPart < 0))
692 status = STATUS_INVALID_PARAMETER;
693 goto done;
697 for (;;)
699 if ((result = read( unix_handle, (char *)buffer + total, length - total )) >= 0)
701 total += result;
702 if (!result || total == length)
704 if (total)
706 status = STATUS_SUCCESS;
707 goto done;
709 switch (type)
711 case FD_TYPE_FILE:
712 case FD_TYPE_CHAR:
713 status = length ? STATUS_END_OF_FILE : STATUS_SUCCESS;
714 goto done;
715 case FD_TYPE_SERIAL:
716 break;
717 default:
718 status = STATUS_PIPE_BROKEN;
719 goto done;
722 else if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
724 else if (errno != EAGAIN)
726 if (errno == EINTR) continue;
727 if (!total) status = FILE_GetNtStatus();
728 goto done;
731 if (async_read)
733 struct async_fileio_read *fileio;
734 BOOL avail_mode;
736 if ((status = get_io_avail_mode( hFile, type, &avail_mode )))
737 goto err;
738 if (total && avail_mode)
740 status = STATUS_SUCCESS;
741 goto done;
744 if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio))))
746 status = STATUS_NO_MEMORY;
747 goto err;
749 fileio->io.handle = hFile;
750 fileio->io.apc = apc;
751 fileio->io.apc_arg = apc_user;
752 fileio->already = total;
753 fileio->count = length;
754 fileio->buffer = buffer;
755 fileio->avail_mode = avail_mode;
757 SERVER_START_REQ( register_async )
759 req->type = ASYNC_TYPE_READ;
760 req->count = length;
761 req->async.handle = wine_server_obj_handle( hFile );
762 req->async.event = wine_server_obj_handle( hEvent );
763 req->async.callback = wine_server_client_ptr( FILE_AsyncReadService );
764 req->async.iosb = wine_server_client_ptr( io_status );
765 req->async.arg = wine_server_client_ptr( fileio );
766 req->async.cvalue = cvalue;
767 status = wine_server_call( req );
769 SERVER_END_REQ;
771 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
772 goto err;
774 else /* synchronous read, wait for the fd to become ready */
776 struct pollfd pfd;
777 int ret, timeout;
779 if (!timeout_init_done)
781 timeout_init_done = TRUE;
782 if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts )))
783 goto err;
784 if (hEvent) NtResetEvent( hEvent, NULL );
786 timeout = get_next_io_timeout( &timeouts, total );
788 pfd.fd = unix_handle;
789 pfd.events = POLLIN;
791 if (!timeout || !(ret = poll( &pfd, 1, timeout )))
793 if (total) /* return with what we got so far */
794 status = STATUS_SUCCESS;
795 else
796 status = (type == FD_TYPE_MAILSLOT) ? STATUS_IO_TIMEOUT : STATUS_TIMEOUT;
797 goto done;
799 if (ret == -1 && errno != EINTR)
801 status = FILE_GetNtStatus();
802 goto done;
804 /* will now restart the read */
808 done:
809 send_completion = cvalue != 0;
811 err:
812 if (needs_close) close( unix_handle );
813 if (status == STATUS_SUCCESS || (status == STATUS_END_OF_FILE && !async_read))
815 io_status->u.Status = status;
816 io_status->Information = total;
817 TRACE("= SUCCESS (%u)\n", total);
818 if (hEvent) NtSetEvent( hEvent, NULL );
819 if (apc && !status) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
820 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
822 else
824 TRACE("= 0x%08x\n", status);
825 if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
828 if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total );
830 return status;
834 /******************************************************************************
835 * NtReadFileScatter [NTDLL.@]
836 * ZwReadFileScatter [NTDLL.@]
838 NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
839 PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
840 ULONG length, PLARGE_INTEGER offset, PULONG key )
842 int result, unix_handle, needs_close;
843 unsigned int options;
844 NTSTATUS status;
845 ULONG pos = 0, total = 0;
846 enum server_fd_type type;
847 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
848 BOOL send_completion = FALSE;
850 TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
851 file, event, apc, apc_user, io_status, segments, length, offset, key);
853 if (length % page_size) return STATUS_INVALID_PARAMETER;
854 if (!io_status) return STATUS_ACCESS_VIOLATION;
856 status = server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
857 &needs_close, &type, &options );
858 if (status) return status;
860 if ((type != FD_TYPE_FILE) ||
861 (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
862 !(options & FILE_NO_INTERMEDIATE_BUFFERING))
864 status = STATUS_INVALID_PARAMETER;
865 goto error;
868 while (length)
870 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
871 result = pread( unix_handle, (char *)segments->Buffer + pos,
872 page_size - pos, offset->QuadPart + total );
873 else
874 result = read( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
876 if (result == -1)
878 if (errno == EINTR) continue;
879 status = FILE_GetNtStatus();
880 break;
882 if (!result)
884 status = STATUS_END_OF_FILE;
885 break;
887 total += result;
888 length -= result;
889 if ((pos += result) == page_size)
891 pos = 0;
892 segments++;
896 send_completion = cvalue != 0;
898 error:
899 if (needs_close) close( unix_handle );
900 if (status == STATUS_SUCCESS)
902 io_status->u.Status = status;
903 io_status->Information = total;
904 TRACE("= SUCCESS (%u)\n", total);
905 if (event) NtSetEvent( event, NULL );
906 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
907 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
909 else
911 TRACE("= 0x%08x\n", status);
912 if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
915 if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total );
917 return status;
921 /***********************************************************************
922 * FILE_AsyncWriteService (INTERNAL)
924 static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status, void **apc)
926 struct async_fileio_write *fileio = user;
927 int result, fd, needs_close;
928 enum server_fd_type type;
930 switch (status)
932 case STATUS_ALERTED:
933 /* write some data (non-blocking) */
934 if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
935 &needs_close, &type, NULL )))
936 break;
938 if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
939 result = send( fd, fileio->buffer, 0, 0 );
940 else
941 result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already );
943 if (needs_close) close( fd );
945 if (result < 0)
947 if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING;
948 else status = FILE_GetNtStatus();
950 else
952 fileio->already += result;
953 status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
955 break;
957 case STATUS_TIMEOUT:
958 case STATUS_IO_TIMEOUT:
959 if (fileio->already) status = STATUS_SUCCESS;
960 break;
962 if (status != STATUS_PENDING)
964 iosb->u.Status = status;
965 iosb->Information = fileio->already;
966 *apc = fileio_apc;
968 return status;
971 static NTSTATUS set_pending_write( HANDLE device )
973 NTSTATUS status;
975 SERVER_START_REQ( set_serial_info )
977 req->handle = wine_server_obj_handle( device );
978 req->flags = SERIALINFO_PENDING_WRITE;
979 status = wine_server_call( req );
981 SERVER_END_REQ;
982 return status;
985 /******************************************************************************
986 * NtWriteFile [NTDLL.@]
987 * ZwWriteFile [NTDLL.@]
989 * Write to an open file handle.
991 * PARAMS
992 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
993 * Event [I] Event to signal upon completion (or NULL)
994 * ApcRoutine [I] Callback to call upon completion (or NULL)
995 * ApcContext [I] Context for ApcRoutine (or NULL)
996 * IoStatusBlock [O] Receives information about the operation on return
997 * Buffer [I] Source for the data to write
998 * Length [I] Size of Buffer
999 * ByteOffset [O] Destination for the new file pointer position (or NULL)
1000 * Key [O] Function unknown (may be NULL)
1002 * RETURNS
1003 * Success: 0. IoStatusBlock is updated, and the Information member contains
1004 * The number of bytes written.
1005 * Failure: An NTSTATUS error code describing the error.
1007 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
1008 PIO_APC_ROUTINE apc, void* apc_user,
1009 PIO_STATUS_BLOCK io_status,
1010 const void* buffer, ULONG length,
1011 PLARGE_INTEGER offset, PULONG key)
1013 int result, unix_handle, needs_close;
1014 unsigned int options;
1015 struct io_timeouts timeouts;
1016 NTSTATUS status;
1017 ULONG total = 0;
1018 enum server_fd_type type;
1019 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1020 BOOL send_completion = FALSE, async_write, append_write = FALSE, timeout_init_done = FALSE;
1021 LARGE_INTEGER offset_eof;
1023 TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)!\n",
1024 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
1026 if (!io_status) return STATUS_ACCESS_VIOLATION;
1028 status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
1029 &needs_close, &type, &options );
1030 if (status == STATUS_ACCESS_DENIED)
1032 status = server_get_unix_fd( hFile, FILE_APPEND_DATA, &unix_handle,
1033 &needs_close, &type, &options );
1034 append_write = TRUE;
1036 if (status) return status;
1038 if (!virtual_check_buffer_for_read( buffer, length ))
1040 status = STATUS_INVALID_USER_BUFFER;
1041 goto done;
1044 async_write = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
1046 if (type == FD_TYPE_FILE)
1048 if (async_write &&
1049 (!offset || (offset->QuadPart < 0 && offset->QuadPart != FILE_WRITE_TO_END_OF_FILE)))
1051 status = STATUS_INVALID_PARAMETER;
1052 goto done;
1055 if (append_write)
1057 offset_eof.QuadPart = FILE_WRITE_TO_END_OF_FILE;
1058 offset = &offset_eof;
1061 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
1063 off_t off = offset->QuadPart;
1065 if (offset->QuadPart == FILE_WRITE_TO_END_OF_FILE)
1067 struct stat st;
1069 if (fstat( unix_handle, &st ) == -1)
1071 status = FILE_GetNtStatus();
1072 goto done;
1074 off = st.st_size;
1076 else if (offset->QuadPart < 0)
1078 status = STATUS_INVALID_PARAMETER;
1079 goto done;
1082 /* async I/O doesn't make sense on regular files */
1083 while ((result = pwrite( unix_handle, buffer, length, off )) == -1)
1085 if (errno != EINTR)
1087 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
1088 else status = FILE_GetNtStatus();
1089 goto done;
1093 if (!async_write)
1094 /* update file pointer position */
1095 lseek( unix_handle, off + result, SEEK_SET );
1097 total = result;
1098 status = STATUS_SUCCESS;
1099 goto done;
1102 else if (type == FD_TYPE_SERIAL)
1104 if (async_write &&
1105 (!offset || (offset->QuadPart < 0 && offset->QuadPart != FILE_WRITE_TO_END_OF_FILE)))
1107 status = STATUS_INVALID_PARAMETER;
1108 goto done;
1112 for (;;)
1114 /* zero-length writes on sockets may not work with plain write(2) */
1115 if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
1116 result = send( unix_handle, buffer, 0, 0 );
1117 else
1118 result = write( unix_handle, (const char *)buffer + total, length - total );
1120 if (result >= 0)
1122 total += result;
1123 if (total == length)
1125 status = STATUS_SUCCESS;
1126 goto done;
1128 if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
1130 else if (errno != EAGAIN)
1132 if (errno == EINTR) continue;
1133 if (!total)
1135 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
1136 else status = FILE_GetNtStatus();
1138 goto done;
1141 if (async_write)
1143 struct async_fileio_write *fileio;
1145 if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio))))
1147 status = STATUS_NO_MEMORY;
1148 goto err;
1150 fileio->io.handle = hFile;
1151 fileio->io.apc = apc;
1152 fileio->io.apc_arg = apc_user;
1153 fileio->already = total;
1154 fileio->count = length;
1155 fileio->buffer = buffer;
1157 SERVER_START_REQ( register_async )
1159 req->type = ASYNC_TYPE_WRITE;
1160 req->count = length;
1161 req->async.handle = wine_server_obj_handle( hFile );
1162 req->async.event = wine_server_obj_handle( hEvent );
1163 req->async.callback = wine_server_client_ptr( FILE_AsyncWriteService );
1164 req->async.iosb = wine_server_client_ptr( io_status );
1165 req->async.arg = wine_server_client_ptr( fileio );
1166 req->async.cvalue = cvalue;
1167 status = wine_server_call( req );
1169 SERVER_END_REQ;
1171 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
1172 goto err;
1174 else /* synchronous write, wait for the fd to become ready */
1176 struct pollfd pfd;
1177 int ret, timeout;
1179 if (!timeout_init_done)
1181 timeout_init_done = TRUE;
1182 if ((status = get_io_timeouts( hFile, type, length, FALSE, &timeouts )))
1183 goto err;
1184 if (hEvent) NtResetEvent( hEvent, NULL );
1186 timeout = get_next_io_timeout( &timeouts, total );
1188 pfd.fd = unix_handle;
1189 pfd.events = POLLOUT;
1191 if (!timeout || !(ret = poll( &pfd, 1, timeout )))
1193 /* return with what we got so far */
1194 status = total ? STATUS_SUCCESS : STATUS_TIMEOUT;
1195 goto done;
1197 if (ret == -1 && errno != EINTR)
1199 status = FILE_GetNtStatus();
1200 goto done;
1202 /* will now restart the write */
1206 done:
1207 send_completion = cvalue != 0;
1209 err:
1210 if (needs_close) close( unix_handle );
1212 if (type == FD_TYPE_SERIAL && (status == STATUS_SUCCESS || status == STATUS_PENDING))
1213 set_pending_write( hFile );
1215 if (status == STATUS_SUCCESS)
1217 io_status->u.Status = status;
1218 io_status->Information = total;
1219 TRACE("= SUCCESS (%u)\n", total);
1220 if (hEvent) NtSetEvent( hEvent, NULL );
1221 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1222 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1224 else
1226 TRACE("= 0x%08x\n", status);
1227 if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
1230 if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total );
1232 return status;
1236 /******************************************************************************
1237 * NtWriteFileGather [NTDLL.@]
1238 * ZwWriteFileGather [NTDLL.@]
1240 NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1241 PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
1242 ULONG length, PLARGE_INTEGER offset, PULONG key )
1244 int result, unix_handle, needs_close;
1245 unsigned int options;
1246 NTSTATUS status;
1247 ULONG pos = 0, total = 0;
1248 enum server_fd_type type;
1249 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1250 BOOL send_completion = FALSE;
1252 TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
1253 file, event, apc, apc_user, io_status, segments, length, offset, key);
1255 if (length % page_size) return STATUS_INVALID_PARAMETER;
1256 if (!io_status) return STATUS_ACCESS_VIOLATION;
1258 status = server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
1259 &needs_close, &type, &options );
1260 if (status) return status;
1262 if ((type != FD_TYPE_FILE) ||
1263 (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
1264 !(options & FILE_NO_INTERMEDIATE_BUFFERING))
1266 status = STATUS_INVALID_PARAMETER;
1267 goto error;
1270 while (length)
1272 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
1273 result = pwrite( unix_handle, (char *)segments->Buffer + pos,
1274 page_size - pos, offset->QuadPart + total );
1275 else
1276 result = write( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
1278 if (result == -1)
1280 if (errno == EINTR) continue;
1281 if (errno == EFAULT)
1283 status = STATUS_INVALID_USER_BUFFER;
1284 goto error;
1286 status = FILE_GetNtStatus();
1287 break;
1289 if (!result)
1291 status = STATUS_DISK_FULL;
1292 break;
1294 total += result;
1295 length -= result;
1296 if ((pos += result) == page_size)
1298 pos = 0;
1299 segments++;
1303 send_completion = cvalue != 0;
1305 error:
1306 if (needs_close) close( unix_handle );
1307 if (status == STATUS_SUCCESS)
1309 io_status->u.Status = status;
1310 io_status->Information = total;
1311 TRACE("= SUCCESS (%u)\n", total);
1312 if (event) NtSetEvent( event, NULL );
1313 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1314 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1316 else
1318 TRACE("= 0x%08x\n", status);
1319 if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
1322 if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total );
1324 return status;
1328 struct async_ioctl
1330 struct async_fileio io;
1331 HANDLE event; /* async event */
1332 void *buffer; /* buffer for output */
1333 ULONG size; /* size of buffer */
1336 /* callback for ioctl async I/O completion */
1337 static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS status, void **apc )
1339 struct async_ioctl *async = arg;
1341 if (status == STATUS_ALERTED)
1343 SERVER_START_REQ( get_ioctl_result )
1345 req->handle = wine_server_obj_handle( async->io.handle );
1346 req->user_arg = wine_server_client_ptr( async );
1347 wine_server_set_reply( req, async->buffer, async->size );
1348 status = wine_server_call( req );
1349 if (status != STATUS_PENDING) io->Information = wine_server_reply_size( reply );
1351 SERVER_END_REQ;
1353 if (status != STATUS_PENDING)
1355 io->u.Status = status;
1356 if (async->io.apc || async->event) *apc = fileio_apc;
1358 return status;
1361 /* do an ioctl call through the server */
1362 static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
1363 PIO_APC_ROUTINE apc, PVOID apc_context,
1364 IO_STATUS_BLOCK *io, ULONG code,
1365 const void *in_buffer, ULONG in_size,
1366 PVOID out_buffer, ULONG out_size )
1368 struct async_ioctl *async;
1369 NTSTATUS status;
1370 HANDLE wait_handle;
1371 ULONG options;
1372 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
1374 if (!(async = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*async) )))
1375 return STATUS_NO_MEMORY;
1376 async->io.handle = handle;
1377 async->io.apc = apc;
1378 async->io.apc_arg = apc_context;
1379 async->event = event;
1380 async->buffer = out_buffer;
1381 async->size = out_size;
1383 SERVER_START_REQ( ioctl )
1385 req->code = code;
1386 req->blocking = !apc && !event && !cvalue;
1387 req->async.handle = wine_server_obj_handle( handle );
1388 req->async.callback = wine_server_client_ptr( ioctl_completion );
1389 req->async.iosb = wine_server_client_ptr( io );
1390 req->async.arg = wine_server_client_ptr( async );
1391 req->async.event = wine_server_obj_handle( event );
1392 req->async.cvalue = cvalue;
1393 wine_server_add_data( req, in_buffer, in_size );
1394 wine_server_set_reply( req, out_buffer, out_size );
1395 status = wine_server_call( req );
1396 wait_handle = wine_server_ptr_handle( reply->wait );
1397 options = reply->options;
1398 if (status != STATUS_PENDING) io->Information = wine_server_reply_size( reply );
1400 SERVER_END_REQ;
1402 if (status == STATUS_NOT_SUPPORTED)
1403 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
1404 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1406 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
1408 if (wait_handle)
1410 NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL );
1411 status = io->u.Status;
1412 NtClose( wait_handle );
1413 RtlFreeHeap( GetProcessHeap(), 0, async );
1416 return status;
1419 /* Tell Valgrind to ignore any holes in structs we will be passing to the
1420 * server */
1421 static void ignore_server_ioctl_struct_holes (ULONG code, const void *in_buffer,
1422 ULONG in_size)
1424 #ifdef VALGRIND_MAKE_MEM_DEFINED
1425 # define IGNORE_STRUCT_HOLE(buf, size, t, f1, f2) \
1426 do { \
1427 if (FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1) < FIELD_OFFSET(t, f2)) \
1428 if ((size) >= FIELD_OFFSET(t, f2)) \
1429 VALGRIND_MAKE_MEM_DEFINED( \
1430 (const char *)(buf) + FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1), \
1431 FIELD_OFFSET(t, f2) - FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1)); \
1432 } while (0)
1434 switch (code)
1436 case FSCTL_PIPE_WAIT:
1437 IGNORE_STRUCT_HOLE(in_buffer, in_size, FILE_PIPE_WAIT_FOR_BUFFER, TimeoutSpecified, Name);
1438 break;
1440 #endif
1444 /**************************************************************************
1445 * NtDeviceIoControlFile [NTDLL.@]
1446 * ZwDeviceIoControlFile [NTDLL.@]
1448 * Perform an I/O control operation on an open file handle.
1450 * PARAMS
1451 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1452 * event [I] Event to signal upon completion (or NULL)
1453 * apc [I] Callback to call upon completion (or NULL)
1454 * apc_context [I] Context for ApcRoutine (or NULL)
1455 * io [O] Receives information about the operation on return
1456 * code [I] Control code for the operation to perform
1457 * in_buffer [I] Source for any input data required (or NULL)
1458 * in_size [I] Size of InputBuffer
1459 * out_buffer [O] Source for any output data returned (or NULL)
1460 * out_size [I] Size of OutputBuffer
1462 * RETURNS
1463 * Success: 0. IoStatusBlock is updated.
1464 * Failure: An NTSTATUS error code describing the error.
1466 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
1467 PIO_APC_ROUTINE apc, PVOID apc_context,
1468 PIO_STATUS_BLOCK io, ULONG code,
1469 PVOID in_buffer, ULONG in_size,
1470 PVOID out_buffer, ULONG out_size)
1472 ULONG device = (code >> 16);
1473 NTSTATUS status = STATUS_NOT_SUPPORTED;
1475 TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1476 handle, event, apc, apc_context, io, code,
1477 in_buffer, in_size, out_buffer, out_size);
1479 switch(device)
1481 case FILE_DEVICE_DISK:
1482 case FILE_DEVICE_CD_ROM:
1483 case FILE_DEVICE_DVD:
1484 case FILE_DEVICE_CONTROLLER:
1485 case FILE_DEVICE_MASS_STORAGE:
1486 status = CDROM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1487 in_buffer, in_size, out_buffer, out_size);
1488 break;
1489 case FILE_DEVICE_SERIAL_PORT:
1490 status = COMM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1491 in_buffer, in_size, out_buffer, out_size);
1492 break;
1493 case FILE_DEVICE_TAPE:
1494 status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
1495 in_buffer, in_size, out_buffer, out_size);
1496 break;
1499 if (status == STATUS_NOT_SUPPORTED || status == STATUS_BAD_DEVICE_TYPE)
1500 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1501 in_buffer, in_size, out_buffer, out_size );
1503 if (status != STATUS_PENDING) io->u.Status = status;
1504 return status;
1508 /**************************************************************************
1509 * NtFsControlFile [NTDLL.@]
1510 * ZwFsControlFile [NTDLL.@]
1512 * Perform a file system control operation on an open file handle.
1514 * PARAMS
1515 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1516 * event [I] Event to signal upon completion (or NULL)
1517 * apc [I] Callback to call upon completion (or NULL)
1518 * apc_context [I] Context for ApcRoutine (or NULL)
1519 * io [O] Receives information about the operation on return
1520 * code [I] Control code for the operation to perform
1521 * in_buffer [I] Source for any input data required (or NULL)
1522 * in_size [I] Size of InputBuffer
1523 * out_buffer [O] Source for any output data returned (or NULL)
1524 * out_size [I] Size of OutputBuffer
1526 * RETURNS
1527 * Success: 0. IoStatusBlock is updated.
1528 * Failure: An NTSTATUS error code describing the error.
1530 NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
1531 PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code,
1532 PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size)
1534 NTSTATUS status;
1536 TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1537 handle, event, apc, apc_context, io, code,
1538 in_buffer, in_size, out_buffer, out_size);
1540 if (!io) return STATUS_INVALID_PARAMETER;
1542 ignore_server_ioctl_struct_holes( code, in_buffer, in_size );
1544 switch(code)
1546 case FSCTL_DISMOUNT_VOLUME:
1547 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1548 in_buffer, in_size, out_buffer, out_size );
1549 if (!status) status = DIR_unmount_device( handle );
1550 break;
1552 case FSCTL_PIPE_PEEK:
1554 FILE_PIPE_PEEK_BUFFER *buffer = out_buffer;
1555 int avail = 0, fd, needs_close;
1557 if (out_size < FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ))
1559 status = STATUS_INFO_LENGTH_MISMATCH;
1560 break;
1563 if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )))
1564 break;
1566 #ifdef FIONREAD
1567 if (ioctl( fd, FIONREAD, &avail ) != 0)
1569 TRACE("FIONREAD failed reason: %s\n",strerror(errno));
1570 if (needs_close) close( fd );
1571 status = FILE_GetNtStatus();
1572 break;
1574 #endif
1575 if (!avail) /* check for closed pipe */
1577 struct pollfd pollfd;
1578 int ret;
1580 pollfd.fd = fd;
1581 pollfd.events = POLLIN;
1582 pollfd.revents = 0;
1583 ret = poll( &pollfd, 1, 0 );
1584 if (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR))))
1586 if (needs_close) close( fd );
1587 status = STATUS_PIPE_BROKEN;
1588 break;
1591 buffer->NamedPipeState = 0; /* FIXME */
1592 buffer->ReadDataAvailable = avail;
1593 buffer->NumberOfMessages = 0; /* FIXME */
1594 buffer->MessageLength = 0; /* FIXME */
1595 io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1596 status = STATUS_SUCCESS;
1597 if (avail)
1599 ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1600 if (data_size)
1602 int res = recv( fd, buffer->Data, data_size, MSG_PEEK );
1603 if (res >= 0) io->Information += res;
1606 if (needs_close) close( fd );
1608 break;
1610 case FSCTL_PIPE_DISCONNECT:
1611 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1612 in_buffer, in_size, out_buffer, out_size );
1613 if (!status)
1615 int fd = server_remove_fd_from_cache( handle );
1616 if (fd != -1) close( fd );
1618 break;
1620 case FSCTL_PIPE_IMPERSONATE:
1621 FIXME("FSCTL_PIPE_IMPERSONATE: impersonating self\n");
1622 status = RtlImpersonateSelf( SecurityImpersonation );
1623 break;
1625 case FSCTL_IS_VOLUME_MOUNTED:
1626 case FSCTL_LOCK_VOLUME:
1627 case FSCTL_UNLOCK_VOLUME:
1628 FIXME("stub! return success - Unsupported fsctl %x (device=%x access=%x func=%x method=%x)\n",
1629 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1630 status = STATUS_SUCCESS;
1631 break;
1633 case FSCTL_GET_RETRIEVAL_POINTERS:
1635 RETRIEVAL_POINTERS_BUFFER *buffer = (RETRIEVAL_POINTERS_BUFFER *)out_buffer;
1637 FIXME("stub: FSCTL_GET_RETRIEVAL_POINTERS\n");
1639 if (out_size >= sizeof(RETRIEVAL_POINTERS_BUFFER))
1641 buffer->ExtentCount = 1;
1642 buffer->StartingVcn.QuadPart = 1;
1643 buffer->Extents[0].NextVcn.QuadPart = 0;
1644 buffer->Extents[0].Lcn.QuadPart = 0;
1645 io->Information = sizeof(RETRIEVAL_POINTERS_BUFFER);
1646 status = STATUS_SUCCESS;
1648 else
1650 io->Information = 0;
1651 status = STATUS_BUFFER_TOO_SMALL;
1653 break;
1655 case FSCTL_PIPE_LISTEN:
1656 case FSCTL_PIPE_WAIT:
1657 default:
1658 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1659 in_buffer, in_size, out_buffer, out_size );
1660 break;
1663 if (status != STATUS_PENDING) io->u.Status = status;
1664 return status;
1667 /******************************************************************************
1668 * NtSetVolumeInformationFile [NTDLL.@]
1669 * ZwSetVolumeInformationFile [NTDLL.@]
1671 * Set volume information for an open file handle.
1673 * PARAMS
1674 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1675 * IoStatusBlock [O] Receives information about the operation on return
1676 * FsInformation [I] Source for volume information
1677 * Length [I] Size of FsInformation
1678 * FsInformationClass [I] Type of volume information to set
1680 * RETURNS
1681 * Success: 0. IoStatusBlock is updated.
1682 * Failure: An NTSTATUS error code describing the error.
1684 NTSTATUS WINAPI NtSetVolumeInformationFile(
1685 IN HANDLE FileHandle,
1686 PIO_STATUS_BLOCK IoStatusBlock,
1687 PVOID FsInformation,
1688 ULONG Length,
1689 FS_INFORMATION_CLASS FsInformationClass)
1691 FIXME("(%p,%p,%p,0x%08x,0x%08x) stub\n",
1692 FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
1693 return 0;
1696 #if defined(__ANDROID__) && !defined(HAVE_FUTIMENS)
1697 static int futimens( int fd, const struct timespec spec[2] )
1699 return syscall( __NR_utimensat, fd, NULL, spec, 0 );
1701 #define HAVE_FUTIMENS
1702 #endif /* __ANDROID__ */
1704 #ifndef UTIME_OMIT
1705 #define UTIME_OMIT ((1 << 30) - 2)
1706 #endif
1708 static NTSTATUS set_file_times( int fd, const LARGE_INTEGER *mtime, const LARGE_INTEGER *atime )
1710 NTSTATUS status = STATUS_SUCCESS;
1712 #ifdef HAVE_FUTIMENS
1713 struct timespec tv[2];
1715 tv[0].tv_sec = tv[1].tv_sec = 0;
1716 tv[0].tv_nsec = tv[1].tv_nsec = UTIME_OMIT;
1717 if (atime->QuadPart)
1719 tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
1720 tv[0].tv_nsec = (atime->QuadPart % 10000000) * 100;
1722 if (mtime->QuadPart)
1724 tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
1725 tv[1].tv_nsec = (mtime->QuadPart % 10000000) * 100;
1727 if (futimens( fd, tv ) == -1) status = FILE_GetNtStatus();
1729 #elif defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
1730 struct timeval tv[2];
1731 struct stat st;
1733 if (!atime->QuadPart || !mtime->QuadPart)
1736 tv[0].tv_sec = tv[0].tv_usec = 0;
1737 tv[1].tv_sec = tv[1].tv_usec = 0;
1738 if (!fstat( fd, &st ))
1740 tv[0].tv_sec = st.st_atime;
1741 tv[1].tv_sec = st.st_mtime;
1742 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1743 tv[0].tv_usec = st.st_atim.tv_nsec / 1000;
1744 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
1745 tv[0].tv_usec = st.st_atimespec.tv_nsec / 1000;
1746 #endif
1747 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1748 tv[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1749 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
1750 tv[1].tv_usec = st.st_mtimespec.tv_nsec / 1000;
1751 #endif
1754 if (atime->QuadPart)
1756 tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
1757 tv[0].tv_usec = (atime->QuadPart % 10000000) / 10;
1759 if (mtime->QuadPart)
1761 tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
1762 tv[1].tv_usec = (mtime->QuadPart % 10000000) / 10;
1764 #ifdef HAVE_FUTIMES
1765 if (futimes( fd, tv ) == -1) status = FILE_GetNtStatus();
1766 #elif defined(HAVE_FUTIMESAT)
1767 if (futimesat( fd, NULL, tv ) == -1) status = FILE_GetNtStatus();
1768 #endif
1770 #else /* HAVE_FUTIMES || HAVE_FUTIMESAT */
1771 FIXME( "setting file times not supported\n" );
1772 status = STATUS_NOT_IMPLEMENTED;
1773 #endif
1774 return status;
1777 static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, LARGE_INTEGER *ctime,
1778 LARGE_INTEGER *atime, LARGE_INTEGER *creation )
1780 RtlSecondsSince1970ToTime( st->st_mtime, mtime );
1781 RtlSecondsSince1970ToTime( st->st_ctime, ctime );
1782 RtlSecondsSince1970ToTime( st->st_atime, atime );
1783 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1784 mtime->QuadPart += st->st_mtim.tv_nsec / 100;
1785 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
1786 mtime->QuadPart += st->st_mtimespec.tv_nsec / 100;
1787 #endif
1788 #ifdef HAVE_STRUCT_STAT_ST_CTIM
1789 ctime->QuadPart += st->st_ctim.tv_nsec / 100;
1790 #elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
1791 ctime->QuadPart += st->st_ctimespec.tv_nsec / 100;
1792 #endif
1793 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1794 atime->QuadPart += st->st_atim.tv_nsec / 100;
1795 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
1796 atime->QuadPart += st->st_atimespec.tv_nsec / 100;
1797 #endif
1798 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
1799 RtlSecondsSince1970ToTime( st->st_birthtime, creation );
1800 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIM
1801 creation->QuadPart += st->st_birthtim.tv_nsec / 100;
1802 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
1803 creation->QuadPart += st->st_birthtimespec.tv_nsec / 100;
1804 #endif
1805 #elif defined(HAVE_STRUCT_STAT___ST_BIRTHTIME)
1806 RtlSecondsSince1970ToTime( st->__st_birthtime, creation );
1807 #ifdef HAVE_STRUCT_STAT___ST_BIRTHTIM
1808 creation->QuadPart += st->__st_birthtim.tv_nsec / 100;
1809 #endif
1810 #else
1811 *creation = *mtime;
1812 #endif
1815 /* fill in the file information that depends on the stat and attribute info */
1816 NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
1817 FILE_INFORMATION_CLASS class )
1819 switch (class)
1821 case FileBasicInformation:
1823 FILE_BASIC_INFORMATION *info = ptr;
1825 get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
1826 &info->LastAccessTime, &info->CreationTime );
1827 info->FileAttributes = attr;
1829 break;
1830 case FileStandardInformation:
1832 FILE_STANDARD_INFORMATION *info = ptr;
1834 if ((info->Directory = S_ISDIR(st->st_mode)))
1836 info->AllocationSize.QuadPart = 0;
1837 info->EndOfFile.QuadPart = 0;
1838 info->NumberOfLinks = 1;
1840 else
1842 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
1843 info->EndOfFile.QuadPart = st->st_size;
1844 info->NumberOfLinks = st->st_nlink;
1847 break;
1848 case FileInternalInformation:
1850 FILE_INTERNAL_INFORMATION *info = ptr;
1851 info->IndexNumber.QuadPart = st->st_ino;
1853 break;
1854 case FileEndOfFileInformation:
1856 FILE_END_OF_FILE_INFORMATION *info = ptr;
1857 info->EndOfFile.QuadPart = S_ISDIR(st->st_mode) ? 0 : st->st_size;
1859 break;
1860 case FileAllInformation:
1862 FILE_ALL_INFORMATION *info = ptr;
1863 fill_file_info( st, attr, &info->BasicInformation, FileBasicInformation );
1864 fill_file_info( st, attr, &info->StandardInformation, FileStandardInformation );
1865 fill_file_info( st, attr, &info->InternalInformation, FileInternalInformation );
1867 break;
1868 /* all directory structures start with the FileDirectoryInformation layout */
1869 case FileBothDirectoryInformation:
1870 case FileFullDirectoryInformation:
1871 case FileDirectoryInformation:
1873 FILE_DIRECTORY_INFORMATION *info = ptr;
1875 get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
1876 &info->LastAccessTime, &info->CreationTime );
1877 if (S_ISDIR(st->st_mode))
1879 info->AllocationSize.QuadPart = 0;
1880 info->EndOfFile.QuadPart = 0;
1882 else
1884 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
1885 info->EndOfFile.QuadPart = st->st_size;
1887 info->FileAttributes = attr;
1889 break;
1890 case FileIdFullDirectoryInformation:
1892 FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr;
1893 info->FileId.QuadPart = st->st_ino;
1894 fill_file_info( st, attr, info, FileDirectoryInformation );
1896 break;
1897 case FileIdBothDirectoryInformation:
1899 FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr;
1900 info->FileId.QuadPart = st->st_ino;
1901 fill_file_info( st, attr, info, FileDirectoryInformation );
1903 break;
1905 default:
1906 return STATUS_INVALID_INFO_CLASS;
1908 return STATUS_SUCCESS;
1911 NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name )
1913 data_size_t size = 1024;
1914 NTSTATUS ret;
1915 char *name;
1917 for (;;)
1919 name = RtlAllocateHeap( GetProcessHeap(), 0, size + 1 );
1920 if (!name) return STATUS_NO_MEMORY;
1921 unix_name->MaximumLength = size + 1;
1923 SERVER_START_REQ( get_handle_unix_name )
1925 req->handle = wine_server_obj_handle( handle );
1926 wine_server_set_reply( req, name, size );
1927 ret = wine_server_call( req );
1928 size = reply->name_len;
1930 SERVER_END_REQ;
1932 if (!ret)
1934 name[size] = 0;
1935 unix_name->Buffer = name;
1936 unix_name->Length = size;
1937 break;
1939 RtlFreeHeap( GetProcessHeap(), 0, name );
1940 if (ret != STATUS_BUFFER_OVERFLOW) break;
1942 return ret;
1945 static NTSTATUS fill_name_info( const ANSI_STRING *unix_name, FILE_NAME_INFORMATION *info, LONG *name_len )
1947 UNICODE_STRING nt_name;
1948 NTSTATUS status;
1950 if (!(status = wine_unix_to_nt_file_name( unix_name, &nt_name )))
1952 const WCHAR *ptr = nt_name.Buffer;
1953 const WCHAR *end = ptr + (nt_name.Length / sizeof(WCHAR));
1955 /* Skip the volume mount point. */
1956 while (ptr != end && *ptr == '\\') ++ptr;
1957 while (ptr != end && *ptr != '\\') ++ptr;
1958 while (ptr != end && *ptr == '\\') ++ptr;
1959 while (ptr != end && *ptr != '\\') ++ptr;
1961 info->FileNameLength = (end - ptr) * sizeof(WCHAR);
1962 if (*name_len < info->FileNameLength) status = STATUS_BUFFER_OVERFLOW;
1963 else *name_len = info->FileNameLength;
1965 memcpy( info->FileName, ptr, *name_len );
1966 RtlFreeUnicodeString( &nt_name );
1969 return status;
1972 /******************************************************************************
1973 * NtQueryInformationFile [NTDLL.@]
1974 * ZwQueryInformationFile [NTDLL.@]
1976 * Get information about an open file handle.
1978 * PARAMS
1979 * hFile [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1980 * io [O] Receives information about the operation on return
1981 * ptr [O] Destination for file information
1982 * len [I] Size of FileInformation
1983 * class [I] Type of file information to get
1985 * RETURNS
1986 * Success: 0. IoStatusBlock and FileInformation are updated.
1987 * Failure: An NTSTATUS error code describing the error.
1989 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
1990 PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
1992 static const size_t info_sizes[] =
1995 sizeof(FILE_DIRECTORY_INFORMATION), /* FileDirectoryInformation */
1996 sizeof(FILE_FULL_DIRECTORY_INFORMATION), /* FileFullDirectoryInformation */
1997 sizeof(FILE_BOTH_DIRECTORY_INFORMATION), /* FileBothDirectoryInformation */
1998 sizeof(FILE_BASIC_INFORMATION), /* FileBasicInformation */
1999 sizeof(FILE_STANDARD_INFORMATION), /* FileStandardInformation */
2000 sizeof(FILE_INTERNAL_INFORMATION), /* FileInternalInformation */
2001 sizeof(FILE_EA_INFORMATION), /* FileEaInformation */
2002 sizeof(FILE_ACCESS_INFORMATION), /* FileAccessInformation */
2003 sizeof(FILE_NAME_INFORMATION), /* FileNameInformation */
2004 sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
2005 0, /* FileLinkInformation */
2006 sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR), /* FileNamesInformation */
2007 sizeof(FILE_DISPOSITION_INFORMATION), /* FileDispositionInformation */
2008 sizeof(FILE_POSITION_INFORMATION), /* FilePositionInformation */
2009 sizeof(FILE_FULL_EA_INFORMATION), /* FileFullEaInformation */
2010 sizeof(FILE_MODE_INFORMATION), /* FileModeInformation */
2011 sizeof(FILE_ALIGNMENT_INFORMATION), /* FileAlignmentInformation */
2012 sizeof(FILE_ALL_INFORMATION), /* FileAllInformation */
2013 sizeof(FILE_ALLOCATION_INFORMATION), /* FileAllocationInformation */
2014 sizeof(FILE_END_OF_FILE_INFORMATION), /* FileEndOfFileInformation */
2015 0, /* FileAlternateNameInformation */
2016 sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
2017 sizeof(FILE_PIPE_INFORMATION), /* FilePipeInformation */
2018 sizeof(FILE_PIPE_LOCAL_INFORMATION), /* FilePipeLocalInformation */
2019 0, /* FilePipeRemoteInformation */
2020 sizeof(FILE_MAILSLOT_QUERY_INFORMATION), /* FileMailslotQueryInformation */
2021 0, /* FileMailslotSetInformation */
2022 0, /* FileCompressionInformation */
2023 0, /* FileObjectIdInformation */
2024 0, /* FileCompletionInformation */
2025 0, /* FileMoveClusterInformation */
2026 0, /* FileQuotaInformation */
2027 0, /* FileReparsePointInformation */
2028 0, /* FileNetworkOpenInformation */
2029 0, /* FileAttributeTagInformation */
2030 0, /* FileTrackingInformation */
2031 0, /* FileIdBothDirectoryInformation */
2032 0, /* FileIdFullDirectoryInformation */
2033 0, /* FileValidDataLengthInformation */
2034 0, /* FileShortNameInformation */
2038 0, /* FileSfioReserveInformation */
2039 0, /* FileSfioVolumeInformation */
2040 0, /* FileHardLinkInformation */
2042 0, /* FileNormalizedNameInformation */
2044 0, /* FileIdGlobalTxDirectoryInformation */
2048 0 /* FileStandardLinkInformation */
2051 struct stat st;
2052 int fd, needs_close = FALSE;
2053 ULONG attr;
2055 TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
2057 io->Information = 0;
2059 if (class <= 0 || class >= FileMaximumInformation)
2060 return io->u.Status = STATUS_INVALID_INFO_CLASS;
2061 if (!info_sizes[class])
2063 FIXME("Unsupported class (%d)\n", class);
2064 return io->u.Status = STATUS_NOT_IMPLEMENTED;
2066 if (len < info_sizes[class])
2067 return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
2069 if (class != FilePipeInformation && class != FilePipeLocalInformation)
2071 if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, NULL )))
2072 return io->u.Status;
2075 switch (class)
2077 case FileBasicInformation:
2078 if (fd_get_file_info( fd, &st, &attr ) == -1)
2079 io->u.Status = FILE_GetNtStatus();
2080 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2081 io->u.Status = STATUS_INVALID_INFO_CLASS;
2082 else
2083 fill_file_info( &st, attr, ptr, class );
2084 break;
2085 case FileStandardInformation:
2087 FILE_STANDARD_INFORMATION *info = ptr;
2089 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2090 else
2092 fill_file_info( &st, attr, info, class );
2093 info->DeletePending = FALSE; /* FIXME */
2096 break;
2097 case FilePositionInformation:
2099 FILE_POSITION_INFORMATION *info = ptr;
2100 off_t res = lseek( fd, 0, SEEK_CUR );
2101 if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
2102 else info->CurrentByteOffset.QuadPart = res;
2104 break;
2105 case FileInternalInformation:
2106 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2107 else fill_file_info( &st, attr, ptr, class );
2108 break;
2109 case FileEaInformation:
2111 FILE_EA_INFORMATION *info = ptr;
2112 info->EaSize = 0;
2114 break;
2115 case FileEndOfFileInformation:
2116 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2117 else fill_file_info( &st, attr, ptr, class );
2118 break;
2119 case FileAllInformation:
2121 FILE_ALL_INFORMATION *info = ptr;
2122 ANSI_STRING unix_name;
2124 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2125 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2126 io->u.Status = STATUS_INVALID_INFO_CLASS;
2127 else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2129 LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
2131 fill_file_info( &st, attr, info, FileAllInformation );
2132 info->StandardInformation.DeletePending = FALSE; /* FIXME */
2133 info->EaInformation.EaSize = 0;
2134 info->AccessInformation.AccessFlags = 0; /* FIXME */
2135 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
2136 info->ModeInformation.Mode = 0; /* FIXME */
2137 info->AlignmentInformation.AlignmentRequirement = 1; /* FIXME */
2139 io->u.Status = fill_name_info( &unix_name, &info->NameInformation, &name_len );
2140 RtlFreeAnsiString( &unix_name );
2141 io->Information = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + name_len;
2144 break;
2145 case FileMailslotQueryInformation:
2147 FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
2149 SERVER_START_REQ( set_mailslot_info )
2151 req->handle = wine_server_obj_handle( hFile );
2152 req->flags = 0;
2153 io->u.Status = wine_server_call( req );
2154 if( io->u.Status == STATUS_SUCCESS )
2156 info->MaximumMessageSize = reply->max_msgsize;
2157 info->MailslotQuota = 0;
2158 info->NextMessageSize = 0;
2159 info->MessagesAvailable = 0;
2160 info->ReadTimeout.QuadPart = reply->read_timeout;
2163 SERVER_END_REQ;
2164 if (!io->u.Status)
2166 char *tmpbuf;
2167 ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000;
2168 if (size > 0x10000) size = 0x10000;
2169 if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2171 if (!server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
2173 int res = recv( fd, tmpbuf, size, MSG_PEEK );
2174 info->MessagesAvailable = (res > 0);
2175 info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE;
2176 if (needs_close) close( fd );
2178 RtlFreeHeap( GetProcessHeap(), 0, tmpbuf );
2182 break;
2183 case FilePipeInformation:
2185 FILE_PIPE_INFORMATION* pi = ptr;
2187 SERVER_START_REQ( get_named_pipe_info )
2189 req->handle = wine_server_obj_handle( hFile );
2190 if (!(io->u.Status = wine_server_call( req )))
2192 pi->ReadMode = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_READ) ?
2193 FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
2194 pi->CompletionMode = (reply->flags & NAMED_PIPE_NONBLOCKING_MODE) ?
2195 FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
2198 SERVER_END_REQ;
2200 break;
2201 case FilePipeLocalInformation:
2203 FILE_PIPE_LOCAL_INFORMATION* pli = ptr;
2205 SERVER_START_REQ( get_named_pipe_info )
2207 req->handle = wine_server_obj_handle( hFile );
2208 if (!(io->u.Status = wine_server_call( req )))
2210 pli->NamedPipeType = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ?
2211 FILE_PIPE_TYPE_MESSAGE : FILE_PIPE_TYPE_BYTE;
2212 switch (reply->sharing)
2214 case FILE_SHARE_READ:
2215 pli->NamedPipeConfiguration = FILE_PIPE_OUTBOUND;
2216 break;
2217 case FILE_SHARE_WRITE:
2218 pli->NamedPipeConfiguration = FILE_PIPE_INBOUND;
2219 break;
2220 case FILE_SHARE_READ | FILE_SHARE_WRITE:
2221 pli->NamedPipeConfiguration = FILE_PIPE_FULL_DUPLEX;
2222 break;
2224 pli->MaximumInstances = reply->maxinstances;
2225 pli->CurrentInstances = reply->instances;
2226 pli->InboundQuota = reply->insize;
2227 pli->ReadDataAvailable = 0; /* FIXME */
2228 pli->OutboundQuota = reply->outsize;
2229 pli->WriteQuotaAvailable = 0; /* FIXME */
2230 pli->NamedPipeState = 0; /* FIXME */
2231 pli->NamedPipeEnd = (reply->flags & NAMED_PIPE_SERVER_END) ?
2232 FILE_PIPE_SERVER_END : FILE_PIPE_CLIENT_END;
2235 SERVER_END_REQ;
2237 break;
2238 case FileNameInformation:
2240 FILE_NAME_INFORMATION *info = ptr;
2241 ANSI_STRING unix_name;
2243 if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2245 LONG name_len = len - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2246 io->u.Status = fill_name_info( &unix_name, info, &name_len );
2247 RtlFreeAnsiString( &unix_name );
2248 io->Information = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + name_len;
2251 break;
2252 default:
2253 FIXME("Unsupported class (%d)\n", class);
2254 io->u.Status = STATUS_NOT_IMPLEMENTED;
2255 break;
2257 if (needs_close) close( fd );
2258 if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
2259 return io->u.Status;
2262 /******************************************************************************
2263 * NtSetInformationFile [NTDLL.@]
2264 * ZwSetInformationFile [NTDLL.@]
2266 * Set information about an open file handle.
2268 * PARAMS
2269 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2270 * io [O] Receives information about the operation on return
2271 * ptr [I] Source for file information
2272 * len [I] Size of FileInformation
2273 * class [I] Type of file information to set
2275 * RETURNS
2276 * Success: 0. io is updated.
2277 * Failure: An NTSTATUS error code describing the error.
2279 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
2280 PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
2282 int fd, needs_close;
2284 TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", handle, io, ptr, len, class);
2286 io->u.Status = STATUS_SUCCESS;
2287 switch (class)
2289 case FileBasicInformation:
2290 if (len >= sizeof(FILE_BASIC_INFORMATION))
2292 struct stat st;
2293 const FILE_BASIC_INFORMATION *info = ptr;
2295 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2296 return io->u.Status;
2298 if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
2299 io->u.Status = set_file_times( fd, &info->LastWriteTime, &info->LastAccessTime );
2301 if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
2303 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2304 else
2306 if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
2308 if (S_ISDIR( st.st_mode))
2309 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
2310 else
2311 st.st_mode &= ~0222; /* clear write permission bits */
2313 else
2315 /* add write permission only where we already have read permission */
2316 st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
2318 if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
2322 if (needs_close) close( fd );
2324 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2325 break;
2327 case FilePositionInformation:
2328 if (len >= sizeof(FILE_POSITION_INFORMATION))
2330 const FILE_POSITION_INFORMATION *info = ptr;
2332 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2333 return io->u.Status;
2335 if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
2336 io->u.Status = FILE_GetNtStatus();
2338 if (needs_close) close( fd );
2340 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2341 break;
2343 case FileEndOfFileInformation:
2344 if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
2346 struct stat st;
2347 const FILE_END_OF_FILE_INFORMATION *info = ptr;
2349 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2350 return io->u.Status;
2352 /* first try normal truncate */
2353 if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2355 /* now check for the need to extend the file */
2356 if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
2358 static const char zero;
2360 /* extend the file one byte beyond the requested size and then truncate it */
2361 /* this should work around ftruncate implementations that can't extend files */
2362 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
2363 ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2365 io->u.Status = FILE_GetNtStatus();
2367 if (needs_close) close( fd );
2369 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2370 break;
2372 case FilePipeInformation:
2373 if (len >= sizeof(FILE_PIPE_INFORMATION))
2375 FILE_PIPE_INFORMATION *info = ptr;
2377 if ((info->CompletionMode | info->ReadMode) & ~1)
2379 io->u.Status = STATUS_INVALID_PARAMETER;
2380 break;
2383 SERVER_START_REQ( set_named_pipe_info )
2385 req->handle = wine_server_obj_handle( handle );
2386 req->flags = (info->CompletionMode ? NAMED_PIPE_NONBLOCKING_MODE : 0) |
2387 (info->ReadMode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0);
2388 io->u.Status = wine_server_call( req );
2390 SERVER_END_REQ;
2392 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2393 break;
2395 case FileMailslotSetInformation:
2397 FILE_MAILSLOT_SET_INFORMATION *info = ptr;
2399 SERVER_START_REQ( set_mailslot_info )
2401 req->handle = wine_server_obj_handle( handle );
2402 req->flags = MAILSLOT_SET_READ_TIMEOUT;
2403 req->read_timeout = info->ReadTimeout.QuadPart;
2404 io->u.Status = wine_server_call( req );
2406 SERVER_END_REQ;
2408 break;
2410 case FileCompletionInformation:
2411 if (len >= sizeof(FILE_COMPLETION_INFORMATION))
2413 FILE_COMPLETION_INFORMATION *info = ptr;
2415 SERVER_START_REQ( set_completion_info )
2417 req->handle = wine_server_obj_handle( handle );
2418 req->chandle = wine_server_obj_handle( info->CompletionPort );
2419 req->ckey = info->CompletionKey;
2420 io->u.Status = wine_server_call( req );
2422 SERVER_END_REQ;
2423 } else
2424 io->u.Status = STATUS_INVALID_PARAMETER_3;
2425 break;
2427 case FileAllInformation:
2428 io->u.Status = STATUS_INVALID_INFO_CLASS;
2429 break;
2431 case FileValidDataLengthInformation:
2432 if (len >= sizeof(FILE_VALID_DATA_LENGTH_INFORMATION))
2434 struct stat st;
2435 const FILE_VALID_DATA_LENGTH_INFORMATION *info = ptr;
2437 if ((io->u.Status = server_get_unix_fd( handle, FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL )))
2438 return io->u.Status;
2440 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2441 else if (info->ValidDataLength.QuadPart <= 0 || (off_t)info->ValidDataLength.QuadPart > st.st_size)
2442 io->u.Status = STATUS_INVALID_PARAMETER;
2443 else
2445 #ifdef HAVE_FALLOCATE
2446 if (fallocate( fd, 0, 0, (off_t)info->ValidDataLength.QuadPart ) == -1)
2448 NTSTATUS status = FILE_GetNtStatus();
2449 if (status == STATUS_NOT_SUPPORTED) WARN( "fallocate not supported on this filesystem\n" );
2450 else io->u.Status = status;
2452 #else
2453 FIXME( "setting valid data length not supported\n" );
2454 #endif
2456 if (needs_close) close( fd );
2458 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2459 break;
2461 default:
2462 FIXME("Unsupported class (%d)\n", class);
2463 io->u.Status = STATUS_NOT_IMPLEMENTED;
2464 break;
2466 io->Information = 0;
2467 return io->u.Status;
2471 /******************************************************************************
2472 * NtQueryFullAttributesFile (NTDLL.@)
2474 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
2475 FILE_NETWORK_OPEN_INFORMATION *info )
2477 ANSI_STRING unix_name;
2478 NTSTATUS status;
2480 if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2482 ULONG attributes;
2483 struct stat st;
2485 if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
2486 status = FILE_GetNtStatus();
2487 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2488 status = STATUS_INVALID_INFO_CLASS;
2489 else
2491 FILE_BASIC_INFORMATION basic;
2492 FILE_STANDARD_INFORMATION std;
2494 fill_file_info( &st, attributes, &basic, FileBasicInformation );
2495 fill_file_info( &st, attributes, &std, FileStandardInformation );
2497 info->CreationTime = basic.CreationTime;
2498 info->LastAccessTime = basic.LastAccessTime;
2499 info->LastWriteTime = basic.LastWriteTime;
2500 info->ChangeTime = basic.ChangeTime;
2501 info->AllocationSize = std.AllocationSize;
2502 info->EndOfFile = std.EndOfFile;
2503 info->FileAttributes = basic.FileAttributes;
2504 if (DIR_is_hidden_file( attr->ObjectName ))
2505 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2507 RtlFreeAnsiString( &unix_name );
2509 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2510 return status;
2514 /******************************************************************************
2515 * NtQueryAttributesFile (NTDLL.@)
2516 * ZwQueryAttributesFile (NTDLL.@)
2518 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
2520 ANSI_STRING unix_name;
2521 NTSTATUS status;
2523 if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2525 ULONG attributes;
2526 struct stat st;
2528 if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
2529 status = FILE_GetNtStatus();
2530 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2531 status = STATUS_INVALID_INFO_CLASS;
2532 else
2534 status = fill_file_info( &st, attributes, info, FileBasicInformation );
2535 if (DIR_is_hidden_file( attr->ObjectName ))
2536 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2538 RtlFreeAnsiString( &unix_name );
2540 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2541 return status;
2545 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2546 /* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */
2547 static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename,
2548 unsigned int flags )
2550 if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename))
2552 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2553 /* Don't assume read-only, let the mount options set it below */
2554 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2556 else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) ||
2557 !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename))
2559 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2560 info->Characteristics |= FILE_REMOTE_DEVICE;
2562 else if (!strcmp("procfs", fstypename))
2563 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2564 else
2565 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2567 if (flags & MNT_RDONLY)
2568 info->Characteristics |= FILE_READ_ONLY_DEVICE;
2570 if (!(flags & MNT_LOCAL))
2572 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2573 info->Characteristics |= FILE_REMOTE_DEVICE;
2576 #endif
2578 static inline BOOL is_device_placeholder( int fd )
2580 static const char wine_placeholder[] = "Wine device placeholder";
2581 char buffer[sizeof(wine_placeholder)-1];
2583 if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
2584 return FALSE;
2585 return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
2588 /******************************************************************************
2589 * get_device_info
2591 * Implementation of the FileFsDeviceInformation query for NtQueryVolumeInformationFile.
2593 static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
2595 struct stat st;
2597 info->Characteristics = 0;
2598 if (fstat( fd, &st ) < 0) return FILE_GetNtStatus();
2599 if (S_ISCHR( st.st_mode ))
2601 info->DeviceType = FILE_DEVICE_UNKNOWN;
2602 #ifdef linux
2603 switch(major(st.st_rdev))
2605 case MEM_MAJOR:
2606 info->DeviceType = FILE_DEVICE_NULL;
2607 break;
2608 case TTY_MAJOR:
2609 info->DeviceType = FILE_DEVICE_SERIAL_PORT;
2610 break;
2611 case LP_MAJOR:
2612 info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
2613 break;
2614 case SCSI_TAPE_MAJOR:
2615 info->DeviceType = FILE_DEVICE_TAPE;
2616 break;
2618 #endif
2620 else if (S_ISBLK( st.st_mode ))
2622 info->DeviceType = FILE_DEVICE_DISK;
2624 else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
2626 info->DeviceType = FILE_DEVICE_NAMED_PIPE;
2628 else if (is_device_placeholder( fd ))
2630 info->DeviceType = FILE_DEVICE_DISK;
2632 else /* regular file or directory */
2634 #if defined(linux) && defined(HAVE_FSTATFS)
2635 struct statfs stfs;
2637 /* check for floppy disk */
2638 if (major(st.st_dev) == FLOPPY_MAJOR)
2639 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2641 if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
2642 switch (stfs.f_type)
2644 case 0x9660: /* iso9660 */
2645 case 0x9fa1: /* supermount */
2646 case 0x15013346: /* udf */
2647 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2648 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2649 break;
2650 case 0x6969: /* nfs */
2651 case 0x517B: /* smbfs */
2652 case 0x564c: /* ncpfs */
2653 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2654 info->Characteristics |= FILE_REMOTE_DEVICE;
2655 break;
2656 case 0x01021994: /* tmpfs */
2657 case 0x28cd3d45: /* cramfs */
2658 case 0x1373: /* devfs */
2659 case 0x9fa0: /* procfs */
2660 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2661 break;
2662 default:
2663 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2664 break;
2666 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2667 struct statfs stfs;
2669 if (fstatfs( fd, &stfs ) < 0)
2670 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2671 else
2672 get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags );
2673 #elif defined(__NetBSD__)
2674 struct statvfs stfs;
2676 if (fstatvfs( fd, &stfs) < 0)
2677 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2678 else
2679 get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag );
2680 #elif defined(sun)
2681 /* Use dkio to work out device types */
2683 # include <sys/dkio.h>
2684 # include <sys/vtoc.h>
2685 struct dk_cinfo dkinf;
2686 int retval = ioctl(fd, DKIOCINFO, &dkinf);
2687 if(retval==-1){
2688 WARN("Unable to get disk device type information - assuming a disk like device\n");
2689 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2691 switch (dkinf.dki_ctype)
2693 case DKC_CDROM:
2694 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2695 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2696 break;
2697 case DKC_NCRFLOPPY:
2698 case DKC_SMSFLOPPY:
2699 case DKC_INTEL82072:
2700 case DKC_INTEL82077:
2701 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2702 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2703 break;
2704 case DKC_MD:
2705 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2706 break;
2707 default:
2708 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2711 #else
2712 static int warned;
2713 if (!warned++) FIXME( "device info not properly supported on this platform\n" );
2714 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2715 #endif
2716 info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
2718 return STATUS_SUCCESS;
2722 /******************************************************************************
2723 * NtQueryVolumeInformationFile [NTDLL.@]
2724 * ZwQueryVolumeInformationFile [NTDLL.@]
2726 * Get volume information for an open file handle.
2728 * PARAMS
2729 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2730 * io [O] Receives information about the operation on return
2731 * buffer [O] Destination for volume information
2732 * length [I] Size of FsInformation
2733 * info_class [I] Type of volume information to set
2735 * RETURNS
2736 * Success: 0. io and buffer are updated.
2737 * Failure: An NTSTATUS error code describing the error.
2739 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
2740 PVOID buffer, ULONG length,
2741 FS_INFORMATION_CLASS info_class )
2743 int fd, needs_close;
2744 struct stat st;
2745 static int once;
2747 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
2748 return io->u.Status;
2750 io->u.Status = STATUS_NOT_IMPLEMENTED;
2751 io->Information = 0;
2753 switch( info_class )
2755 case FileFsVolumeInformation:
2756 if (!once++) FIXME( "%p: volume info not supported\n", handle );
2757 break;
2758 case FileFsLabelInformation:
2759 FIXME( "%p: label info not supported\n", handle );
2760 break;
2761 case FileFsSizeInformation:
2762 if (length < sizeof(FILE_FS_SIZE_INFORMATION))
2763 io->u.Status = STATUS_BUFFER_TOO_SMALL;
2764 else
2766 FILE_FS_SIZE_INFORMATION *info = buffer;
2768 if (fstat( fd, &st ) < 0)
2770 io->u.Status = FILE_GetNtStatus();
2771 break;
2773 if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2775 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
2777 else
2779 ULONGLONG bsize;
2780 /* Linux's fstatvfs is buggy */
2781 #if !defined(linux) || !defined(HAVE_FSTATFS)
2782 struct statvfs stfs;
2784 if (fstatvfs( fd, &stfs ) < 0)
2786 io->u.Status = FILE_GetNtStatus();
2787 break;
2789 bsize = stfs.f_frsize;
2790 #else
2791 struct statfs stfs;
2792 if (fstatfs( fd, &stfs ) < 0)
2794 io->u.Status = FILE_GetNtStatus();
2795 break;
2797 bsize = stfs.f_bsize;
2798 #endif
2799 if (bsize == 2048) /* assume CD-ROM */
2801 info->BytesPerSector = 2048;
2802 info->SectorsPerAllocationUnit = 1;
2804 else
2806 info->BytesPerSector = 512;
2807 info->SectorsPerAllocationUnit = 8;
2809 info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2810 info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2811 io->Information = sizeof(*info);
2812 io->u.Status = STATUS_SUCCESS;
2815 break;
2816 case FileFsDeviceInformation:
2817 if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
2818 io->u.Status = STATUS_BUFFER_TOO_SMALL;
2819 else
2821 FILE_FS_DEVICE_INFORMATION *info = buffer;
2823 if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS)
2824 io->Information = sizeof(*info);
2826 break;
2827 case FileFsAttributeInformation:
2828 if (length < offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[sizeof(ntfsW)/sizeof(WCHAR)] ))
2829 io->u.Status = STATUS_BUFFER_TOO_SMALL;
2830 else
2832 FILE_FS_ATTRIBUTE_INFORMATION *info = buffer;
2834 FIXME( "%p: faking attribute info\n", handle );
2835 info->FileSystemAttribute = FILE_SUPPORTS_ENCRYPTION | FILE_FILE_COMPRESSION |
2836 FILE_PERSISTENT_ACLS | FILE_UNICODE_ON_DISK |
2837 FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH;
2838 info->MaximumComponentNameLength = MAXIMUM_FILENAME_LENGTH - 1;
2839 info->FileSystemNameLength = sizeof(ntfsW);
2840 memcpy(info->FileSystemName, ntfsW, sizeof(ntfsW));
2842 io->Information = sizeof(*info);
2843 io->u.Status = STATUS_SUCCESS;
2845 break;
2846 case FileFsControlInformation:
2847 FIXME( "%p: control info not supported\n", handle );
2848 break;
2849 case FileFsFullSizeInformation:
2850 FIXME( "%p: full size info not supported\n", handle );
2851 break;
2852 case FileFsObjectIdInformation:
2853 FIXME( "%p: object id info not supported\n", handle );
2854 break;
2855 case FileFsMaximumInformation:
2856 FIXME( "%p: maximum info not supported\n", handle );
2857 break;
2858 default:
2859 io->u.Status = STATUS_INVALID_PARAMETER;
2860 break;
2862 if (needs_close) close( fd );
2863 return io->u.Status;
2867 /******************************************************************
2868 * NtQueryEaFile (NTDLL.@)
2870 * Read extended attributes from NTFS files.
2872 * PARAMS
2873 * hFile [I] File handle, must be opened with FILE_READ_EA access
2874 * iosb [O] Receives information about the operation on return
2875 * buffer [O] Output buffer
2876 * length [I] Length of output buffer
2877 * single_entry [I] Only read and return one entry
2878 * ea_list [I] Optional list with names of EAs to return
2879 * ea_list_len [I] Length of ea_list in bytes
2880 * ea_index [I] Optional pointer to 1-based index of attribute to return
2881 * restart [I] restart EA scan
2883 * RETURNS
2884 * Success: 0. Atrributes read into buffer
2885 * Failure: An NTSTATUS error code describing the error.
2887 NTSTATUS WINAPI NtQueryEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length,
2888 BOOLEAN single_entry, PVOID ea_list, ULONG ea_list_len,
2889 PULONG ea_index, BOOLEAN restart )
2891 FIXME("(%p,%p,%p,%d,%d,%p,%d,%p,%d) stub\n",
2892 hFile, iosb, buffer, length, single_entry, ea_list,
2893 ea_list_len, ea_index, restart);
2894 return STATUS_ACCESS_DENIED;
2898 /******************************************************************
2899 * NtSetEaFile (NTDLL.@)
2901 * Update extended attributes for NTFS files.
2903 * PARAMS
2904 * hFile [I] File handle, must be opened with FILE_READ_EA access
2905 * iosb [O] Receives information about the operation on return
2906 * buffer [I] Buffer with EA information
2907 * length [I] Length of buffer
2909 * RETURNS
2910 * Success: 0. Attributes are updated
2911 * Failure: An NTSTATUS error code describing the error.
2913 NTSTATUS WINAPI NtSetEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length )
2915 FIXME("(%p,%p,%p,%d) stub\n", hFile, iosb, buffer, length);
2916 return STATUS_ACCESS_DENIED;
2920 /******************************************************************
2921 * NtFlushBuffersFile (NTDLL.@)
2923 * Flush any buffered data on an open file handle.
2925 * PARAMS
2926 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2927 * IoStatusBlock [O] Receives information about the operation on return
2929 * RETURNS
2930 * Success: 0. IoStatusBlock is updated.
2931 * Failure: An NTSTATUS error code describing the error.
2933 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
2935 NTSTATUS ret;
2936 HANDLE hEvent = NULL;
2937 enum server_fd_type type;
2938 int fd, needs_close;
2940 ret = server_get_unix_fd( hFile, FILE_WRITE_DATA, &fd, &needs_close, &type, NULL );
2942 if (!ret && type == FD_TYPE_SERIAL)
2944 ret = COMM_FlushBuffersFile( fd );
2946 else
2948 SERVER_START_REQ( flush_file )
2950 req->handle = wine_server_obj_handle( hFile );
2951 ret = wine_server_call( req );
2952 hEvent = wine_server_ptr_handle( reply->event );
2954 SERVER_END_REQ;
2955 if (!ret && hEvent)
2957 ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
2958 NtClose( hEvent );
2962 if (needs_close) close( fd );
2963 return ret;
2966 /******************************************************************
2967 * NtLockFile (NTDLL.@)
2971 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
2972 PIO_APC_ROUTINE apc, void* apc_user,
2973 PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
2974 PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
2975 BOOLEAN exclusive )
2977 NTSTATUS ret;
2978 HANDLE handle;
2979 BOOLEAN async;
2980 static BOOLEAN warn = TRUE;
2982 if (apc || io_status || key)
2984 FIXME("Unimplemented yet parameter\n");
2985 return STATUS_NOT_IMPLEMENTED;
2988 if (apc_user && warn)
2990 FIXME("I/O completion on lock not implemented yet\n");
2991 warn = FALSE;
2994 for (;;)
2996 SERVER_START_REQ( lock_file )
2998 req->handle = wine_server_obj_handle( hFile );
2999 req->offset = offset->QuadPart;
3000 req->count = count->QuadPart;
3001 req->shared = !exclusive;
3002 req->wait = !dont_wait;
3003 ret = wine_server_call( req );
3004 handle = wine_server_ptr_handle( reply->handle );
3005 async = reply->overlapped;
3007 SERVER_END_REQ;
3008 if (ret != STATUS_PENDING)
3010 if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
3011 return ret;
3014 if (async)
3016 FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
3017 if (handle) NtClose( handle );
3018 return STATUS_PENDING;
3020 if (handle)
3022 NtWaitForSingleObject( handle, FALSE, NULL );
3023 NtClose( handle );
3025 else
3027 LARGE_INTEGER time;
3029 /* Unix lock conflict, sleep a bit and retry */
3030 time.QuadPart = 100 * (ULONGLONG)10000;
3031 time.QuadPart = -time.QuadPart;
3032 NtDelayExecution( FALSE, &time );
3038 /******************************************************************
3039 * NtUnlockFile (NTDLL.@)
3043 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
3044 PLARGE_INTEGER offset, PLARGE_INTEGER count,
3045 PULONG key )
3047 NTSTATUS status;
3049 TRACE( "%p %x%08x %x%08x\n",
3050 hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
3052 if (io_status || key)
3054 FIXME("Unimplemented yet parameter\n");
3055 return STATUS_NOT_IMPLEMENTED;
3058 SERVER_START_REQ( unlock_file )
3060 req->handle = wine_server_obj_handle( hFile );
3061 req->offset = offset->QuadPart;
3062 req->count = count->QuadPart;
3063 status = wine_server_call( req );
3065 SERVER_END_REQ;
3066 return status;
3069 /******************************************************************
3070 * NtCreateNamedPipeFile (NTDLL.@)
3074 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
3075 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
3076 ULONG sharing, ULONG dispo, ULONG options,
3077 ULONG pipe_type, ULONG read_mode,
3078 ULONG completion_mode, ULONG max_inst,
3079 ULONG inbound_quota, ULONG outbound_quota,
3080 PLARGE_INTEGER timeout)
3082 struct security_descriptor *sd = NULL;
3083 struct object_attributes objattr;
3084 NTSTATUS status;
3086 TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n",
3087 handle, access, debugstr_w(attr->ObjectName->Buffer), iosb, sharing, dispo,
3088 options, pipe_type, read_mode, completion_mode, max_inst, inbound_quota,
3089 outbound_quota, timeout);
3091 /* assume we only get relative timeout */
3092 if (timeout->QuadPart > 0)
3093 FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
3095 objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
3096 objattr.sd_len = 0;
3097 objattr.name_len = attr->ObjectName->Length;
3099 status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
3100 if (status != STATUS_SUCCESS) return status;
3102 SERVER_START_REQ( create_named_pipe )
3104 req->access = access;
3105 req->attributes = attr->Attributes;
3106 req->options = options;
3107 req->sharing = sharing;
3108 req->flags =
3109 (pipe_type ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0) |
3110 (read_mode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0) |
3111 (completion_mode ? NAMED_PIPE_NONBLOCKING_MODE : 0);
3112 req->maxinstances = max_inst;
3113 req->outsize = outbound_quota;
3114 req->insize = inbound_quota;
3115 req->timeout = timeout->QuadPart;
3116 wine_server_add_data( req, &objattr, sizeof(objattr) );
3117 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
3118 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
3119 status = wine_server_call( req );
3120 if (!status) *handle = wine_server_ptr_handle( reply->handle );
3122 SERVER_END_REQ;
3124 NTDLL_free_struct_sd( sd );
3125 return status;
3128 /******************************************************************
3129 * NtDeleteFile (NTDLL.@)
3133 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
3135 NTSTATUS status;
3136 HANDLE hFile;
3137 IO_STATUS_BLOCK io;
3139 TRACE("%p\n", ObjectAttributes);
3140 status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE | DELETE,
3141 ObjectAttributes, &io, NULL, 0,
3142 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
3143 FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
3144 if (status == STATUS_SUCCESS) status = NtClose(hFile);
3145 return status;
3148 /******************************************************************
3149 * NtCancelIoFileEx (NTDLL.@)
3153 NTSTATUS WINAPI NtCancelIoFileEx( HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status )
3155 LARGE_INTEGER timeout;
3157 TRACE("%p %p %p\n", hFile, iosb, io_status );
3159 SERVER_START_REQ( cancel_async )
3161 req->handle = wine_server_obj_handle( hFile );
3162 req->iosb = wine_server_client_ptr( iosb );
3163 req->only_thread = FALSE;
3164 io_status->u.Status = wine_server_call( req );
3166 SERVER_END_REQ;
3167 if (io_status->u.Status)
3168 return io_status->u.Status;
3170 /* Let some APC be run, so that we can run the remaining APCs on hFile
3171 * either the cancelation of the pending one, but also the execution
3172 * of the queued APC, but not yet run. This is needed to ensure proper
3173 * clean-up of allocated data.
3175 timeout.QuadPart = 0;
3176 NtDelayExecution( TRUE, &timeout );
3177 return io_status->u.Status;
3180 /******************************************************************
3181 * NtCancelIoFile (NTDLL.@)
3185 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
3187 LARGE_INTEGER timeout;
3189 TRACE("%p %p\n", hFile, io_status );
3191 SERVER_START_REQ( cancel_async )
3193 req->handle = wine_server_obj_handle( hFile );
3194 req->iosb = 0;
3195 req->only_thread = TRUE;
3196 io_status->u.Status = wine_server_call( req );
3198 SERVER_END_REQ;
3199 if (io_status->u.Status)
3200 return io_status->u.Status;
3202 /* Let some APC be run, so that we can run the remaining APCs on hFile
3203 * either the cancelation of the pending one, but also the execution
3204 * of the queued APC, but not yet run. This is needed to ensure proper
3205 * clean-up of allocated data.
3207 timeout.QuadPart = 0;
3208 NtDelayExecution( TRUE, &timeout );
3209 return io_status->u.Status;
3212 /******************************************************************************
3213 * NtCreateMailslotFile [NTDLL.@]
3214 * ZwCreateMailslotFile [NTDLL.@]
3216 * PARAMS
3217 * pHandle [O] pointer to receive the handle created
3218 * DesiredAccess [I] access mode (read, write, etc)
3219 * ObjectAttributes [I] fully qualified NT path of the mailslot
3220 * IoStatusBlock [O] receives completion status and other info
3221 * CreateOptions [I]
3222 * MailslotQuota [I]
3223 * MaxMessageSize [I]
3224 * TimeOut [I]
3226 * RETURNS
3227 * An NT status code
3229 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
3230 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
3231 ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
3232 PLARGE_INTEGER TimeOut)
3234 LARGE_INTEGER timeout;
3235 NTSTATUS ret;
3237 TRACE("%p %08x %p %p %08x %08x %08x %p\n",
3238 pHandle, DesiredAccess, attr, IoStatusBlock,
3239 CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
3241 if (!pHandle) return STATUS_ACCESS_VIOLATION;
3242 if (!attr) return STATUS_INVALID_PARAMETER;
3243 if (!attr->ObjectName) return STATUS_OBJECT_PATH_SYNTAX_BAD;
3246 * For a NULL TimeOut pointer set the default timeout value
3248 if (!TimeOut)
3249 timeout.QuadPart = -1;
3250 else
3251 timeout.QuadPart = TimeOut->QuadPart;
3253 SERVER_START_REQ( create_mailslot )
3255 req->access = DesiredAccess;
3256 req->attributes = attr->Attributes;
3257 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
3258 req->max_msgsize = MaxMessageSize;
3259 req->read_timeout = timeout.QuadPart;
3260 wine_server_add_data( req, attr->ObjectName->Buffer,
3261 attr->ObjectName->Length );
3262 ret = wine_server_call( req );
3263 if( ret == STATUS_SUCCESS )
3264 *pHandle = wine_server_ptr_handle( reply->handle );
3266 SERVER_END_REQ;
3268 return ret;