ntdll: Make sure we don't try to attach the main exe a second time.
[wine/zf.git] / dlls / ntdll / file.c
bloba9770290e0cdccf17a5fdb033244aa4b98422013
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 MAJOR_IN_MKDEV
61 # include <sys/mkdev.h>
62 #elif defined(MAJOR_IN_SYSMACROS)
63 # include <sys/sysmacros.h>
64 #endif
65 #ifdef HAVE_UTIME_H
66 # include <utime.h>
67 #endif
68 #ifdef HAVE_SYS_VFS_H
69 /* Work around a conflict with Solaris' system list defined in sys/list.h. */
70 #define list SYSLIST
71 #define list_next SYSLIST_NEXT
72 #define list_prev SYSLIST_PREV
73 #define list_head SYSLIST_HEAD
74 #define list_tail SYSLIST_TAIL
75 #define list_move_tail SYSLIST_MOVE_TAIL
76 #define list_remove SYSLIST_REMOVE
77 # include <sys/vfs.h>
78 #undef list
79 #undef list_next
80 #undef list_prev
81 #undef list_head
82 #undef list_tail
83 #undef list_move_tail
84 #undef list_remove
85 #endif
86 #ifdef HAVE_SYS_MOUNT_H
87 # include <sys/mount.h>
88 #endif
89 #ifdef HAVE_SYS_STATFS_H
90 # include <sys/statfs.h>
91 #endif
92 #ifdef HAVE_TERMIOS_H
93 #include <termios.h>
94 #endif
95 #ifdef HAVE_VALGRIND_MEMCHECK_H
96 # include <valgrind/memcheck.h>
97 #endif
99 #include "ntstatus.h"
100 #define WIN32_NO_STATUS
101 #define NONAMELESSUNION
102 #include "wine/debug.h"
103 #include "wine/server.h"
104 #include "ntdll_misc.h"
106 #include "winternl.h"
107 #include "winioctl.h"
108 #include "ddk/ntddk.h"
109 #include "ddk/ntddser.h"
110 #define WINE_MOUNTMGR_EXTENSIONS
111 #include "ddk/mountmgr.h"
113 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
114 WINE_DECLARE_DEBUG_CHANNEL(winediag);
116 mode_t FILE_umask = 0;
118 #define SECSPERDAY 86400
119 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
121 #define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1)
122 #define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
124 /* fetch the attributes of a file */
125 static inline ULONG get_file_attributes( const struct stat *st )
127 ULONG attr;
129 if (S_ISDIR(st->st_mode))
130 attr = FILE_ATTRIBUTE_DIRECTORY;
131 else
132 attr = FILE_ATTRIBUTE_ARCHIVE;
133 if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
134 attr |= FILE_ATTRIBUTE_READONLY;
135 return attr;
138 static BOOL fd_is_mount_point( int fd, const struct stat *st )
140 struct stat parent;
141 return S_ISDIR( st->st_mode ) && !fstatat( fd, "..", &parent, 0 )
142 && (parent.st_dev != st->st_dev || parent.st_ino == st->st_ino);
145 /* get the stat info and file attributes for a file (by file descriptor) */
146 int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULONG *attr )
148 int ret;
150 *attr = 0;
151 ret = fstat( fd, st );
152 if (ret == -1) return ret;
153 *attr |= get_file_attributes( st );
154 /* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */
155 if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, st ))
156 *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
157 return ret;
160 /* get the stat info and file attributes for a file (by name) */
161 int get_file_info( const char *path, struct stat *st, ULONG *attr )
163 char *parent_path;
164 int ret;
166 *attr = 0;
167 ret = lstat( path, st );
168 if (ret == -1) return ret;
169 if (S_ISLNK( st->st_mode ))
171 ret = stat( path, st );
172 if (ret == -1) return ret;
173 /* is a symbolic link and a directory, consider these "reparse points" */
174 if (S_ISDIR( st->st_mode )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
176 else if (S_ISDIR( st->st_mode ) && (parent_path = RtlAllocateHeap( GetProcessHeap(), 0, strlen(path) + 4 )))
178 struct stat parent_st;
180 /* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */
181 strcpy( parent_path, path );
182 strcat( parent_path, "/.." );
183 if (!stat( parent_path, &parent_st )
184 && (st->st_dev != parent_st.st_dev || st->st_ino == parent_st.st_ino))
185 *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
187 RtlFreeHeap( GetProcessHeap(), 0, parent_path );
189 *attr |= get_file_attributes( st );
190 return ret;
193 /**************************************************************************
194 * FILE_CreateFile (internal)
195 * Open a file.
197 * Parameter set fully identical with NtCreateFile
199 static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
200 PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
201 ULONG attributes, ULONG sharing, ULONG disposition,
202 ULONG options, PVOID ea_buffer, ULONG ea_length )
204 ANSI_STRING unix_name;
205 BOOL created = FALSE;
207 TRACE("handle=%p access=%08x name=%s objattr=%08x root=%p sec=%p io=%p alloc_size=%p "
208 "attr=%08x sharing=%08x disp=%d options=%08x ea=%p.0x%08x\n",
209 handle, access, debugstr_us(attr->ObjectName), attr->Attributes,
210 attr->RootDirectory, attr->SecurityDescriptor, io, alloc_size,
211 attributes, sharing, disposition, options, ea_buffer, ea_length );
213 if (!attr || !attr->ObjectName) return STATUS_INVALID_PARAMETER;
215 if (alloc_size) FIXME( "alloc_size not supported\n" );
217 if (options & FILE_OPEN_BY_FILE_ID)
218 io->u.Status = file_id_to_unix_file_name( attr, &unix_name );
219 else
220 io->u.Status = nt_to_unix_file_name_attr( attr, &unix_name, disposition );
222 if (io->u.Status == STATUS_BAD_DEVICE_TYPE)
224 SERVER_START_REQ( open_file_object )
226 req->access = access;
227 req->attributes = attr->Attributes;
228 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
229 req->sharing = sharing;
230 req->options = options;
231 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
232 io->u.Status = wine_server_call( req );
233 *handle = wine_server_ptr_handle( reply->handle );
235 SERVER_END_REQ;
236 if (io->u.Status == STATUS_SUCCESS) io->Information = FILE_OPENED;
237 return io->u.Status;
240 if (io->u.Status == STATUS_NO_SUCH_FILE &&
241 disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
243 created = TRUE;
244 io->u.Status = STATUS_SUCCESS;
247 if (io->u.Status == STATUS_SUCCESS)
249 static UNICODE_STRING empty_string;
250 OBJECT_ATTRIBUTES unix_attr = *attr;
251 data_size_t len;
252 struct object_attributes *objattr;
254 unix_attr.ObjectName = &empty_string; /* we send the unix name instead */
255 if ((io->u.Status = alloc_object_attributes( &unix_attr, &objattr, &len )))
257 RtlFreeAnsiString( &unix_name );
258 return io->u.Status;
261 SERVER_START_REQ( create_file )
263 req->access = access;
264 req->sharing = sharing;
265 req->create = disposition;
266 req->options = options;
267 req->attrs = attributes;
268 wine_server_add_data( req, objattr, len );
269 wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
270 io->u.Status = wine_server_call( req );
271 *handle = wine_server_ptr_handle( reply->handle );
273 SERVER_END_REQ;
274 RtlFreeHeap( GetProcessHeap(), 0, objattr );
275 RtlFreeAnsiString( &unix_name );
277 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
279 if (io->u.Status == STATUS_SUCCESS)
281 if (created) io->Information = FILE_CREATED;
282 else switch(disposition)
284 case FILE_SUPERSEDE:
285 io->Information = FILE_SUPERSEDED;
286 break;
287 case FILE_CREATE:
288 io->Information = FILE_CREATED;
289 break;
290 case FILE_OPEN:
291 case FILE_OPEN_IF:
292 io->Information = FILE_OPENED;
293 break;
294 case FILE_OVERWRITE:
295 case FILE_OVERWRITE_IF:
296 io->Information = FILE_OVERWRITTEN;
297 break;
300 else if (io->u.Status == STATUS_TOO_MANY_OPENED_FILES)
302 static int once;
303 if (!once++) ERR_(winediag)( "Too many open files, ulimit -n probably needs to be increased\n" );
306 return io->u.Status;
309 /**************************************************************************
310 * NtOpenFile [NTDLL.@]
311 * ZwOpenFile [NTDLL.@]
313 * Open a file.
315 * PARAMS
316 * handle [O] Variable that receives the file handle on return
317 * access [I] Access desired by the caller to the file
318 * attr [I] Structure describing the file to be opened
319 * io [O] Receives details about the result of the operation
320 * sharing [I] Type of shared access the caller requires
321 * options [I] Options for the file open
323 * RETURNS
324 * Success: 0. FileHandle and IoStatusBlock are updated.
325 * Failure: An NTSTATUS error code describing the error.
327 NTSTATUS WINAPI NtOpenFile( PHANDLE handle, ACCESS_MASK access,
328 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK io,
329 ULONG sharing, ULONG options )
331 return FILE_CreateFile( handle, access, attr, io, NULL, 0,
332 sharing, FILE_OPEN, options, NULL, 0 );
335 /**************************************************************************
336 * NtCreateFile [NTDLL.@]
337 * ZwCreateFile [NTDLL.@]
339 * Either create a new file or directory, or open an existing file, device,
340 * directory or volume.
342 * PARAMS
343 * handle [O] Points to a variable which receives the file handle on return
344 * access [I] Desired access to the file
345 * attr [I] Structure describing the file
346 * io [O] Receives information about the operation on return
347 * alloc_size [I] Initial size of the file in bytes
348 * attributes [I] Attributes to create the file with
349 * sharing [I] Type of shared access the caller would like to the file
350 * disposition [I] Specifies what to do, depending on whether the file already exists
351 * options [I] Options for creating a new file
352 * ea_buffer [I] Pointer to an extended attributes buffer
353 * ea_length [I] Length of ea_buffer
355 * RETURNS
356 * Success: 0. handle and io are updated.
357 * Failure: An NTSTATUS error code describing the error.
359 NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
360 PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
361 ULONG attributes, ULONG sharing, ULONG disposition,
362 ULONG options, PVOID ea_buffer, ULONG ea_length )
364 return FILE_CreateFile( handle, access, attr, io, alloc_size, attributes,
365 sharing, disposition, options, ea_buffer, ea_length );
368 /***********************************************************************
369 * Asynchronous file I/O *
372 typedef NTSTATUS async_callback_t( void *user, IO_STATUS_BLOCK *io, NTSTATUS status );
374 struct async_fileio
376 async_callback_t *callback; /* must be the first field */
377 struct async_fileio *next;
378 HANDLE handle;
381 struct async_fileio_read
383 struct async_fileio io;
384 char* buffer;
385 unsigned int already;
386 unsigned int count;
387 BOOL avail_mode;
390 struct async_fileio_write
392 struct async_fileio io;
393 const char *buffer;
394 unsigned int already;
395 unsigned int count;
398 struct async_irp
400 struct async_fileio io;
401 void *buffer; /* buffer for output */
402 ULONG size; /* size of buffer */
405 static struct async_fileio *fileio_freelist;
407 static void release_fileio( struct async_fileio *io )
409 for (;;)
411 struct async_fileio *next = fileio_freelist;
412 io->next = next;
413 if (interlocked_cmpxchg_ptr( (void **)&fileio_freelist, io, next ) == next) return;
417 static struct async_fileio *alloc_fileio( DWORD size, async_callback_t callback, HANDLE handle )
419 /* first free remaining previous fileinfos */
421 struct async_fileio *io = interlocked_xchg_ptr( (void **)&fileio_freelist, NULL );
423 while (io)
425 struct async_fileio *next = io->next;
426 RtlFreeHeap( GetProcessHeap(), 0, io );
427 io = next;
430 if ((io = RtlAllocateHeap( GetProcessHeap(), 0, size )))
432 io->callback = callback;
433 io->handle = handle;
435 return io;
438 static async_data_t server_async( HANDLE handle, struct async_fileio *user, HANDLE event,
439 PIO_APC_ROUTINE apc, void *apc_context, IO_STATUS_BLOCK *io )
441 async_data_t async;
442 async.handle = wine_server_obj_handle( handle );
443 async.user = wine_server_client_ptr( user );
444 async.iosb = wine_server_client_ptr( io );
445 async.event = wine_server_obj_handle( event );
446 async.apc = wine_server_client_ptr( apc );
447 async.apc_context = wine_server_client_ptr( apc_context );
448 return async;
451 static NTSTATUS wait_async( HANDLE handle, BOOL alertable, IO_STATUS_BLOCK *io )
453 if (NtWaitForSingleObject( handle, alertable, NULL )) return STATUS_PENDING;
454 return io->u.Status;
457 /* callback for irp async I/O completion */
458 static NTSTATUS irp_completion( void *user, IO_STATUS_BLOCK *io, NTSTATUS status )
460 struct async_irp *async = user;
461 ULONG information = 0;
463 if (status == STATUS_ALERTED)
465 SERVER_START_REQ( get_async_result )
467 req->user_arg = wine_server_client_ptr( async );
468 wine_server_set_reply( req, async->buffer, async->size );
469 status = virtual_locked_server_call( req );
470 information = reply->size;
472 SERVER_END_REQ;
474 if (status != STATUS_PENDING)
476 io->u.Status = status;
477 io->Information = information;
478 release_fileio( &async->io );
480 return status;
483 /***********************************************************************
484 * FILE_GetNtStatus(void)
486 * Retrieve the Nt Status code from errno.
487 * Try to be consistent with FILE_SetDosError().
489 NTSTATUS FILE_GetNtStatus(void)
491 int err = errno;
493 TRACE( "errno = %d\n", errno );
494 switch (err)
496 case EAGAIN: return STATUS_SHARING_VIOLATION;
497 case EBADF: return STATUS_INVALID_HANDLE;
498 case EBUSY: return STATUS_DEVICE_BUSY;
499 case ENOSPC: return STATUS_DISK_FULL;
500 case EPERM:
501 case EROFS:
502 case EACCES: return STATUS_ACCESS_DENIED;
503 case ENOTDIR: return STATUS_OBJECT_PATH_NOT_FOUND;
504 case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND;
505 case EISDIR: return STATUS_FILE_IS_A_DIRECTORY;
506 case EMFILE:
507 case ENFILE: return STATUS_TOO_MANY_OPENED_FILES;
508 case EINVAL: return STATUS_INVALID_PARAMETER;
509 case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
510 case EPIPE: return STATUS_PIPE_DISCONNECTED;
511 case EIO: return STATUS_DEVICE_NOT_READY;
512 #ifdef ENOMEDIUM
513 case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE;
514 #endif
515 case ENXIO: return STATUS_NO_SUCH_DEVICE;
516 case ENOTTY:
517 case EOPNOTSUPP:return STATUS_NOT_SUPPORTED;
518 case ECONNRESET:return STATUS_PIPE_DISCONNECTED;
519 case EFAULT: return STATUS_ACCESS_VIOLATION;
520 case ESPIPE: return STATUS_ILLEGAL_FUNCTION;
521 case ELOOP: return STATUS_REPARSE_POINT_NOT_RESOLVED;
522 #ifdef ETIME /* Missing on FreeBSD */
523 case ETIME: return STATUS_IO_TIMEOUT;
524 #endif
525 case ENOEXEC: /* ?? */
526 case EEXIST: /* ?? */
527 default:
528 FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
529 return STATUS_UNSUCCESSFUL;
533 /***********************************************************************
534 * FILE_AsyncReadService (INTERNAL)
536 static NTSTATUS FILE_AsyncReadService( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
538 struct async_fileio_read *fileio = user;
539 int fd, needs_close, result;
541 switch (status)
543 case STATUS_ALERTED: /* got some new data */
544 /* check to see if the data is ready (non-blocking) */
545 if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
546 &needs_close, NULL, NULL )))
547 break;
549 result = virtual_locked_read(fd, &fileio->buffer[fileio->already], fileio->count-fileio->already);
550 if (needs_close) close( fd );
552 if (result < 0)
554 if (errno == EAGAIN || errno == EINTR)
555 status = STATUS_PENDING;
556 else /* check to see if the transfer is complete */
557 status = FILE_GetNtStatus();
559 else if (result == 0)
561 status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN;
563 else
565 fileio->already += result;
566 if (fileio->already >= fileio->count || fileio->avail_mode)
567 status = STATUS_SUCCESS;
568 else
569 status = STATUS_PENDING;
571 break;
573 case STATUS_TIMEOUT:
574 case STATUS_IO_TIMEOUT:
575 if (fileio->already) status = STATUS_SUCCESS;
576 break;
578 if (status != STATUS_PENDING)
580 iosb->u.Status = status;
581 iosb->Information = fileio->already;
582 release_fileio( &fileio->io );
584 return status;
587 /* do a read call through the server */
588 static NTSTATUS server_read_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_context,
589 IO_STATUS_BLOCK *io, void *buffer, ULONG size,
590 LARGE_INTEGER *offset, ULONG *key )
592 struct async_irp *async;
593 NTSTATUS status;
594 HANDLE wait_handle;
595 ULONG options;
597 if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), irp_completion, handle )))
598 return STATUS_NO_MEMORY;
600 async->buffer = buffer;
601 async->size = size;
603 SERVER_START_REQ( read )
605 req->async = server_async( handle, &async->io, event, apc, apc_context, io );
606 req->pos = offset ? offset->QuadPart : 0;
607 wine_server_set_reply( req, buffer, size );
608 status = virtual_locked_server_call( req );
609 wait_handle = wine_server_ptr_handle( reply->wait );
610 options = reply->options;
611 if (wait_handle && status != STATUS_PENDING)
613 io->u.Status = status;
614 io->Information = wine_server_reply_size( reply );
617 SERVER_END_REQ;
619 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
621 if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), io );
622 return status;
625 /* do a write call through the server */
626 static NTSTATUS server_write_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_context,
627 IO_STATUS_BLOCK *io, const void *buffer, ULONG size,
628 LARGE_INTEGER *offset, ULONG *key )
630 struct async_irp *async;
631 NTSTATUS status;
632 HANDLE wait_handle;
633 ULONG options;
635 if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), irp_completion, handle )))
636 return STATUS_NO_MEMORY;
638 async->buffer = NULL;
639 async->size = 0;
641 SERVER_START_REQ( write )
643 req->async = server_async( handle, &async->io, event, apc, apc_context, io );
644 req->pos = offset ? offset->QuadPart : 0;
645 wine_server_add_data( req, buffer, size );
646 status = wine_server_call( req );
647 wait_handle = wine_server_ptr_handle( reply->wait );
648 options = reply->options;
649 if (wait_handle && status != STATUS_PENDING)
651 io->u.Status = status;
652 io->Information = reply->size;
655 SERVER_END_REQ;
657 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
659 if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), io );
660 return status;
663 struct io_timeouts
665 int interval; /* max interval between two bytes */
666 int total; /* total timeout for the whole operation */
667 int end_time; /* absolute time of end of operation */
670 /* retrieve the I/O timeouts to use for a given handle */
671 static NTSTATUS get_io_timeouts( HANDLE handle, enum server_fd_type type, ULONG count, BOOL is_read,
672 struct io_timeouts *timeouts )
674 NTSTATUS status = STATUS_SUCCESS;
676 timeouts->interval = timeouts->total = -1;
678 switch(type)
680 case FD_TYPE_SERIAL:
682 /* GetCommTimeouts */
683 SERIAL_TIMEOUTS st;
684 IO_STATUS_BLOCK io;
686 status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
687 IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
688 if (status) break;
690 if (is_read)
692 if (st.ReadIntervalTimeout)
693 timeouts->interval = st.ReadIntervalTimeout;
695 if (st.ReadTotalTimeoutMultiplier || st.ReadTotalTimeoutConstant)
697 timeouts->total = st.ReadTotalTimeoutConstant;
698 if (st.ReadTotalTimeoutMultiplier != MAXDWORD)
699 timeouts->total += count * st.ReadTotalTimeoutMultiplier;
701 else if (st.ReadIntervalTimeout == MAXDWORD)
702 timeouts->interval = timeouts->total = 0;
704 else /* write */
706 if (st.WriteTotalTimeoutMultiplier || st.WriteTotalTimeoutConstant)
708 timeouts->total = st.WriteTotalTimeoutConstant;
709 if (st.WriteTotalTimeoutMultiplier != MAXDWORD)
710 timeouts->total += count * st.WriteTotalTimeoutMultiplier;
714 break;
715 case FD_TYPE_MAILSLOT:
716 if (is_read)
718 timeouts->interval = 0; /* return as soon as we got something */
719 SERVER_START_REQ( set_mailslot_info )
721 req->handle = wine_server_obj_handle( handle );
722 req->flags = 0;
723 if (!(status = wine_server_call( req )) &&
724 reply->read_timeout != TIMEOUT_INFINITE)
725 timeouts->total = reply->read_timeout / -10000;
727 SERVER_END_REQ;
729 break;
730 case FD_TYPE_SOCKET:
731 case FD_TYPE_CHAR:
732 if (is_read) timeouts->interval = 0; /* return as soon as we got something */
733 break;
734 default:
735 break;
737 if (timeouts->total != -1) timeouts->end_time = NtGetTickCount() + timeouts->total;
738 return STATUS_SUCCESS;
742 /* retrieve the timeout for the next wait, in milliseconds */
743 static inline int get_next_io_timeout( const struct io_timeouts *timeouts, ULONG already )
745 int ret = -1;
747 if (timeouts->total != -1)
749 ret = timeouts->end_time - NtGetTickCount();
750 if (ret < 0) ret = 0;
752 if (already && timeouts->interval != -1)
754 if (ret == -1 || ret > timeouts->interval) ret = timeouts->interval;
756 return ret;
760 /* retrieve the avail_mode flag for async reads */
761 static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL *avail_mode )
763 NTSTATUS status = STATUS_SUCCESS;
765 switch(type)
767 case FD_TYPE_SERIAL:
769 /* GetCommTimeouts */
770 SERIAL_TIMEOUTS st;
771 IO_STATUS_BLOCK io;
773 status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
774 IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
775 if (status) break;
776 *avail_mode = (!st.ReadTotalTimeoutMultiplier &&
777 !st.ReadTotalTimeoutConstant &&
778 st.ReadIntervalTimeout == MAXDWORD);
780 break;
781 case FD_TYPE_MAILSLOT:
782 case FD_TYPE_SOCKET:
783 case FD_TYPE_CHAR:
784 *avail_mode = TRUE;
785 break;
786 default:
787 *avail_mode = FALSE;
788 break;
790 return status;
793 /* register an async I/O for a file read; helper for NtReadFile */
794 static NTSTATUS register_async_file_read( HANDLE handle, HANDLE event,
795 PIO_APC_ROUTINE apc, void *apc_user,
796 IO_STATUS_BLOCK *iosb, void *buffer,
797 ULONG already, ULONG length, BOOL avail_mode )
799 struct async_fileio_read *fileio;
800 NTSTATUS status;
802 if (!(fileio = (struct async_fileio_read *)alloc_fileio( sizeof(*fileio), FILE_AsyncReadService, handle )))
803 return STATUS_NO_MEMORY;
805 fileio->already = already;
806 fileio->count = length;
807 fileio->buffer = buffer;
808 fileio->avail_mode = avail_mode;
810 SERVER_START_REQ( register_async )
812 req->type = ASYNC_TYPE_READ;
813 req->count = length;
814 req->async = server_async( handle, &fileio->io, event, apc, apc_user, iosb );
815 status = wine_server_call( req );
817 SERVER_END_REQ;
819 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
820 return status;
824 /******************************************************************************
825 * NtReadFile [NTDLL.@]
826 * ZwReadFile [NTDLL.@]
828 * Read from an open file handle.
830 * PARAMS
831 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
832 * Event [I] Event to signal upon completion (or NULL)
833 * ApcRoutine [I] Callback to call upon completion (or NULL)
834 * ApcContext [I] Context for ApcRoutine (or NULL)
835 * IoStatusBlock [O] Receives information about the operation on return
836 * Buffer [O] Destination for the data read
837 * Length [I] Size of Buffer
838 * ByteOffset [O] Destination for the new file pointer position (or NULL)
839 * Key [O] Function unknown (may be NULL)
841 * RETURNS
842 * Success: 0. IoStatusBlock is updated, and the Information member contains
843 * The number of bytes read.
844 * Failure: An NTSTATUS error code describing the error.
846 NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
847 PIO_APC_ROUTINE apc, void* apc_user,
848 PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
849 PLARGE_INTEGER offset, PULONG key)
851 int result, unix_handle, needs_close;
852 unsigned int options;
853 struct io_timeouts timeouts;
854 NTSTATUS status, ret_status;
855 ULONG total = 0;
856 enum server_fd_type type;
857 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
858 BOOL send_completion = FALSE, async_read, timeout_init_done = FALSE;
860 TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)\n",
861 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
863 if (!io_status) return STATUS_ACCESS_VIOLATION;
865 status = server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
866 &needs_close, &type, &options );
867 if (status && status != STATUS_BAD_DEVICE_TYPE) return status;
869 if (!virtual_check_buffer_for_write( buffer, length )) return STATUS_ACCESS_VIOLATION;
871 if (status == STATUS_BAD_DEVICE_TYPE)
872 return server_read_file( hFile, hEvent, apc, apc_user, io_status, buffer, length, offset, key );
874 async_read = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
876 if (type == FD_TYPE_FILE)
878 if (async_read && (!offset || offset->QuadPart < 0))
880 status = STATUS_INVALID_PARAMETER;
881 goto done;
884 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
886 /* async I/O doesn't make sense on regular files */
887 while ((result = virtual_locked_pread( unix_handle, buffer, length, offset->QuadPart )) == -1)
889 if (errno != EINTR)
891 status = FILE_GetNtStatus();
892 goto done;
895 if (!async_read)
896 /* update file pointer position */
897 lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
899 total = result;
900 status = (total || !length) ? STATUS_SUCCESS : STATUS_END_OF_FILE;
901 goto done;
904 else if (type == FD_TYPE_SERIAL || type == FD_TYPE_DEVICE)
906 if (async_read && (!offset || offset->QuadPart < 0))
908 status = STATUS_INVALID_PARAMETER;
909 goto done;
913 if (type == FD_TYPE_SERIAL && async_read && length)
915 /* an asynchronous serial port read with a read interval timeout needs to
916 skip the synchronous read to make sure that the server starts the read
917 interval timer after the first read */
918 if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts ))) goto err;
919 if (timeouts.interval)
921 status = register_async_file_read( hFile, hEvent, apc, apc_user, io_status,
922 buffer, total, length, FALSE );
923 goto err;
927 for (;;)
929 if ((result = virtual_locked_read( unix_handle, (char *)buffer + total, length - total )) >= 0)
931 total += result;
932 if (!result || total == length)
934 if (total)
936 status = STATUS_SUCCESS;
937 goto done;
939 switch (type)
941 case FD_TYPE_FILE:
942 case FD_TYPE_CHAR:
943 case FD_TYPE_DEVICE:
944 status = length ? STATUS_END_OF_FILE : STATUS_SUCCESS;
945 goto done;
946 case FD_TYPE_SERIAL:
947 if (!length)
949 status = STATUS_SUCCESS;
950 goto done;
952 break;
953 default:
954 status = STATUS_PIPE_BROKEN;
955 goto err;
958 else if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
960 else if (errno != EAGAIN)
962 if (errno == EINTR) continue;
963 if (!total) status = FILE_GetNtStatus();
964 goto err;
967 if (async_read)
969 BOOL avail_mode;
971 if ((status = get_io_avail_mode( hFile, type, &avail_mode )))
972 goto err;
973 if (total && avail_mode)
975 status = STATUS_SUCCESS;
976 goto done;
978 status = register_async_file_read( hFile, hEvent, apc, apc_user, io_status,
979 buffer, total, length, avail_mode );
980 goto err;
982 else /* synchronous read, wait for the fd to become ready */
984 struct pollfd pfd;
985 int ret, timeout;
987 if (!timeout_init_done)
989 timeout_init_done = TRUE;
990 if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts )))
991 goto err;
992 if (hEvent) NtResetEvent( hEvent, NULL );
994 timeout = get_next_io_timeout( &timeouts, total );
996 pfd.fd = unix_handle;
997 pfd.events = POLLIN;
999 if (!timeout || !(ret = poll( &pfd, 1, timeout )))
1001 if (total) /* return with what we got so far */
1002 status = STATUS_SUCCESS;
1003 else
1004 status = (type == FD_TYPE_MAILSLOT) ? STATUS_IO_TIMEOUT : STATUS_TIMEOUT;
1005 goto done;
1007 if (ret == -1 && errno != EINTR)
1009 status = FILE_GetNtStatus();
1010 goto done;
1012 /* will now restart the read */
1016 done:
1017 send_completion = cvalue != 0;
1019 err:
1020 if (needs_close) close( unix_handle );
1021 if (status == STATUS_SUCCESS || (status == STATUS_END_OF_FILE && !async_read))
1023 io_status->u.Status = status;
1024 io_status->Information = total;
1025 TRACE("= SUCCESS (%u)\n", total);
1026 if (hEvent) NtSetEvent( hEvent, NULL );
1027 if (apc && !status) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1028 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1030 else
1032 TRACE("= 0x%08x\n", status);
1033 if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
1036 ret_status = async_read && type == FD_TYPE_FILE && status == STATUS_SUCCESS
1037 ? STATUS_PENDING : status;
1039 if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total, ret_status == STATUS_PENDING );
1040 return ret_status;
1044 /******************************************************************************
1045 * NtReadFileScatter [NTDLL.@]
1046 * ZwReadFileScatter [NTDLL.@]
1048 NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1049 PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
1050 ULONG length, PLARGE_INTEGER offset, PULONG key )
1052 int result, unix_handle, needs_close;
1053 unsigned int options;
1054 NTSTATUS status;
1055 ULONG pos = 0, total = 0;
1056 enum server_fd_type type;
1057 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1058 BOOL send_completion = FALSE;
1060 TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
1061 file, event, apc, apc_user, io_status, segments, length, offset, key);
1063 if (!io_status) return STATUS_ACCESS_VIOLATION;
1065 status = server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
1066 &needs_close, &type, &options );
1067 if (status) return status;
1069 if ((type != FD_TYPE_FILE) ||
1070 (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
1071 !(options & FILE_NO_INTERMEDIATE_BUFFERING))
1073 status = STATUS_INVALID_PARAMETER;
1074 goto error;
1077 while (length)
1079 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
1080 result = pread( unix_handle, (char *)segments->Buffer + pos,
1081 min( length - pos, page_size - pos ), offset->QuadPart + total );
1082 else
1083 result = read( unix_handle, (char *)segments->Buffer + pos, min( length - pos, page_size - pos ) );
1085 if (result == -1)
1087 if (errno == EINTR) continue;
1088 status = FILE_GetNtStatus();
1089 break;
1091 if (!result) break;
1092 total += result;
1093 length -= result;
1094 if ((pos += result) == page_size)
1096 pos = 0;
1097 segments++;
1101 if (total == 0) status = STATUS_END_OF_FILE;
1103 send_completion = cvalue != 0;
1105 if (needs_close) close( unix_handle );
1107 io_status->u.Status = status;
1108 io_status->Information = total;
1109 TRACE("= 0x%08x (%u)\n", status, total);
1110 if (event) NtSetEvent( event, NULL );
1111 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1112 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1113 if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total, TRUE );
1115 return STATUS_PENDING;
1117 error:
1118 if (needs_close) close( unix_handle );
1120 TRACE("= 0x%08x\n", status);
1121 if (event) NtResetEvent( event, NULL );
1123 return status;
1127 /***********************************************************************
1128 * FILE_AsyncWriteService (INTERNAL)
1130 static NTSTATUS FILE_AsyncWriteService( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
1132 struct async_fileio_write *fileio = user;
1133 int result, fd, needs_close;
1134 enum server_fd_type type;
1136 switch (status)
1138 case STATUS_ALERTED:
1139 /* write some data (non-blocking) */
1140 if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
1141 &needs_close, &type, NULL )))
1142 break;
1144 if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_SOCKET))
1145 result = send( fd, fileio->buffer, 0, 0 );
1146 else
1147 result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already );
1149 if (needs_close) close( fd );
1151 if (result < 0)
1153 if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING;
1154 else status = FILE_GetNtStatus();
1156 else
1158 fileio->already += result;
1159 status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
1161 break;
1163 case STATUS_TIMEOUT:
1164 case STATUS_IO_TIMEOUT:
1165 if (fileio->already) status = STATUS_SUCCESS;
1166 break;
1168 if (status != STATUS_PENDING)
1170 iosb->u.Status = status;
1171 iosb->Information = fileio->already;
1172 release_fileio( &fileio->io );
1174 return status;
1177 static NTSTATUS set_pending_write( HANDLE device )
1179 NTSTATUS status;
1181 SERVER_START_REQ( set_serial_info )
1183 req->handle = wine_server_obj_handle( device );
1184 req->flags = SERIALINFO_PENDING_WRITE;
1185 status = wine_server_call( req );
1187 SERVER_END_REQ;
1188 return status;
1191 /******************************************************************************
1192 * NtWriteFile [NTDLL.@]
1193 * ZwWriteFile [NTDLL.@]
1195 * Write to an open file handle.
1197 * PARAMS
1198 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1199 * Event [I] Event to signal upon completion (or NULL)
1200 * ApcRoutine [I] Callback to call upon completion (or NULL)
1201 * ApcContext [I] Context for ApcRoutine (or NULL)
1202 * IoStatusBlock [O] Receives information about the operation on return
1203 * Buffer [I] Source for the data to write
1204 * Length [I] Size of Buffer
1205 * ByteOffset [O] Destination for the new file pointer position (or NULL)
1206 * Key [O] Function unknown (may be NULL)
1208 * RETURNS
1209 * Success: 0. IoStatusBlock is updated, and the Information member contains
1210 * The number of bytes written.
1211 * Failure: An NTSTATUS error code describing the error.
1213 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
1214 PIO_APC_ROUTINE apc, void* apc_user,
1215 PIO_STATUS_BLOCK io_status,
1216 const void* buffer, ULONG length,
1217 PLARGE_INTEGER offset, PULONG key)
1219 int result, unix_handle, needs_close;
1220 unsigned int options;
1221 struct io_timeouts timeouts;
1222 NTSTATUS status, ret_status;
1223 ULONG total = 0;
1224 enum server_fd_type type;
1225 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1226 BOOL send_completion = FALSE, async_write, append_write = FALSE, timeout_init_done = FALSE;
1227 LARGE_INTEGER offset_eof;
1229 TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)\n",
1230 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
1232 if (!io_status) return STATUS_ACCESS_VIOLATION;
1234 status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
1235 &needs_close, &type, &options );
1236 if (status == STATUS_ACCESS_DENIED)
1238 status = server_get_unix_fd( hFile, FILE_APPEND_DATA, &unix_handle,
1239 &needs_close, &type, &options );
1240 append_write = TRUE;
1242 if (status && status != STATUS_BAD_DEVICE_TYPE) return status;
1244 async_write = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
1246 if (!virtual_check_buffer_for_read( buffer, length ))
1248 status = STATUS_INVALID_USER_BUFFER;
1249 goto done;
1252 if (status == STATUS_BAD_DEVICE_TYPE)
1253 return server_write_file( hFile, hEvent, apc, apc_user, io_status, buffer, length, offset, key );
1255 if (type == FD_TYPE_FILE)
1257 if (async_write &&
1258 (!offset || (offset->QuadPart < 0 && offset->QuadPart != FILE_WRITE_TO_END_OF_FILE)))
1260 status = STATUS_INVALID_PARAMETER;
1261 goto done;
1264 if (append_write)
1266 offset_eof.QuadPart = FILE_WRITE_TO_END_OF_FILE;
1267 offset = &offset_eof;
1270 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
1272 off_t off = offset->QuadPart;
1274 if (offset->QuadPart == FILE_WRITE_TO_END_OF_FILE)
1276 struct stat st;
1278 if (fstat( unix_handle, &st ) == -1)
1280 status = FILE_GetNtStatus();
1281 goto done;
1283 off = st.st_size;
1285 else if (offset->QuadPart < 0)
1287 status = STATUS_INVALID_PARAMETER;
1288 goto done;
1291 /* async I/O doesn't make sense on regular files */
1292 while ((result = pwrite( unix_handle, buffer, length, off )) == -1)
1294 if (errno != EINTR)
1296 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
1297 else status = FILE_GetNtStatus();
1298 goto done;
1302 if (!async_write)
1303 /* update file pointer position */
1304 lseek( unix_handle, off + result, SEEK_SET );
1306 total = result;
1307 status = STATUS_SUCCESS;
1308 goto done;
1311 else if (type == FD_TYPE_SERIAL || type == FD_TYPE_DEVICE)
1313 if (async_write &&
1314 (!offset || (offset->QuadPart < 0 && offset->QuadPart != FILE_WRITE_TO_END_OF_FILE)))
1316 status = STATUS_INVALID_PARAMETER;
1317 goto done;
1321 for (;;)
1323 /* zero-length writes on sockets may not work with plain write(2) */
1324 if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_SOCKET))
1325 result = send( unix_handle, buffer, 0, 0 );
1326 else
1327 result = write( unix_handle, (const char *)buffer + total, length - total );
1329 if (result >= 0)
1331 total += result;
1332 if (total == length)
1334 status = STATUS_SUCCESS;
1335 goto done;
1337 if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
1339 else if (errno != EAGAIN)
1341 if (errno == EINTR) continue;
1342 if (!total)
1344 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
1345 else status = FILE_GetNtStatus();
1347 goto err;
1350 if (async_write)
1352 struct async_fileio_write *fileio;
1354 fileio = (struct async_fileio_write *)alloc_fileio( sizeof(*fileio), FILE_AsyncWriteService, hFile );
1355 if (!fileio)
1357 status = STATUS_NO_MEMORY;
1358 goto err;
1360 fileio->already = total;
1361 fileio->count = length;
1362 fileio->buffer = buffer;
1364 SERVER_START_REQ( register_async )
1366 req->type = ASYNC_TYPE_WRITE;
1367 req->count = length;
1368 req->async = server_async( hFile, &fileio->io, hEvent, apc, apc_user, io_status );
1369 status = wine_server_call( req );
1371 SERVER_END_REQ;
1373 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
1374 goto err;
1376 else /* synchronous write, wait for the fd to become ready */
1378 struct pollfd pfd;
1379 int ret, timeout;
1381 if (!timeout_init_done)
1383 timeout_init_done = TRUE;
1384 if ((status = get_io_timeouts( hFile, type, length, FALSE, &timeouts )))
1385 goto err;
1386 if (hEvent) NtResetEvent( hEvent, NULL );
1388 timeout = get_next_io_timeout( &timeouts, total );
1390 pfd.fd = unix_handle;
1391 pfd.events = POLLOUT;
1393 if (!timeout || !(ret = poll( &pfd, 1, timeout )))
1395 /* return with what we got so far */
1396 status = total ? STATUS_SUCCESS : STATUS_TIMEOUT;
1397 goto done;
1399 if (ret == -1 && errno != EINTR)
1401 status = FILE_GetNtStatus();
1402 goto done;
1404 /* will now restart the write */
1408 done:
1409 send_completion = cvalue != 0;
1411 err:
1412 if (needs_close) close( unix_handle );
1414 if (type == FD_TYPE_SERIAL && (status == STATUS_SUCCESS || status == STATUS_PENDING))
1415 set_pending_write( hFile );
1417 if (status == STATUS_SUCCESS)
1419 io_status->u.Status = status;
1420 io_status->Information = total;
1421 TRACE("= SUCCESS (%u)\n", total);
1422 if (hEvent) NtSetEvent( hEvent, NULL );
1423 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1424 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1426 else
1428 TRACE("= 0x%08x\n", status);
1429 if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
1432 ret_status = async_write && type == FD_TYPE_FILE && status == STATUS_SUCCESS ? STATUS_PENDING : status;
1433 if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total, ret_status == STATUS_PENDING );
1435 return ret_status;
1439 /******************************************************************************
1440 * NtWriteFileGather [NTDLL.@]
1441 * ZwWriteFileGather [NTDLL.@]
1443 NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1444 PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
1445 ULONG length, PLARGE_INTEGER offset, PULONG key )
1447 int result, unix_handle, needs_close;
1448 unsigned int options;
1449 NTSTATUS status;
1450 ULONG pos = 0, total = 0;
1451 enum server_fd_type type;
1452 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1453 BOOL send_completion = FALSE;
1455 TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
1456 file, event, apc, apc_user, io_status, segments, length, offset, key);
1458 if (length % page_size) return STATUS_INVALID_PARAMETER;
1459 if (!io_status) return STATUS_ACCESS_VIOLATION;
1461 status = server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
1462 &needs_close, &type, &options );
1463 if (status) return status;
1465 if ((type != FD_TYPE_FILE) ||
1466 (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
1467 !(options & FILE_NO_INTERMEDIATE_BUFFERING))
1469 status = STATUS_INVALID_PARAMETER;
1470 goto error;
1473 while (length)
1475 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
1476 result = pwrite( unix_handle, (char *)segments->Buffer + pos,
1477 page_size - pos, offset->QuadPart + total );
1478 else
1479 result = write( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
1481 if (result == -1)
1483 if (errno == EINTR) continue;
1484 if (errno == EFAULT)
1486 status = STATUS_INVALID_USER_BUFFER;
1487 goto error;
1489 status = FILE_GetNtStatus();
1490 break;
1492 if (!result)
1494 status = STATUS_DISK_FULL;
1495 break;
1497 total += result;
1498 length -= result;
1499 if ((pos += result) == page_size)
1501 pos = 0;
1502 segments++;
1506 send_completion = cvalue != 0;
1508 error:
1509 if (needs_close) close( unix_handle );
1510 if (status == STATUS_SUCCESS)
1512 io_status->u.Status = status;
1513 io_status->Information = total;
1514 TRACE("= SUCCESS (%u)\n", total);
1515 if (event) NtSetEvent( event, NULL );
1516 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1517 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1519 else
1521 TRACE("= 0x%08x\n", status);
1522 if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
1525 if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total, FALSE );
1527 return status;
1531 /* do an ioctl call through the server */
1532 static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
1533 PIO_APC_ROUTINE apc, PVOID apc_context,
1534 IO_STATUS_BLOCK *io, ULONG code,
1535 const void *in_buffer, ULONG in_size,
1536 PVOID out_buffer, ULONG out_size )
1538 struct async_irp *async;
1539 NTSTATUS status;
1540 HANDLE wait_handle;
1541 ULONG options;
1543 if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), irp_completion, handle )))
1544 return STATUS_NO_MEMORY;
1545 async->buffer = out_buffer;
1546 async->size = out_size;
1548 SERVER_START_REQ( ioctl )
1550 req->code = code;
1551 req->async = server_async( handle, &async->io, event, apc, apc_context, io );
1552 wine_server_add_data( req, in_buffer, in_size );
1553 if ((code & 3) != METHOD_BUFFERED)
1554 wine_server_add_data( req, out_buffer, out_size );
1555 wine_server_set_reply( req, out_buffer, out_size );
1556 status = virtual_locked_server_call( req );
1557 wait_handle = wine_server_ptr_handle( reply->wait );
1558 options = reply->options;
1559 if (wait_handle && status != STATUS_PENDING)
1561 io->u.Status = status;
1562 io->Information = wine_server_reply_size( reply );
1565 SERVER_END_REQ;
1567 if (status == STATUS_NOT_SUPPORTED)
1568 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
1569 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1571 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
1573 if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), io );
1574 return status;
1577 /* Tell Valgrind to ignore any holes in structs we will be passing to the
1578 * server */
1579 static void ignore_server_ioctl_struct_holes (ULONG code, const void *in_buffer,
1580 ULONG in_size)
1582 #ifdef VALGRIND_MAKE_MEM_DEFINED
1583 # define IGNORE_STRUCT_HOLE(buf, size, t, f1, f2) \
1584 do { \
1585 if (FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1) < FIELD_OFFSET(t, f2)) \
1586 if ((size) >= FIELD_OFFSET(t, f2)) \
1587 VALGRIND_MAKE_MEM_DEFINED( \
1588 (const char *)(buf) + FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1), \
1589 FIELD_OFFSET(t, f2) - FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1)); \
1590 } while (0)
1592 switch (code)
1594 case FSCTL_PIPE_WAIT:
1595 IGNORE_STRUCT_HOLE(in_buffer, in_size, FILE_PIPE_WAIT_FOR_BUFFER, TimeoutSpecified, Name);
1596 break;
1598 #endif
1602 /**************************************************************************
1603 * NtDeviceIoControlFile [NTDLL.@]
1604 * ZwDeviceIoControlFile [NTDLL.@]
1606 * Perform an I/O control operation on an open file handle.
1608 * PARAMS
1609 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1610 * event [I] Event to signal upon completion (or NULL)
1611 * apc [I] Callback to call upon completion (or NULL)
1612 * apc_context [I] Context for ApcRoutine (or NULL)
1613 * io [O] Receives information about the operation on return
1614 * code [I] Control code for the operation to perform
1615 * in_buffer [I] Source for any input data required (or NULL)
1616 * in_size [I] Size of InputBuffer
1617 * out_buffer [O] Source for any output data returned (or NULL)
1618 * out_size [I] Size of OutputBuffer
1620 * RETURNS
1621 * Success: 0. IoStatusBlock is updated.
1622 * Failure: An NTSTATUS error code describing the error.
1624 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
1625 PIO_APC_ROUTINE apc, PVOID apc_context,
1626 PIO_STATUS_BLOCK io, ULONG code,
1627 PVOID in_buffer, ULONG in_size,
1628 PVOID out_buffer, ULONG out_size)
1630 ULONG device = (code >> 16);
1631 NTSTATUS status = STATUS_NOT_SUPPORTED;
1633 TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1634 handle, event, apc, apc_context, io, code,
1635 in_buffer, in_size, out_buffer, out_size);
1637 switch(device)
1639 case FILE_DEVICE_DISK:
1640 case FILE_DEVICE_CD_ROM:
1641 case FILE_DEVICE_DVD:
1642 case FILE_DEVICE_CONTROLLER:
1643 case FILE_DEVICE_MASS_STORAGE:
1644 status = CDROM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1645 in_buffer, in_size, out_buffer, out_size);
1646 break;
1647 case FILE_DEVICE_SERIAL_PORT:
1648 status = COMM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1649 in_buffer, in_size, out_buffer, out_size);
1650 break;
1651 case FILE_DEVICE_TAPE:
1652 status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
1653 in_buffer, in_size, out_buffer, out_size);
1654 break;
1657 if (status == STATUS_NOT_SUPPORTED || status == STATUS_BAD_DEVICE_TYPE)
1658 return server_ioctl_file( handle, event, apc, apc_context, io, code,
1659 in_buffer, in_size, out_buffer, out_size );
1661 if (status != STATUS_PENDING) io->u.Status = status;
1662 return status;
1666 /**************************************************************************
1667 * NtFsControlFile [NTDLL.@]
1668 * ZwFsControlFile [NTDLL.@]
1670 * Perform a file system control operation on an open file handle.
1672 * PARAMS
1673 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1674 * event [I] Event to signal upon completion (or NULL)
1675 * apc [I] Callback to call upon completion (or NULL)
1676 * apc_context [I] Context for ApcRoutine (or NULL)
1677 * io [O] Receives information about the operation on return
1678 * code [I] Control code for the operation to perform
1679 * in_buffer [I] Source for any input data required (or NULL)
1680 * in_size [I] Size of InputBuffer
1681 * out_buffer [O] Source for any output data returned (or NULL)
1682 * out_size [I] Size of OutputBuffer
1684 * RETURNS
1685 * Success: 0. IoStatusBlock is updated.
1686 * Failure: An NTSTATUS error code describing the error.
1688 NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
1689 PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code,
1690 PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size)
1692 NTSTATUS status;
1694 TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1695 handle, event, apc, apc_context, io, code,
1696 in_buffer, in_size, out_buffer, out_size);
1698 if (!io) return STATUS_INVALID_PARAMETER;
1700 ignore_server_ioctl_struct_holes( code, in_buffer, in_size );
1702 switch(code)
1704 case FSCTL_DISMOUNT_VOLUME:
1705 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1706 in_buffer, in_size, out_buffer, out_size );
1707 if (!status) status = DIR_unmount_device( handle );
1708 return status;
1710 case FSCTL_PIPE_IMPERSONATE:
1711 FIXME("FSCTL_PIPE_IMPERSONATE: impersonating self\n");
1712 status = RtlImpersonateSelf( SecurityImpersonation );
1713 break;
1715 case FSCTL_IS_VOLUME_MOUNTED:
1716 case FSCTL_LOCK_VOLUME:
1717 case FSCTL_UNLOCK_VOLUME:
1718 FIXME("stub! return success - Unsupported fsctl %x (device=%x access=%x func=%x method=%x)\n",
1719 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1720 status = STATUS_SUCCESS;
1721 break;
1723 case FSCTL_GET_RETRIEVAL_POINTERS:
1725 RETRIEVAL_POINTERS_BUFFER *buffer = (RETRIEVAL_POINTERS_BUFFER *)out_buffer;
1727 FIXME("stub: FSCTL_GET_RETRIEVAL_POINTERS\n");
1729 if (out_size >= sizeof(RETRIEVAL_POINTERS_BUFFER))
1731 buffer->ExtentCount = 1;
1732 buffer->StartingVcn.QuadPart = 1;
1733 buffer->Extents[0].NextVcn.QuadPart = 0;
1734 buffer->Extents[0].Lcn.QuadPart = 0;
1735 io->Information = sizeof(RETRIEVAL_POINTERS_BUFFER);
1736 status = STATUS_SUCCESS;
1738 else
1740 io->Information = 0;
1741 status = STATUS_BUFFER_TOO_SMALL;
1743 break;
1745 case FSCTL_SET_SPARSE:
1746 TRACE("FSCTL_SET_SPARSE: Ignoring request\n");
1747 io->Information = 0;
1748 status = STATUS_SUCCESS;
1749 break;
1750 default:
1751 return server_ioctl_file( handle, event, apc, apc_context, io, code,
1752 in_buffer, in_size, out_buffer, out_size );
1755 if (status != STATUS_PENDING) io->u.Status = status;
1756 return status;
1760 struct read_changes_fileio
1762 struct async_fileio io;
1763 void *buffer;
1764 ULONG buffer_size;
1765 ULONG data_size;
1766 char data[1];
1769 static NTSTATUS read_changes_apc( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
1771 struct read_changes_fileio *fileio = user;
1772 int size = 0;
1774 if (status == STATUS_ALERTED)
1776 SERVER_START_REQ( read_change )
1778 req->handle = wine_server_obj_handle( fileio->io.handle );
1779 wine_server_set_reply( req, fileio->data, fileio->data_size );
1780 status = wine_server_call( req );
1781 size = wine_server_reply_size( reply );
1783 SERVER_END_REQ;
1785 if (status == STATUS_SUCCESS && fileio->buffer)
1787 FILE_NOTIFY_INFORMATION *pfni = fileio->buffer;
1788 int i, left = fileio->buffer_size;
1789 DWORD *last_entry_offset = NULL;
1790 struct filesystem_event *event = (struct filesystem_event*)fileio->data;
1792 while (size && left >= sizeof(*pfni))
1794 DWORD len = (left - offsetof(FILE_NOTIFY_INFORMATION, FileName)) / sizeof(WCHAR);
1796 /* convert to an NT style path */
1797 for (i = 0; i < event->len; i++)
1798 if (event->name[i] == '/') event->name[i] = '\\';
1800 pfni->Action = event->action;
1801 pfni->FileNameLength = ntdll_umbstowcs( event->name, event->len, pfni->FileName, len );
1802 last_entry_offset = &pfni->NextEntryOffset;
1804 if (pfni->FileNameLength == len) break;
1806 i = offsetof(FILE_NOTIFY_INFORMATION, FileName[pfni->FileNameLength]);
1807 pfni->FileNameLength *= sizeof(WCHAR);
1808 pfni->NextEntryOffset = i;
1809 pfni = (FILE_NOTIFY_INFORMATION*)((char*)pfni + i);
1810 left -= i;
1812 i = (offsetof(struct filesystem_event, name[event->len])
1813 + sizeof(int)-1) / sizeof(int) * sizeof(int);
1814 event = (struct filesystem_event*)((char*)event + i);
1815 size -= i;
1818 if (size)
1820 status = STATUS_NOTIFY_ENUM_DIR;
1821 size = 0;
1823 else
1825 if (last_entry_offset) *last_entry_offset = 0;
1826 size = fileio->buffer_size - left;
1829 else
1831 status = STATUS_NOTIFY_ENUM_DIR;
1832 size = 0;
1836 if (status != STATUS_PENDING)
1838 iosb->u.Status = status;
1839 iosb->Information = size;
1840 release_fileio( &fileio->io );
1842 return status;
1845 #define FILE_NOTIFY_ALL ( \
1846 FILE_NOTIFY_CHANGE_FILE_NAME | \
1847 FILE_NOTIFY_CHANGE_DIR_NAME | \
1848 FILE_NOTIFY_CHANGE_ATTRIBUTES | \
1849 FILE_NOTIFY_CHANGE_SIZE | \
1850 FILE_NOTIFY_CHANGE_LAST_WRITE | \
1851 FILE_NOTIFY_CHANGE_LAST_ACCESS | \
1852 FILE_NOTIFY_CHANGE_CREATION | \
1853 FILE_NOTIFY_CHANGE_SECURITY )
1855 /******************************************************************************
1856 * NtNotifyChangeDirectoryFile [NTDLL.@]
1858 NTSTATUS WINAPI NtNotifyChangeDirectoryFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
1859 void *apc_context, PIO_STATUS_BLOCK iosb, void *buffer,
1860 ULONG buffer_size, ULONG filter, BOOLEAN subtree )
1862 struct read_changes_fileio *fileio;
1863 NTSTATUS status;
1864 ULONG size = max( 4096, buffer_size );
1866 TRACE( "%p %p %p %p %p %p %u %u %d\n",
1867 handle, event, apc, apc_context, iosb, buffer, buffer_size, filter, subtree );
1869 if (!iosb) return STATUS_ACCESS_VIOLATION;
1870 if (filter == 0 || (filter & ~FILE_NOTIFY_ALL)) return STATUS_INVALID_PARAMETER;
1872 fileio = (struct read_changes_fileio *)alloc_fileio( offsetof(struct read_changes_fileio, data[size]),
1873 read_changes_apc, handle );
1874 if (!fileio) return STATUS_NO_MEMORY;
1876 fileio->buffer = buffer;
1877 fileio->buffer_size = buffer_size;
1878 fileio->data_size = size;
1880 SERVER_START_REQ( read_directory_changes )
1882 req->filter = filter;
1883 req->want_data = (buffer != NULL);
1884 req->subtree = subtree;
1885 req->async = server_async( handle, &fileio->io, event, apc, apc_context, iosb );
1886 status = wine_server_call( req );
1888 SERVER_END_REQ;
1890 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
1891 return status;
1894 /******************************************************************************
1895 * NtSetVolumeInformationFile [NTDLL.@]
1896 * ZwSetVolumeInformationFile [NTDLL.@]
1898 * Set volume information for an open file handle.
1900 * PARAMS
1901 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1902 * IoStatusBlock [O] Receives information about the operation on return
1903 * FsInformation [I] Source for volume information
1904 * Length [I] Size of FsInformation
1905 * FsInformationClass [I] Type of volume information to set
1907 * RETURNS
1908 * Success: 0. IoStatusBlock is updated.
1909 * Failure: An NTSTATUS error code describing the error.
1911 NTSTATUS WINAPI NtSetVolumeInformationFile(
1912 IN HANDLE FileHandle,
1913 PIO_STATUS_BLOCK IoStatusBlock,
1914 PVOID FsInformation,
1915 ULONG Length,
1916 FS_INFORMATION_CLASS FsInformationClass)
1918 FIXME("(%p,%p,%p,0x%08x,0x%08x) stub\n",
1919 FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
1920 return 0;
1923 #if defined(__ANDROID__) && !defined(HAVE_FUTIMENS)
1924 static int futimens( int fd, const struct timespec spec[2] )
1926 return syscall( __NR_utimensat, fd, NULL, spec, 0 );
1928 #define HAVE_FUTIMENS
1929 #endif /* __ANDROID__ */
1931 #ifndef UTIME_OMIT
1932 #define UTIME_OMIT ((1 << 30) - 2)
1933 #endif
1935 static BOOL set_file_times_precise( int fd, const LARGE_INTEGER *mtime,
1936 const LARGE_INTEGER *atime, NTSTATUS *status )
1938 #ifdef HAVE_FUTIMENS
1939 struct timespec tv[2];
1941 tv[0].tv_sec = tv[1].tv_sec = 0;
1942 tv[0].tv_nsec = tv[1].tv_nsec = UTIME_OMIT;
1943 if (atime->QuadPart)
1945 tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
1946 tv[0].tv_nsec = (atime->QuadPart % 10000000) * 100;
1948 if (mtime->QuadPart)
1950 tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
1951 tv[1].tv_nsec = (mtime->QuadPart % 10000000) * 100;
1953 #ifdef __APPLE__
1954 if (!&futimens) return FALSE;
1955 #endif
1956 if (futimens( fd, tv ) == -1) *status = FILE_GetNtStatus();
1957 else *status = STATUS_SUCCESS;
1958 return TRUE;
1959 #else
1960 return FALSE;
1961 #endif
1964 static NTSTATUS set_file_times( int fd, const LARGE_INTEGER *mtime, const LARGE_INTEGER *atime )
1966 NTSTATUS status = STATUS_SUCCESS;
1967 #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
1968 struct timeval tv[2];
1969 struct stat st;
1970 #endif
1972 if (set_file_times_precise( fd, mtime, atime, &status ))
1973 return status;
1975 #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
1976 if (!atime->QuadPart || !mtime->QuadPart)
1979 tv[0].tv_sec = tv[0].tv_usec = 0;
1980 tv[1].tv_sec = tv[1].tv_usec = 0;
1981 if (!fstat( fd, &st ))
1983 tv[0].tv_sec = st.st_atime;
1984 tv[1].tv_sec = st.st_mtime;
1985 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1986 tv[0].tv_usec = st.st_atim.tv_nsec / 1000;
1987 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
1988 tv[0].tv_usec = st.st_atimespec.tv_nsec / 1000;
1989 #endif
1990 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1991 tv[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1992 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
1993 tv[1].tv_usec = st.st_mtimespec.tv_nsec / 1000;
1994 #endif
1997 if (atime->QuadPart)
1999 tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
2000 tv[0].tv_usec = (atime->QuadPart % 10000000) / 10;
2002 if (mtime->QuadPart)
2004 tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
2005 tv[1].tv_usec = (mtime->QuadPart % 10000000) / 10;
2007 #ifdef HAVE_FUTIMES
2008 if (futimes( fd, tv ) == -1) status = FILE_GetNtStatus();
2009 #elif defined(HAVE_FUTIMESAT)
2010 if (futimesat( fd, NULL, tv ) == -1) status = FILE_GetNtStatus();
2011 #endif
2013 #else /* HAVE_FUTIMES || HAVE_FUTIMESAT */
2014 FIXME( "setting file times not supported\n" );
2015 status = STATUS_NOT_IMPLEMENTED;
2016 #endif
2017 return status;
2020 static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, LARGE_INTEGER *ctime,
2021 LARGE_INTEGER *atime, LARGE_INTEGER *creation )
2023 RtlSecondsSince1970ToTime( st->st_mtime, mtime );
2024 RtlSecondsSince1970ToTime( st->st_ctime, ctime );
2025 RtlSecondsSince1970ToTime( st->st_atime, atime );
2026 #ifdef HAVE_STRUCT_STAT_ST_MTIM
2027 mtime->QuadPart += st->st_mtim.tv_nsec / 100;
2028 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
2029 mtime->QuadPart += st->st_mtimespec.tv_nsec / 100;
2030 #endif
2031 #ifdef HAVE_STRUCT_STAT_ST_CTIM
2032 ctime->QuadPart += st->st_ctim.tv_nsec / 100;
2033 #elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
2034 ctime->QuadPart += st->st_ctimespec.tv_nsec / 100;
2035 #endif
2036 #ifdef HAVE_STRUCT_STAT_ST_ATIM
2037 atime->QuadPart += st->st_atim.tv_nsec / 100;
2038 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
2039 atime->QuadPart += st->st_atimespec.tv_nsec / 100;
2040 #endif
2041 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2042 RtlSecondsSince1970ToTime( st->st_birthtime, creation );
2043 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIM
2044 creation->QuadPart += st->st_birthtim.tv_nsec / 100;
2045 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
2046 creation->QuadPart += st->st_birthtimespec.tv_nsec / 100;
2047 #endif
2048 #elif defined(HAVE_STRUCT_STAT___ST_BIRTHTIME)
2049 RtlSecondsSince1970ToTime( st->__st_birthtime, creation );
2050 #ifdef HAVE_STRUCT_STAT___ST_BIRTHTIM
2051 creation->QuadPart += st->__st_birthtim.tv_nsec / 100;
2052 #endif
2053 #else
2054 *creation = *mtime;
2055 #endif
2058 /* fill in the file information that depends on the stat and attribute info */
2059 NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
2060 FILE_INFORMATION_CLASS class )
2062 switch (class)
2064 case FileBasicInformation:
2066 FILE_BASIC_INFORMATION *info = ptr;
2068 get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
2069 &info->LastAccessTime, &info->CreationTime );
2070 info->FileAttributes = attr;
2072 break;
2073 case FileStandardInformation:
2075 FILE_STANDARD_INFORMATION *info = ptr;
2077 if ((info->Directory = S_ISDIR(st->st_mode)))
2079 info->AllocationSize.QuadPart = 0;
2080 info->EndOfFile.QuadPart = 0;
2081 info->NumberOfLinks = 1;
2083 else
2085 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
2086 info->EndOfFile.QuadPart = st->st_size;
2087 info->NumberOfLinks = st->st_nlink;
2090 break;
2091 case FileInternalInformation:
2093 FILE_INTERNAL_INFORMATION *info = ptr;
2094 info->IndexNumber.QuadPart = st->st_ino;
2096 break;
2097 case FileEndOfFileInformation:
2099 FILE_END_OF_FILE_INFORMATION *info = ptr;
2100 info->EndOfFile.QuadPart = S_ISDIR(st->st_mode) ? 0 : st->st_size;
2102 break;
2103 case FileAllInformation:
2105 FILE_ALL_INFORMATION *info = ptr;
2106 fill_file_info( st, attr, &info->BasicInformation, FileBasicInformation );
2107 fill_file_info( st, attr, &info->StandardInformation, FileStandardInformation );
2108 fill_file_info( st, attr, &info->InternalInformation, FileInternalInformation );
2110 break;
2111 /* all directory structures start with the FileDirectoryInformation layout */
2112 case FileBothDirectoryInformation:
2113 case FileFullDirectoryInformation:
2114 case FileDirectoryInformation:
2116 FILE_DIRECTORY_INFORMATION *info = ptr;
2118 get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
2119 &info->LastAccessTime, &info->CreationTime );
2120 if (S_ISDIR(st->st_mode))
2122 info->AllocationSize.QuadPart = 0;
2123 info->EndOfFile.QuadPart = 0;
2125 else
2127 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
2128 info->EndOfFile.QuadPart = st->st_size;
2130 info->FileAttributes = attr;
2132 break;
2133 case FileIdFullDirectoryInformation:
2135 FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr;
2136 info->FileId.QuadPart = st->st_ino;
2137 fill_file_info( st, attr, info, FileDirectoryInformation );
2139 break;
2140 case FileIdBothDirectoryInformation:
2142 FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr;
2143 info->FileId.QuadPart = st->st_ino;
2144 fill_file_info( st, attr, info, FileDirectoryInformation );
2146 break;
2147 case FileIdGlobalTxDirectoryInformation:
2149 FILE_ID_GLOBAL_TX_DIR_INFORMATION *info = ptr;
2150 info->FileId.QuadPart = st->st_ino;
2151 fill_file_info( st, attr, info, FileDirectoryInformation );
2153 break;
2155 default:
2156 return STATUS_INVALID_INFO_CLASS;
2158 return STATUS_SUCCESS;
2161 NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name )
2163 data_size_t size = 1024;
2164 NTSTATUS ret;
2165 char *name;
2167 for (;;)
2169 name = RtlAllocateHeap( GetProcessHeap(), 0, size + 1 );
2170 if (!name) return STATUS_NO_MEMORY;
2171 unix_name->MaximumLength = size + 1;
2173 SERVER_START_REQ( get_handle_unix_name )
2175 req->handle = wine_server_obj_handle( handle );
2176 wine_server_set_reply( req, name, size );
2177 ret = wine_server_call( req );
2178 size = reply->name_len;
2180 SERVER_END_REQ;
2182 if (!ret)
2184 name[size] = 0;
2185 unix_name->Buffer = name;
2186 unix_name->Length = size;
2187 break;
2189 RtlFreeHeap( GetProcessHeap(), 0, name );
2190 if (ret != STATUS_BUFFER_OVERFLOW) break;
2192 return ret;
2195 static NTSTATUS fill_name_info( const ANSI_STRING *unix_name, FILE_NAME_INFORMATION *info, LONG *name_len )
2197 UNICODE_STRING nt_name;
2198 NTSTATUS status;
2200 if (!(status = wine_unix_to_nt_file_name( unix_name, &nt_name )))
2202 const WCHAR *ptr = nt_name.Buffer;
2203 const WCHAR *end = ptr + (nt_name.Length / sizeof(WCHAR));
2205 /* Skip the volume mount point. */
2206 while (ptr != end && *ptr == '\\') ++ptr;
2207 while (ptr != end && *ptr != '\\') ++ptr;
2208 while (ptr != end && *ptr == '\\') ++ptr;
2209 while (ptr != end && *ptr != '\\') ++ptr;
2211 info->FileNameLength = (end - ptr) * sizeof(WCHAR);
2212 if (*name_len < info->FileNameLength) status = STATUS_BUFFER_OVERFLOW;
2213 else *name_len = info->FileNameLength;
2215 memcpy( info->FileName, ptr, *name_len );
2216 RtlFreeUnicodeString( &nt_name );
2219 return status;
2222 static NTSTATUS server_get_file_info( HANDLE handle, IO_STATUS_BLOCK *io, void *buffer,
2223 ULONG length, FILE_INFORMATION_CLASS info_class )
2225 SERVER_START_REQ( get_file_info )
2227 req->handle = wine_server_obj_handle( handle );
2228 req->info_class = info_class;
2229 wine_server_set_reply( req, buffer, length );
2230 io->u.Status = wine_server_call( req );
2231 io->Information = wine_server_reply_size( reply );
2233 SERVER_END_REQ;
2234 if (io->u.Status == STATUS_NOT_IMPLEMENTED)
2235 FIXME( "Unsupported info class %x\n", info_class );
2236 return io->u.Status;
2240 /* Find a DOS device which can act as the root of "path".
2241 * Similar to find_drive_root(), but returns -1 instead of crossing volumes. */
2242 static int find_dos_device( const char *path )
2244 int len = strlen(path);
2245 int drive;
2246 char *buffer;
2247 struct stat st;
2248 struct drive_info info[MAX_DOS_DRIVES];
2249 dev_t dev_id;
2251 if (!DIR_get_drives_info( info )) return -1;
2253 if (stat( path, &st ) < 0) return -1;
2254 dev_id = st.st_dev;
2256 /* strip off trailing slashes */
2257 while (len > 1 && path[len - 1] == '/') len--;
2259 /* make a copy of the path */
2260 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, len + 1 ))) return -1;
2261 memcpy( buffer, path, len );
2262 buffer[len] = 0;
2264 for (;;)
2266 if (!stat( buffer, &st ) && S_ISDIR( st.st_mode ))
2268 if (st.st_dev != dev_id) break;
2270 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
2272 if ((info[drive].dev == st.st_dev) && (info[drive].ino == st.st_ino))
2274 if (len == 1) len = 0; /* preserve root slash in returned path */
2275 TRACE( "%s -> drive %c:, root=%s, name=%s\n",
2276 debugstr_a(path), 'A' + drive, debugstr_a(buffer), debugstr_a(path + len));
2277 RtlFreeHeap( GetProcessHeap(), 0, buffer );
2278 return drive;
2282 if (len <= 1) break; /* reached root */
2283 while (path[len - 1] != '/') len--;
2284 while (path[len - 1] == '/') len--;
2285 buffer[len] = 0;
2287 RtlFreeHeap( GetProcessHeap(), 0, buffer );
2288 return -1;
2291 static struct mountmgr_unix_drive *get_mountmgr_fs_info( HANDLE handle, int fd )
2293 struct mountmgr_unix_drive *drive;
2294 OBJECT_ATTRIBUTES attr;
2295 UNICODE_STRING string;
2296 ANSI_STRING unix_name;
2297 IO_STATUS_BLOCK io;
2298 HANDLE mountmgr;
2299 NTSTATUS status;
2300 int letter;
2302 if (server_get_unix_name( handle, &unix_name ))
2303 return NULL;
2305 letter = find_dos_device( unix_name.Buffer );
2306 RtlFreeAnsiString( &unix_name );
2308 if (!(drive = RtlAllocateHeap( GetProcessHeap(), 0, 1024 )))
2309 return NULL;
2311 if (letter == -1)
2313 struct stat st;
2315 if (fstat( fd, &st ) == -1)
2317 RtlFreeHeap( GetProcessHeap(), 0, drive );
2318 return NULL;
2321 drive->unix_dev = st.st_dev;
2322 drive->letter = 0;
2324 else
2325 drive->letter = 'a' + letter;
2327 RtlInitUnicodeString( &string, MOUNTMGR_DEVICE_NAME );
2328 InitializeObjectAttributes( &attr, &string, 0, NULL, NULL );
2329 if (NtOpenFile( &mountmgr, GENERIC_READ | SYNCHRONIZE, &attr, &io,
2330 FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT ))
2331 return NULL;
2333 status = NtDeviceIoControlFile( mountmgr, NULL, NULL, NULL, &io, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE,
2334 drive, sizeof(*drive), drive, 1024 );
2335 if (status == STATUS_BUFFER_OVERFLOW)
2337 if (!(drive = RtlReAllocateHeap( GetProcessHeap(), 0, drive, drive->size )))
2339 RtlFreeHeap( GetProcessHeap(), 0, drive );
2340 NtClose( mountmgr );
2341 return NULL;
2343 status = NtDeviceIoControlFile( mountmgr, NULL, NULL, NULL, &io, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE,
2344 drive, sizeof(*drive), drive, drive->size );
2346 NtClose( mountmgr );
2348 if (status)
2350 WARN("failed to retrieve filesystem type from mountmgr, status %#x\n", status);
2351 RtlFreeHeap( GetProcessHeap(), 0, drive );
2352 return NULL;
2355 return drive;
2358 /******************************************************************************
2359 * NtQueryInformationFile [NTDLL.@]
2360 * ZwQueryInformationFile [NTDLL.@]
2362 * Get information about an open file handle.
2364 * PARAMS
2365 * hFile [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2366 * io [O] Receives information about the operation on return
2367 * ptr [O] Destination for file information
2368 * len [I] Size of FileInformation
2369 * class [I] Type of file information to get
2371 * RETURNS
2372 * Success: 0. IoStatusBlock and FileInformation are updated.
2373 * Failure: An NTSTATUS error code describing the error.
2375 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
2376 PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
2378 static const size_t info_sizes[] =
2381 sizeof(FILE_DIRECTORY_INFORMATION), /* FileDirectoryInformation */
2382 sizeof(FILE_FULL_DIRECTORY_INFORMATION), /* FileFullDirectoryInformation */
2383 sizeof(FILE_BOTH_DIRECTORY_INFORMATION), /* FileBothDirectoryInformation */
2384 sizeof(FILE_BASIC_INFORMATION), /* FileBasicInformation */
2385 sizeof(FILE_STANDARD_INFORMATION), /* FileStandardInformation */
2386 sizeof(FILE_INTERNAL_INFORMATION), /* FileInternalInformation */
2387 sizeof(FILE_EA_INFORMATION), /* FileEaInformation */
2388 0, /* FileAccessInformation */
2389 sizeof(FILE_NAME_INFORMATION), /* FileNameInformation */
2390 sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
2391 0, /* FileLinkInformation */
2392 sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR), /* FileNamesInformation */
2393 sizeof(FILE_DISPOSITION_INFORMATION), /* FileDispositionInformation */
2394 sizeof(FILE_POSITION_INFORMATION), /* FilePositionInformation */
2395 sizeof(FILE_FULL_EA_INFORMATION), /* FileFullEaInformation */
2396 0, /* FileModeInformation */
2397 sizeof(FILE_ALIGNMENT_INFORMATION), /* FileAlignmentInformation */
2398 sizeof(FILE_ALL_INFORMATION), /* FileAllInformation */
2399 sizeof(FILE_ALLOCATION_INFORMATION), /* FileAllocationInformation */
2400 sizeof(FILE_END_OF_FILE_INFORMATION), /* FileEndOfFileInformation */
2401 0, /* FileAlternateNameInformation */
2402 sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
2403 sizeof(FILE_PIPE_INFORMATION), /* FilePipeInformation */
2404 sizeof(FILE_PIPE_LOCAL_INFORMATION), /* FilePipeLocalInformation */
2405 0, /* FilePipeRemoteInformation */
2406 sizeof(FILE_MAILSLOT_QUERY_INFORMATION), /* FileMailslotQueryInformation */
2407 0, /* FileMailslotSetInformation */
2408 0, /* FileCompressionInformation */
2409 0, /* FileObjectIdInformation */
2410 0, /* FileCompletionInformation */
2411 0, /* FileMoveClusterInformation */
2412 0, /* FileQuotaInformation */
2413 0, /* FileReparsePointInformation */
2414 sizeof(FILE_NETWORK_OPEN_INFORMATION), /* FileNetworkOpenInformation */
2415 sizeof(FILE_ATTRIBUTE_TAG_INFORMATION), /* FileAttributeTagInformation */
2416 0, /* FileTrackingInformation */
2417 0, /* FileIdBothDirectoryInformation */
2418 0, /* FileIdFullDirectoryInformation */
2419 0, /* FileValidDataLengthInformation */
2420 0, /* FileShortNameInformation */
2421 0, /* FileIoCompletionNotificationInformation, */
2422 0, /* FileIoStatusBlockRangeInformation */
2423 0, /* FileIoPriorityHintInformation */
2424 0, /* FileSfioReserveInformation */
2425 0, /* FileSfioVolumeInformation */
2426 0, /* FileHardLinkInformation */
2427 0, /* FileProcessIdsUsingFileInformation */
2428 0, /* FileNormalizedNameInformation */
2429 0, /* FileNetworkPhysicalNameInformation */
2430 0, /* FileIdGlobalTxDirectoryInformation */
2431 0, /* FileIsRemoteDeviceInformation */
2432 0, /* FileAttributeCacheInformation */
2433 0, /* FileNumaNodeInformation */
2434 0, /* FileStandardLinkInformation */
2435 0, /* FileRemoteProtocolInformation */
2436 0, /* FileRenameInformationBypassAccessCheck */
2437 0, /* FileLinkInformationBypassAccessCheck */
2438 0, /* FileVolumeNameInformation */
2439 sizeof(FILE_ID_INFORMATION), /* FileIdInformation */
2440 0, /* FileIdExtdDirectoryInformation */
2441 0, /* FileReplaceCompletionInformation */
2442 0, /* FileHardLinkFullIdInformation */
2443 0, /* FileIdExtdBothDirectoryInformation */
2446 struct stat st;
2447 int fd, needs_close = FALSE;
2448 ULONG attr;
2449 unsigned int options;
2451 TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
2453 io->Information = 0;
2455 if (class <= 0 || class >= FileMaximumInformation)
2456 return io->u.Status = STATUS_INVALID_INFO_CLASS;
2457 if (!info_sizes[class])
2458 return server_get_file_info( hFile, io, ptr, len, class );
2459 if (len < info_sizes[class])
2460 return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
2462 if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, &options )))
2464 if (io->u.Status != STATUS_BAD_DEVICE_TYPE) return io->u.Status;
2465 return server_get_file_info( hFile, io, ptr, len, class );
2468 switch (class)
2470 case FileBasicInformation:
2471 if (fd_get_file_info( fd, options, &st, &attr ) == -1)
2472 io->u.Status = FILE_GetNtStatus();
2473 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2474 io->u.Status = STATUS_INVALID_INFO_CLASS;
2475 else
2476 fill_file_info( &st, attr, ptr, class );
2477 break;
2478 case FileStandardInformation:
2480 FILE_STANDARD_INFORMATION *info = ptr;
2482 if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2483 else
2485 fill_file_info( &st, attr, info, class );
2486 info->DeletePending = FALSE; /* FIXME */
2489 break;
2490 case FilePositionInformation:
2492 FILE_POSITION_INFORMATION *info = ptr;
2493 off_t res = lseek( fd, 0, SEEK_CUR );
2494 if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
2495 else info->CurrentByteOffset.QuadPart = res;
2497 break;
2498 case FileInternalInformation:
2499 if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2500 else fill_file_info( &st, attr, ptr, class );
2501 break;
2502 case FileEaInformation:
2504 FILE_EA_INFORMATION *info = ptr;
2505 info->EaSize = 0;
2507 break;
2508 case FileEndOfFileInformation:
2509 if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2510 else fill_file_info( &st, attr, ptr, class );
2511 break;
2512 case FileAllInformation:
2514 FILE_ALL_INFORMATION *info = ptr;
2515 ANSI_STRING unix_name;
2517 if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2518 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2519 io->u.Status = STATUS_INVALID_INFO_CLASS;
2520 else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2522 LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
2524 fill_file_info( &st, attr, info, FileAllInformation );
2525 info->StandardInformation.DeletePending = FALSE; /* FIXME */
2526 info->EaInformation.EaSize = 0;
2527 info->AccessInformation.AccessFlags = 0; /* FIXME */
2528 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
2529 info->ModeInformation.Mode = 0; /* FIXME */
2530 info->AlignmentInformation.AlignmentRequirement = 1; /* FIXME */
2532 io->u.Status = fill_name_info( &unix_name, &info->NameInformation, &name_len );
2533 RtlFreeAnsiString( &unix_name );
2534 io->Information = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + name_len;
2537 break;
2538 case FileMailslotQueryInformation:
2540 FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
2542 SERVER_START_REQ( set_mailslot_info )
2544 req->handle = wine_server_obj_handle( hFile );
2545 req->flags = 0;
2546 io->u.Status = wine_server_call( req );
2547 if( io->u.Status == STATUS_SUCCESS )
2549 info->MaximumMessageSize = reply->max_msgsize;
2550 info->MailslotQuota = 0;
2551 info->NextMessageSize = 0;
2552 info->MessagesAvailable = 0;
2553 info->ReadTimeout.QuadPart = reply->read_timeout;
2556 SERVER_END_REQ;
2557 if (!io->u.Status)
2559 char *tmpbuf;
2560 ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000;
2561 if (size > 0x10000) size = 0x10000;
2562 if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2564 if (!server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
2566 int res = recv( fd, tmpbuf, size, MSG_PEEK );
2567 info->MessagesAvailable = (res > 0);
2568 info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE;
2569 if (needs_close) close( fd );
2571 RtlFreeHeap( GetProcessHeap(), 0, tmpbuf );
2575 break;
2576 case FileNameInformation:
2578 FILE_NAME_INFORMATION *info = ptr;
2579 ANSI_STRING unix_name;
2581 if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2583 LONG name_len = len - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2584 io->u.Status = fill_name_info( &unix_name, info, &name_len );
2585 RtlFreeAnsiString( &unix_name );
2586 io->Information = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + name_len;
2589 break;
2590 case FileNetworkOpenInformation:
2592 FILE_NETWORK_OPEN_INFORMATION *info = ptr;
2593 ANSI_STRING unix_name;
2595 if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2597 ULONG attributes;
2598 struct stat st;
2600 if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
2601 io->u.Status = FILE_GetNtStatus();
2602 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2603 io->u.Status = STATUS_INVALID_INFO_CLASS;
2604 else
2606 FILE_BASIC_INFORMATION basic;
2607 FILE_STANDARD_INFORMATION std;
2609 fill_file_info( &st, attributes, &basic, FileBasicInformation );
2610 fill_file_info( &st, attributes, &std, FileStandardInformation );
2612 info->CreationTime = basic.CreationTime;
2613 info->LastAccessTime = basic.LastAccessTime;
2614 info->LastWriteTime = basic.LastWriteTime;
2615 info->ChangeTime = basic.ChangeTime;
2616 info->AllocationSize = std.AllocationSize;
2617 info->EndOfFile = std.EndOfFile;
2618 info->FileAttributes = basic.FileAttributes;
2620 RtlFreeAnsiString( &unix_name );
2623 break;
2624 case FileIdInformation:
2625 if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2626 else
2628 struct mountmgr_unix_drive *drive;
2629 FILE_ID_INFORMATION *info = ptr;
2631 info->VolumeSerialNumber = 0;
2632 if ((drive = get_mountmgr_fs_info( hFile, fd )))
2634 info->VolumeSerialNumber = drive->serial;
2635 RtlFreeHeap( GetProcessHeap(), 0, drive );
2637 memset( &info->FileId, 0, sizeof(info->FileId) );
2638 *(ULONGLONG *)&info->FileId = st.st_ino;
2640 break;
2641 case FileAttributeTagInformation:
2642 if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2643 else
2645 FILE_ATTRIBUTE_TAG_INFORMATION *info = ptr;
2646 info->FileAttributes = attr;
2647 info->ReparseTag = 0; /* FIXME */
2648 if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, &st ))
2649 info->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
2651 break;
2652 default:
2653 FIXME("Unsupported class (%d)\n", class);
2654 io->u.Status = STATUS_NOT_IMPLEMENTED;
2655 break;
2657 if (needs_close) close( fd );
2658 if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
2659 return io->u.Status;
2662 /******************************************************************************
2663 * NtSetInformationFile [NTDLL.@]
2664 * ZwSetInformationFile [NTDLL.@]
2666 * Set information about an open file handle.
2668 * PARAMS
2669 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2670 * io [O] Receives information about the operation on return
2671 * ptr [I] Source for file information
2672 * len [I] Size of FileInformation
2673 * class [I] Type of file information to set
2675 * RETURNS
2676 * Success: 0. io is updated.
2677 * Failure: An NTSTATUS error code describing the error.
2679 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
2680 PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
2682 int fd, needs_close;
2684 TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", handle, io, ptr, len, class);
2686 io->u.Status = STATUS_SUCCESS;
2687 switch (class)
2689 case FileBasicInformation:
2690 if (len >= sizeof(FILE_BASIC_INFORMATION))
2692 struct stat st;
2693 const FILE_BASIC_INFORMATION *info = ptr;
2694 LARGE_INTEGER mtime, atime;
2696 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2697 return io->u.Status;
2699 mtime.QuadPart = info->LastWriteTime.QuadPart == -1 ? 0 : info->LastWriteTime.QuadPart;
2700 atime.QuadPart = info->LastAccessTime.QuadPart == -1 ? 0 : info->LastAccessTime.QuadPart;
2702 if (atime.QuadPart || mtime.QuadPart)
2703 io->u.Status = set_file_times( fd, &mtime, &atime );
2705 if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
2707 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2708 else
2710 if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
2712 if (S_ISDIR( st.st_mode))
2713 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
2714 else
2715 st.st_mode &= ~0222; /* clear write permission bits */
2717 else
2719 /* add write permission only where we already have read permission */
2720 st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
2722 if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
2726 if (needs_close) close( fd );
2728 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2729 break;
2731 case FilePositionInformation:
2732 if (len >= sizeof(FILE_POSITION_INFORMATION))
2734 const FILE_POSITION_INFORMATION *info = ptr;
2736 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2737 return io->u.Status;
2739 if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
2740 io->u.Status = FILE_GetNtStatus();
2742 if (needs_close) close( fd );
2744 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2745 break;
2747 case FileEndOfFileInformation:
2748 if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
2750 struct stat st;
2751 const FILE_END_OF_FILE_INFORMATION *info = ptr;
2753 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2754 return io->u.Status;
2756 /* first try normal truncate */
2757 if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2759 /* now check for the need to extend the file */
2760 if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
2762 static const char zero;
2764 /* extend the file one byte beyond the requested size and then truncate it */
2765 /* this should work around ftruncate implementations that can't extend files */
2766 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
2767 ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2769 io->u.Status = FILE_GetNtStatus();
2771 if (needs_close) close( fd );
2773 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2774 break;
2776 case FilePipeInformation:
2777 if (len >= sizeof(FILE_PIPE_INFORMATION))
2779 FILE_PIPE_INFORMATION *info = ptr;
2781 if ((info->CompletionMode | info->ReadMode) & ~1)
2783 io->u.Status = STATUS_INVALID_PARAMETER;
2784 break;
2787 SERVER_START_REQ( set_named_pipe_info )
2789 req->handle = wine_server_obj_handle( handle );
2790 req->flags = (info->CompletionMode ? NAMED_PIPE_NONBLOCKING_MODE : 0) |
2791 (info->ReadMode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0);
2792 io->u.Status = wine_server_call( req );
2794 SERVER_END_REQ;
2796 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2797 break;
2799 case FileMailslotSetInformation:
2801 FILE_MAILSLOT_SET_INFORMATION *info = ptr;
2803 SERVER_START_REQ( set_mailslot_info )
2805 req->handle = wine_server_obj_handle( handle );
2806 req->flags = MAILSLOT_SET_READ_TIMEOUT;
2807 req->read_timeout = info->ReadTimeout.QuadPart;
2808 io->u.Status = wine_server_call( req );
2810 SERVER_END_REQ;
2812 break;
2814 case FileCompletionInformation:
2815 if (len >= sizeof(FILE_COMPLETION_INFORMATION))
2817 FILE_COMPLETION_INFORMATION *info = ptr;
2819 SERVER_START_REQ( set_completion_info )
2821 req->handle = wine_server_obj_handle( handle );
2822 req->chandle = wine_server_obj_handle( info->CompletionPort );
2823 req->ckey = info->CompletionKey;
2824 io->u.Status = wine_server_call( req );
2826 SERVER_END_REQ;
2827 } else
2828 io->u.Status = STATUS_INVALID_PARAMETER_3;
2829 break;
2831 case FileIoCompletionNotificationInformation:
2832 if (len >= sizeof(FILE_IO_COMPLETION_NOTIFICATION_INFORMATION))
2834 FILE_IO_COMPLETION_NOTIFICATION_INFORMATION *info = ptr;
2836 if (info->Flags & FILE_SKIP_SET_USER_EVENT_ON_FAST_IO)
2837 FIXME( "FILE_SKIP_SET_USER_EVENT_ON_FAST_IO not supported\n" );
2839 SERVER_START_REQ( set_fd_completion_mode )
2841 req->handle = wine_server_obj_handle( handle );
2842 req->flags = info->Flags;
2843 io->u.Status = wine_server_call( req );
2845 SERVER_END_REQ;
2846 } else
2847 io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
2848 break;
2850 case FileIoPriorityHintInformation:
2851 if (len >= sizeof(FILE_IO_PRIORITY_HINT_INFO))
2853 FILE_IO_PRIORITY_HINT_INFO *info = ptr;
2854 if (info->PriorityHint < MaximumIoPriorityHintType)
2855 TRACE( "ignoring FileIoPriorityHintInformation %u\n", info->PriorityHint );
2856 else
2857 io->u.Status = STATUS_INVALID_PARAMETER;
2859 else io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
2860 break;
2862 case FileAllInformation:
2863 io->u.Status = STATUS_INVALID_INFO_CLASS;
2864 break;
2866 case FileValidDataLengthInformation:
2867 if (len >= sizeof(FILE_VALID_DATA_LENGTH_INFORMATION))
2869 struct stat st;
2870 const FILE_VALID_DATA_LENGTH_INFORMATION *info = ptr;
2872 if ((io->u.Status = server_get_unix_fd( handle, FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL )))
2873 return io->u.Status;
2875 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2876 else if (info->ValidDataLength.QuadPart <= 0 || (off_t)info->ValidDataLength.QuadPart > st.st_size)
2877 io->u.Status = STATUS_INVALID_PARAMETER;
2878 else
2880 #ifdef HAVE_FALLOCATE
2881 if (fallocate( fd, 0, 0, (off_t)info->ValidDataLength.QuadPart ) == -1)
2883 NTSTATUS status = FILE_GetNtStatus();
2884 if (status == STATUS_NOT_SUPPORTED) WARN( "fallocate not supported on this filesystem\n" );
2885 else io->u.Status = status;
2887 #else
2888 FIXME( "setting valid data length not supported\n" );
2889 #endif
2891 if (needs_close) close( fd );
2893 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2894 break;
2896 case FileDispositionInformation:
2897 if (len >= sizeof(FILE_DISPOSITION_INFORMATION))
2899 FILE_DISPOSITION_INFORMATION *info = ptr;
2901 SERVER_START_REQ( set_fd_disp_info )
2903 req->handle = wine_server_obj_handle( handle );
2904 req->unlink = info->DoDeleteFile;
2905 io->u.Status = wine_server_call( req );
2907 SERVER_END_REQ;
2908 } else
2909 io->u.Status = STATUS_INVALID_PARAMETER_3;
2910 break;
2912 case FileRenameInformation:
2913 if (len >= sizeof(FILE_RENAME_INFORMATION))
2915 FILE_RENAME_INFORMATION *info = ptr;
2916 UNICODE_STRING name_str;
2917 OBJECT_ATTRIBUTES attr;
2918 ANSI_STRING unix_name;
2920 name_str.Buffer = info->FileName;
2921 name_str.Length = info->FileNameLength;
2922 name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR);
2924 attr.Length = sizeof(attr);
2925 attr.ObjectName = &name_str;
2926 attr.RootDirectory = info->RootDirectory;
2927 attr.Attributes = OBJ_CASE_INSENSITIVE;
2929 io->u.Status = nt_to_unix_file_name_attr( &attr, &unix_name, FILE_OPEN_IF );
2930 if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE)
2931 break;
2933 SERVER_START_REQ( set_fd_name_info )
2935 req->handle = wine_server_obj_handle( handle );
2936 req->rootdir = wine_server_obj_handle( attr.RootDirectory );
2937 req->link = FALSE;
2938 req->replace = info->ReplaceIfExists;
2939 wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
2940 io->u.Status = wine_server_call( req );
2942 SERVER_END_REQ;
2944 RtlFreeAnsiString( &unix_name );
2946 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2947 break;
2949 case FileLinkInformation:
2950 if (len >= sizeof(FILE_LINK_INFORMATION))
2952 FILE_LINK_INFORMATION *info = ptr;
2953 UNICODE_STRING name_str;
2954 OBJECT_ATTRIBUTES attr;
2955 ANSI_STRING unix_name;
2957 name_str.Buffer = info->FileName;
2958 name_str.Length = info->FileNameLength;
2959 name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR);
2961 attr.Length = sizeof(attr);
2962 attr.ObjectName = &name_str;
2963 attr.RootDirectory = info->RootDirectory;
2964 attr.Attributes = OBJ_CASE_INSENSITIVE;
2966 io->u.Status = nt_to_unix_file_name_attr( &attr, &unix_name, FILE_OPEN_IF );
2967 if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE)
2968 break;
2970 SERVER_START_REQ( set_fd_name_info )
2972 req->handle = wine_server_obj_handle( handle );
2973 req->rootdir = wine_server_obj_handle( attr.RootDirectory );
2974 req->link = TRUE;
2975 req->replace = info->ReplaceIfExists;
2976 wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
2977 io->u.Status = wine_server_call( req );
2979 SERVER_END_REQ;
2981 RtlFreeAnsiString( &unix_name );
2983 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2984 break;
2986 default:
2987 FIXME("Unsupported class (%d)\n", class);
2988 io->u.Status = STATUS_NOT_IMPLEMENTED;
2989 break;
2991 io->Information = 0;
2992 return io->u.Status;
2996 /******************************************************************************
2997 * NtQueryFullAttributesFile (NTDLL.@)
2999 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
3000 FILE_NETWORK_OPEN_INFORMATION *info )
3002 ANSI_STRING unix_name;
3003 NTSTATUS status;
3005 if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
3007 ULONG attributes;
3008 struct stat st;
3010 if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
3011 status = FILE_GetNtStatus();
3012 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
3013 status = STATUS_INVALID_INFO_CLASS;
3014 else
3016 FILE_BASIC_INFORMATION basic;
3017 FILE_STANDARD_INFORMATION std;
3019 fill_file_info( &st, attributes, &basic, FileBasicInformation );
3020 fill_file_info( &st, attributes, &std, FileStandardInformation );
3022 info->CreationTime = basic.CreationTime;
3023 info->LastAccessTime = basic.LastAccessTime;
3024 info->LastWriteTime = basic.LastWriteTime;
3025 info->ChangeTime = basic.ChangeTime;
3026 info->AllocationSize = std.AllocationSize;
3027 info->EndOfFile = std.EndOfFile;
3028 info->FileAttributes = basic.FileAttributes;
3029 if (DIR_is_hidden_file( attr->ObjectName ))
3030 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
3032 RtlFreeAnsiString( &unix_name );
3034 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
3035 return status;
3039 /******************************************************************************
3040 * NtQueryAttributesFile (NTDLL.@)
3041 * ZwQueryAttributesFile (NTDLL.@)
3043 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
3045 ANSI_STRING unix_name;
3046 NTSTATUS status;
3048 if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
3050 ULONG attributes;
3051 struct stat st;
3053 if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
3054 status = FILE_GetNtStatus();
3055 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
3056 status = STATUS_INVALID_INFO_CLASS;
3057 else
3059 status = fill_file_info( &st, attributes, info, FileBasicInformation );
3060 if (DIR_is_hidden_file( attr->ObjectName ))
3061 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
3063 RtlFreeAnsiString( &unix_name );
3065 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
3066 return status;
3070 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
3071 /* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */
3072 static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename,
3073 unsigned int flags )
3075 if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename))
3077 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
3078 /* Don't assume read-only, let the mount options set it below */
3079 info->Characteristics |= FILE_REMOVABLE_MEDIA;
3081 else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) ||
3082 !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename))
3084 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
3085 info->Characteristics |= FILE_REMOTE_DEVICE;
3087 else if (!strcmp("procfs", fstypename))
3088 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
3089 else
3090 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3092 if (flags & MNT_RDONLY)
3093 info->Characteristics |= FILE_READ_ONLY_DEVICE;
3095 if (!(flags & MNT_LOCAL))
3097 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
3098 info->Characteristics |= FILE_REMOTE_DEVICE;
3101 #endif
3103 static inline BOOL is_device_placeholder( int fd )
3105 static const char wine_placeholder[] = "Wine device placeholder";
3106 char buffer[sizeof(wine_placeholder)-1];
3108 if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
3109 return FALSE;
3110 return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
3113 /******************************************************************************
3114 * get_device_info
3116 * Implementation of the FileFsDeviceInformation query for NtQueryVolumeInformationFile.
3118 static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
3120 struct stat st;
3122 info->Characteristics = 0;
3123 if (fstat( fd, &st ) < 0) return FILE_GetNtStatus();
3124 if (S_ISCHR( st.st_mode ))
3126 info->DeviceType = FILE_DEVICE_UNKNOWN;
3127 #ifdef linux
3128 switch(major(st.st_rdev))
3130 case MEM_MAJOR:
3131 info->DeviceType = FILE_DEVICE_NULL;
3132 break;
3133 case TTY_MAJOR:
3134 info->DeviceType = FILE_DEVICE_SERIAL_PORT;
3135 break;
3136 case LP_MAJOR:
3137 info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
3138 break;
3139 case SCSI_TAPE_MAJOR:
3140 info->DeviceType = FILE_DEVICE_TAPE;
3141 break;
3143 #endif
3145 else if (S_ISBLK( st.st_mode ))
3147 info->DeviceType = FILE_DEVICE_DISK;
3149 else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
3151 info->DeviceType = FILE_DEVICE_NAMED_PIPE;
3153 else if (is_device_placeholder( fd ))
3155 info->DeviceType = FILE_DEVICE_DISK;
3157 else /* regular file or directory */
3159 #if defined(linux) && defined(HAVE_FSTATFS)
3160 struct statfs stfs;
3162 /* check for floppy disk */
3163 if (major(st.st_dev) == FLOPPY_MAJOR)
3164 info->Characteristics |= FILE_REMOVABLE_MEDIA;
3166 if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
3167 switch (stfs.f_type)
3169 case 0x9660: /* iso9660 */
3170 case 0x9fa1: /* supermount */
3171 case 0x15013346: /* udf */
3172 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
3173 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
3174 break;
3175 case 0x6969: /* nfs */
3176 case 0xff534d42: /* cifs */
3177 case 0xfe534d42: /* smb2 */
3178 case 0x517b: /* smbfs */
3179 case 0x564c: /* ncpfs */
3180 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
3181 info->Characteristics |= FILE_REMOTE_DEVICE;
3182 break;
3183 case 0x01021994: /* tmpfs */
3184 case 0x28cd3d45: /* cramfs */
3185 case 0x1373: /* devfs */
3186 case 0x9fa0: /* procfs */
3187 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
3188 break;
3189 default:
3190 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3191 break;
3193 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
3194 struct statfs stfs;
3196 if (fstatfs( fd, &stfs ) < 0)
3197 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3198 else
3199 get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags );
3200 #elif defined(__NetBSD__)
3201 struct statvfs stfs;
3203 if (fstatvfs( fd, &stfs) < 0)
3204 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3205 else
3206 get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag );
3207 #elif defined(sun)
3208 /* Use dkio to work out device types */
3210 # include <sys/dkio.h>
3211 # include <sys/vtoc.h>
3212 struct dk_cinfo dkinf;
3213 int retval = ioctl(fd, DKIOCINFO, &dkinf);
3214 if(retval==-1){
3215 WARN("Unable to get disk device type information - assuming a disk like device\n");
3216 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3218 switch (dkinf.dki_ctype)
3220 case DKC_CDROM:
3221 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
3222 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
3223 break;
3224 case DKC_NCRFLOPPY:
3225 case DKC_SMSFLOPPY:
3226 case DKC_INTEL82072:
3227 case DKC_INTEL82077:
3228 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3229 info->Characteristics |= FILE_REMOVABLE_MEDIA;
3230 break;
3231 case DKC_MD:
3232 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
3233 break;
3234 default:
3235 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3238 #else
3239 static int warned;
3240 if (!warned++) FIXME( "device info not properly supported on this platform\n" );
3241 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3242 #endif
3243 info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
3245 return STATUS_SUCCESS;
3248 /******************************************************************************
3249 * NtQueryVolumeInformationFile [NTDLL.@]
3250 * ZwQueryVolumeInformationFile [NTDLL.@]
3252 * Get volume information for an open file handle.
3254 * PARAMS
3255 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
3256 * io [O] Receives information about the operation on return
3257 * buffer [O] Destination for volume information
3258 * length [I] Size of FsInformation
3259 * info_class [I] Type of volume information to set
3261 * RETURNS
3262 * Success: 0. io and buffer are updated.
3263 * Failure: An NTSTATUS error code describing the error.
3265 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
3266 PVOID buffer, ULONG length,
3267 FS_INFORMATION_CLASS info_class )
3269 int fd, needs_close;
3270 struct stat st;
3272 io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL );
3273 if (io->u.Status == STATUS_BAD_DEVICE_TYPE)
3275 SERVER_START_REQ( get_volume_info )
3277 req->handle = wine_server_obj_handle( handle );
3278 req->info_class = info_class;
3279 wine_server_set_reply( req, buffer, length );
3280 io->u.Status = wine_server_call( req );
3281 if (!io->u.Status) io->Information = wine_server_reply_size( reply );
3283 SERVER_END_REQ;
3284 return io->u.Status;
3286 else if (io->u.Status) return io->u.Status;
3288 io->u.Status = STATUS_NOT_IMPLEMENTED;
3289 io->Information = 0;
3291 switch( info_class )
3293 case FileFsLabelInformation:
3294 FIXME( "%p: label info not supported\n", handle );
3295 break;
3296 case FileFsSizeInformation:
3297 if (length < sizeof(FILE_FS_SIZE_INFORMATION))
3298 io->u.Status = STATUS_BUFFER_TOO_SMALL;
3299 else
3301 FILE_FS_SIZE_INFORMATION *info = buffer;
3303 if (fstat( fd, &st ) < 0)
3305 io->u.Status = FILE_GetNtStatus();
3306 break;
3308 if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
3310 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
3312 else
3314 ULONGLONG bsize;
3315 /* Linux's fstatvfs is buggy */
3316 #if !defined(linux) || !defined(HAVE_FSTATFS)
3317 struct statvfs stfs;
3319 if (fstatvfs( fd, &stfs ) < 0)
3321 io->u.Status = FILE_GetNtStatus();
3322 break;
3324 bsize = stfs.f_frsize;
3325 #else
3326 struct statfs stfs;
3327 if (fstatfs( fd, &stfs ) < 0)
3329 io->u.Status = FILE_GetNtStatus();
3330 break;
3332 bsize = stfs.f_bsize;
3333 #endif
3334 if (bsize == 2048) /* assume CD-ROM */
3336 info->BytesPerSector = 2048;
3337 info->SectorsPerAllocationUnit = 1;
3339 else
3341 info->BytesPerSector = 512;
3342 info->SectorsPerAllocationUnit = 8;
3344 info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit);
3345 info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit);
3346 io->Information = sizeof(*info);
3347 io->u.Status = STATUS_SUCCESS;
3350 break;
3351 case FileFsDeviceInformation:
3352 if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
3353 io->u.Status = STATUS_BUFFER_TOO_SMALL;
3354 else
3356 FILE_FS_DEVICE_INFORMATION *info = buffer;
3358 if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS)
3359 io->Information = sizeof(*info);
3361 break;
3362 case FileFsAttributeInformation:
3364 static const WCHAR fatW[] = {'F','A','T'};
3365 static const WCHAR fat32W[] = {'F','A','T','3','2'};
3366 static const WCHAR ntfsW[] = {'N','T','F','S'};
3367 static const WCHAR cdfsW[] = {'C','D','F','S'};
3368 static const WCHAR udfW[] = {'U','D','F'};
3370 FILE_FS_ATTRIBUTE_INFORMATION *info = buffer;
3371 struct mountmgr_unix_drive *drive;
3372 enum mountmgr_fs_type fs_type = MOUNTMGR_FS_TYPE_NTFS;
3374 if (length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
3376 io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
3377 break;
3380 if ((drive = get_mountmgr_fs_info( handle, fd )))
3382 fs_type = drive->fs_type;
3383 RtlFreeHeap( GetProcessHeap(), 0, drive );
3385 else
3387 struct statfs stfs;
3389 if (!fstatfs( fd, &stfs ))
3391 #if defined(linux) && defined(HAVE_FSTATFS)
3392 switch (stfs.f_type)
3394 case 0x9660:
3395 fs_type = MOUNTMGR_FS_TYPE_ISO9660;
3396 break;
3397 case 0x15013346:
3398 fs_type = MOUNTMGR_FS_TYPE_UDF;
3399 break;
3400 case 0x4d44:
3401 fs_type = MOUNTMGR_FS_TYPE_FAT32;
3402 break;
3404 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
3405 if (!strcmp( stfs.f_fstypename, "cd9660" ))
3406 fs_type = MOUNTMGR_FS_TYPE_ISO9660;
3407 else if (!strcmp( stfs.f_fstypename, "udf" ))
3408 fs_type = MOUNTMGR_FS_TYPE_UDF;
3409 else if (!strcmp( stfs.f_fstypename, "msdos" ))
3410 fs_type = MOUNTMGR_FS_TYPE_FAT32;
3411 #endif
3415 switch (fs_type)
3417 case MOUNTMGR_FS_TYPE_ISO9660:
3418 info->FileSystemAttributes = FILE_READ_ONLY_VOLUME;
3419 info->MaximumComponentNameLength = 221;
3420 info->FileSystemNameLength = min( sizeof(cdfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
3421 memcpy(info->FileSystemName, cdfsW, info->FileSystemNameLength);
3422 break;
3423 case MOUNTMGR_FS_TYPE_UDF:
3424 info->FileSystemAttributes = FILE_READ_ONLY_VOLUME | FILE_UNICODE_ON_DISK | FILE_CASE_SENSITIVE_SEARCH;
3425 info->MaximumComponentNameLength = 255;
3426 info->FileSystemNameLength = min( sizeof(udfW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
3427 memcpy(info->FileSystemName, udfW, info->FileSystemNameLength);
3428 break;
3429 case MOUNTMGR_FS_TYPE_FAT:
3430 info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */
3431 info->MaximumComponentNameLength = 255;
3432 info->FileSystemNameLength = min( sizeof(fatW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
3433 memcpy(info->FileSystemName, fatW, info->FileSystemNameLength);
3434 break;
3435 case MOUNTMGR_FS_TYPE_FAT32:
3436 info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */
3437 info->MaximumComponentNameLength = 255;
3438 info->FileSystemNameLength = min( sizeof(fat32W), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
3439 memcpy(info->FileSystemName, fat32W, info->FileSystemNameLength);
3440 break;
3441 default:
3442 info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS;
3443 info->MaximumComponentNameLength = 255;
3444 info->FileSystemNameLength = min( sizeof(ntfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
3445 memcpy(info->FileSystemName, ntfsW, info->FileSystemNameLength);
3446 break;
3449 io->Information = offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) + info->FileSystemNameLength;
3450 io->u.Status = STATUS_SUCCESS;
3451 break;
3453 case FileFsVolumeInformation:
3455 FILE_FS_VOLUME_INFORMATION *info = buffer;
3456 struct mountmgr_unix_drive *drive;
3457 const WCHAR *label;
3459 if (length < sizeof(FILE_FS_VOLUME_INFORMATION))
3461 io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
3462 break;
3465 if (!(drive = get_mountmgr_fs_info( handle, fd )))
3467 io->u.Status = STATUS_NOT_IMPLEMENTED;
3468 break;
3471 label = (WCHAR *)((char *)drive + drive->label_offset);
3472 info->VolumeCreationTime.QuadPart = 0; /* FIXME */
3473 info->VolumeSerialNumber = drive->serial;
3474 info->VolumeLabelLength = min( wcslen( label ) * sizeof(WCHAR),
3475 length - offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) );
3476 info->SupportsObjects = (drive->fs_type == MOUNTMGR_FS_TYPE_NTFS);
3477 memcpy( info->VolumeLabel, label, info->VolumeLabelLength );
3478 RtlFreeHeap( GetProcessHeap(), 0, drive );
3480 io->Information = offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) + info->VolumeLabelLength;
3481 io->u.Status = STATUS_SUCCESS;
3482 break;
3484 case FileFsControlInformation:
3485 FIXME( "%p: control info not supported\n", handle );
3486 break;
3487 case FileFsFullSizeInformation:
3488 FIXME( "%p: full size info not supported\n", handle );
3489 break;
3490 case FileFsObjectIdInformation:
3491 FIXME( "%p: object id info not supported\n", handle );
3492 break;
3493 case FileFsMaximumInformation:
3494 FIXME( "%p: maximum info not supported\n", handle );
3495 break;
3496 default:
3497 io->u.Status = STATUS_INVALID_PARAMETER;
3498 break;
3500 if (needs_close) close( fd );
3501 return io->u.Status;
3505 /******************************************************************
3506 * NtQueryEaFile (NTDLL.@)
3508 * Read extended attributes from NTFS files.
3510 * PARAMS
3511 * hFile [I] File handle, must be opened with FILE_READ_EA access
3512 * iosb [O] Receives information about the operation on return
3513 * buffer [O] Output buffer
3514 * length [I] Length of output buffer
3515 * single_entry [I] Only read and return one entry
3516 * ea_list [I] Optional list with names of EAs to return
3517 * ea_list_len [I] Length of ea_list in bytes
3518 * ea_index [I] Optional pointer to 1-based index of attribute to return
3519 * restart [I] restart EA scan
3521 * RETURNS
3522 * Success: 0. Attributes read into buffer
3523 * Failure: An NTSTATUS error code describing the error.
3525 NTSTATUS WINAPI NtQueryEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length,
3526 BOOLEAN single_entry, PVOID ea_list, ULONG ea_list_len,
3527 PULONG ea_index, BOOLEAN restart )
3529 FIXME("(%p,%p,%p,%d,%d,%p,%d,%p,%d) stub\n",
3530 hFile, iosb, buffer, length, single_entry, ea_list,
3531 ea_list_len, ea_index, restart);
3532 return STATUS_ACCESS_DENIED;
3536 /******************************************************************
3537 * NtSetEaFile (NTDLL.@)
3539 * Update extended attributes for NTFS files.
3541 * PARAMS
3542 * hFile [I] File handle, must be opened with FILE_READ_EA access
3543 * iosb [O] Receives information about the operation on return
3544 * buffer [I] Buffer with EA information
3545 * length [I] Length of buffer
3547 * RETURNS
3548 * Success: 0. Attributes are updated
3549 * Failure: An NTSTATUS error code describing the error.
3551 NTSTATUS WINAPI NtSetEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length )
3553 FIXME("(%p,%p,%p,%d) stub\n", hFile, iosb, buffer, length);
3554 return STATUS_ACCESS_DENIED;
3558 /******************************************************************
3559 * NtFlushBuffersFile (NTDLL.@)
3561 * Flush any buffered data on an open file handle.
3563 * PARAMS
3564 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
3565 * IoStatusBlock [O] Receives information about the operation on return
3567 * RETURNS
3568 * Success: 0. IoStatusBlock is updated.
3569 * Failure: An NTSTATUS error code describing the error.
3571 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK *io )
3573 NTSTATUS ret;
3574 HANDLE wait_handle;
3575 enum server_fd_type type;
3576 int fd, needs_close;
3578 if (!io || !virtual_check_buffer_for_write( io, sizeof(*io) )) return STATUS_ACCESS_VIOLATION;
3580 ret = server_get_unix_fd( hFile, FILE_WRITE_DATA, &fd, &needs_close, &type, NULL );
3581 if (ret == STATUS_ACCESS_DENIED)
3582 ret = server_get_unix_fd( hFile, FILE_APPEND_DATA, &fd, &needs_close, &type, NULL );
3584 if (!ret && type == FD_TYPE_SERIAL)
3586 ret = COMM_FlushBuffersFile( fd );
3588 else if (ret != STATUS_ACCESS_DENIED)
3590 struct async_irp *async;
3592 if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), irp_completion, hFile )))
3593 return STATUS_NO_MEMORY;
3594 async->buffer = NULL;
3595 async->size = 0;
3597 SERVER_START_REQ( flush )
3599 req->async = server_async( hFile, &async->io, NULL, NULL, NULL, io );
3600 ret = wine_server_call( req );
3601 wait_handle = wine_server_ptr_handle( reply->event );
3602 if (wait_handle && ret != STATUS_PENDING)
3604 io->u.Status = ret;
3605 io->Information = 0;
3608 SERVER_END_REQ;
3610 if (ret != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
3612 if (wait_handle) ret = wait_async( wait_handle, FALSE, io );
3615 if (needs_close) close( fd );
3616 return ret;
3619 /******************************************************************
3620 * NtLockFile (NTDLL.@)
3624 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
3625 PIO_APC_ROUTINE apc, void* apc_user,
3626 PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
3627 PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
3628 BOOLEAN exclusive )
3630 NTSTATUS ret;
3631 HANDLE handle;
3632 BOOLEAN async;
3633 static BOOLEAN warn = TRUE;
3635 if (apc || io_status || key)
3637 FIXME("Unimplemented yet parameter\n");
3638 return STATUS_NOT_IMPLEMENTED;
3641 if (apc_user && warn)
3643 FIXME("I/O completion on lock not implemented yet\n");
3644 warn = FALSE;
3647 for (;;)
3649 SERVER_START_REQ( lock_file )
3651 req->handle = wine_server_obj_handle( hFile );
3652 req->offset = offset->QuadPart;
3653 req->count = count->QuadPart;
3654 req->shared = !exclusive;
3655 req->wait = !dont_wait;
3656 ret = wine_server_call( req );
3657 handle = wine_server_ptr_handle( reply->handle );
3658 async = reply->overlapped;
3660 SERVER_END_REQ;
3661 if (ret != STATUS_PENDING)
3663 if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
3664 return ret;
3667 if (async)
3669 FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
3670 if (handle) NtClose( handle );
3671 return STATUS_PENDING;
3673 if (handle)
3675 NtWaitForSingleObject( handle, FALSE, NULL );
3676 NtClose( handle );
3678 else
3680 LARGE_INTEGER time;
3682 /* Unix lock conflict, sleep a bit and retry */
3683 time.QuadPart = 100 * (ULONGLONG)10000;
3684 time.QuadPart = -time.QuadPart;
3685 NtDelayExecution( FALSE, &time );
3691 /******************************************************************
3692 * NtUnlockFile (NTDLL.@)
3696 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
3697 PLARGE_INTEGER offset, PLARGE_INTEGER count,
3698 PULONG key )
3700 NTSTATUS status;
3702 TRACE( "%p %x%08x %x%08x\n",
3703 hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
3705 if (io_status || key)
3707 FIXME("Unimplemented yet parameter\n");
3708 return STATUS_NOT_IMPLEMENTED;
3711 SERVER_START_REQ( unlock_file )
3713 req->handle = wine_server_obj_handle( hFile );
3714 req->offset = offset->QuadPart;
3715 req->count = count->QuadPart;
3716 status = wine_server_call( req );
3718 SERVER_END_REQ;
3719 return status;
3722 /******************************************************************
3723 * NtCreateNamedPipeFile (NTDLL.@)
3727 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
3728 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
3729 ULONG sharing, ULONG dispo, ULONG options,
3730 ULONG pipe_type, ULONG read_mode,
3731 ULONG completion_mode, ULONG max_inst,
3732 ULONG inbound_quota, ULONG outbound_quota,
3733 PLARGE_INTEGER timeout)
3735 NTSTATUS status;
3736 data_size_t len;
3737 struct object_attributes *objattr;
3739 if (!attr) return STATUS_INVALID_PARAMETER;
3741 TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n",
3742 handle, access, debugstr_us(attr->ObjectName), iosb, sharing, dispo,
3743 options, pipe_type, read_mode, completion_mode, max_inst, inbound_quota,
3744 outbound_quota, timeout);
3746 /* assume we only get relative timeout */
3747 if (timeout->QuadPart > 0)
3748 FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
3750 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
3752 SERVER_START_REQ( create_named_pipe )
3754 req->access = access;
3755 req->options = options;
3756 req->sharing = sharing;
3757 req->flags =
3758 (pipe_type ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0) |
3759 (read_mode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0) |
3760 (completion_mode ? NAMED_PIPE_NONBLOCKING_MODE : 0);
3761 req->maxinstances = max_inst;
3762 req->outsize = outbound_quota;
3763 req->insize = inbound_quota;
3764 req->timeout = timeout->QuadPart;
3765 wine_server_add_data( req, objattr, len );
3766 status = wine_server_call( req );
3767 if (!status) *handle = wine_server_ptr_handle( reply->handle );
3769 SERVER_END_REQ;
3771 RtlFreeHeap( GetProcessHeap(), 0, objattr );
3772 return status;
3775 /******************************************************************
3776 * NtDeleteFile (NTDLL.@)
3780 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
3782 NTSTATUS status;
3783 HANDLE hFile;
3784 IO_STATUS_BLOCK io;
3786 TRACE("%p\n", ObjectAttributes);
3787 status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE | DELETE,
3788 ObjectAttributes, &io, NULL, 0,
3789 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
3790 FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
3791 if (status == STATUS_SUCCESS) status = NtClose(hFile);
3792 return status;
3795 /******************************************************************
3796 * NtCancelIoFileEx (NTDLL.@)
3800 NTSTATUS WINAPI NtCancelIoFileEx( HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status )
3802 TRACE("%p %p %p\n", hFile, iosb, io_status );
3804 SERVER_START_REQ( cancel_async )
3806 req->handle = wine_server_obj_handle( hFile );
3807 req->iosb = wine_server_client_ptr( iosb );
3808 req->only_thread = FALSE;
3809 io_status->u.Status = wine_server_call( req );
3811 SERVER_END_REQ;
3813 return io_status->u.Status;
3816 /******************************************************************
3817 * NtCancelIoFile (NTDLL.@)
3821 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
3823 TRACE("%p %p\n", hFile, io_status );
3825 SERVER_START_REQ( cancel_async )
3827 req->handle = wine_server_obj_handle( hFile );
3828 req->iosb = 0;
3829 req->only_thread = TRUE;
3830 io_status->u.Status = wine_server_call( req );
3832 SERVER_END_REQ;
3834 return io_status->u.Status;
3837 /******************************************************************************
3838 * NtCreateMailslotFile [NTDLL.@]
3839 * ZwCreateMailslotFile [NTDLL.@]
3841 * PARAMS
3842 * pHandle [O] pointer to receive the handle created
3843 * DesiredAccess [I] access mode (read, write, etc)
3844 * ObjectAttributes [I] fully qualified NT path of the mailslot
3845 * IoStatusBlock [O] receives completion status and other info
3846 * CreateOptions [I]
3847 * MailslotQuota [I]
3848 * MaxMessageSize [I]
3849 * TimeOut [I]
3851 * RETURNS
3852 * An NT status code
3854 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
3855 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
3856 ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
3857 PLARGE_INTEGER TimeOut)
3859 LARGE_INTEGER timeout;
3860 NTSTATUS ret;
3861 data_size_t len;
3862 struct object_attributes *objattr;
3864 TRACE("%p %08x %p %p %08x %08x %08x %p\n",
3865 pHandle, DesiredAccess, attr, IoStatusBlock,
3866 CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
3868 if (!pHandle) return STATUS_ACCESS_VIOLATION;
3869 if (!attr) return STATUS_INVALID_PARAMETER;
3871 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
3874 * For a NULL TimeOut pointer set the default timeout value
3876 if (!TimeOut)
3877 timeout.QuadPart = -1;
3878 else
3879 timeout.QuadPart = TimeOut->QuadPart;
3881 SERVER_START_REQ( create_mailslot )
3883 req->access = DesiredAccess;
3884 req->max_msgsize = MaxMessageSize;
3885 req->read_timeout = timeout.QuadPart;
3886 wine_server_add_data( req, objattr, len );
3887 ret = wine_server_call( req );
3888 if( ret == STATUS_SUCCESS )
3889 *pHandle = wine_server_ptr_handle( reply->handle );
3891 SERVER_END_REQ;
3893 RtlFreeHeap( GetProcessHeap(), 0, objattr );
3894 return ret;