TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / ntdll / file.c
blob1027b54720fd5f6b559217c22dd0d88bd1f847cd
1 /*
2 * Copyright 1999, 2000 Juergen Schmied
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include "wine/port.h"
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <assert.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_LINUX_MAJOR_H
31 # include <linux/major.h>
32 #endif
33 #ifdef HAVE_SYS_STATVFS_H
34 # include <sys/statvfs.h>
35 #endif
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
39 #ifdef HAVE_SYS_SYSCALL_H
40 # include <sys/syscall.h>
41 #endif
42 #ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 #endif
45 #ifdef HAVE_SYS_IOCTL_H
46 #include <sys/ioctl.h>
47 #endif
48 #ifdef HAVE_SYS_FILIO_H
49 # include <sys/filio.h>
50 #endif
51 #ifdef HAVE_POLL_H
52 #include <poll.h>
53 #endif
54 #ifdef HAVE_SYS_POLL_H
55 #include <sys/poll.h>
56 #endif
57 #ifdef HAVE_SYS_SOCKET_H
58 #include <sys/socket.h>
59 #endif
60 #ifdef HAVE_UTIME_H
61 # include <utime.h>
62 #endif
63 #ifdef HAVE_SYS_VFS_H
64 /* Work around a conflict with Solaris' system list defined in sys/list.h. */
65 #define list SYSLIST
66 #define list_next SYSLIST_NEXT
67 #define list_prev SYSLIST_PREV
68 #define list_head SYSLIST_HEAD
69 #define list_tail SYSLIST_TAIL
70 #define list_move_tail SYSLIST_MOVE_TAIL
71 #define list_remove SYSLIST_REMOVE
72 # include <sys/vfs.h>
73 #undef list
74 #undef list_next
75 #undef list_prev
76 #undef list_head
77 #undef list_tail
78 #undef list_move_tail
79 #undef list_remove
80 #endif
81 #ifdef HAVE_SYS_MOUNT_H
82 # include <sys/mount.h>
83 #endif
84 #ifdef HAVE_SYS_STATFS_H
85 # include <sys/statfs.h>
86 #endif
87 #ifdef HAVE_TERMIOS_H
88 #include <termios.h>
89 #endif
90 #ifdef HAVE_VALGRIND_MEMCHECK_H
91 # include <valgrind/memcheck.h>
92 #endif
94 #include "ntstatus.h"
95 #define WIN32_NO_STATUS
96 #define NONAMELESSUNION
97 #include "wine/unicode.h"
98 #include "wine/debug.h"
99 #include "wine/server.h"
100 #include "ntdll_misc.h"
102 #include "winternl.h"
103 #include "winioctl.h"
104 #include "ddk/ntddk.h"
105 #include "ddk/ntddser.h"
107 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
108 WINE_DECLARE_DEBUG_CHANNEL(winediag);
110 mode_t FILE_umask = 0;
112 #define SECSPERDAY 86400
113 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
115 #define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1)
116 #define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
118 static const WCHAR ntfsW[] = {'N','T','F','S'};
120 /* fetch the attributes of a file */
121 static inline ULONG get_file_attributes( const struct stat *st )
123 ULONG attr;
125 if (S_ISDIR(st->st_mode))
126 attr = FILE_ATTRIBUTE_DIRECTORY;
127 else
128 attr = FILE_ATTRIBUTE_ARCHIVE;
129 if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
130 attr |= FILE_ATTRIBUTE_READONLY;
131 return attr;
134 /* get the stat info and file attributes for a file (by file descriptor) */
135 int fd_get_file_info( int fd, struct stat *st, ULONG *attr )
137 int ret;
139 *attr = 0;
140 ret = fstat( fd, st );
141 if (ret == -1) return ret;
142 *attr |= get_file_attributes( st );
143 return ret;
146 /* get the stat info and file attributes for a file (by name) */
147 int get_file_info( const char *path, struct stat *st, ULONG *attr )
149 int ret;
151 *attr = 0;
152 ret = lstat( path, st );
153 if (ret == -1) return ret;
154 if (S_ISLNK( st->st_mode ))
156 ret = stat( path, st );
157 if (ret == -1) return ret;
158 /* is a symbolic link and a directory, consider these "reparse points" */
159 if (S_ISDIR( st->st_mode )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
161 *attr |= get_file_attributes( st );
162 return ret;
165 /**************************************************************************
166 * FILE_CreateFile (internal)
167 * Open a file.
169 * Parameter set fully identical with NtCreateFile
171 static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
172 PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
173 ULONG attributes, ULONG sharing, ULONG disposition,
174 ULONG options, PVOID ea_buffer, ULONG ea_length )
176 ANSI_STRING unix_name;
177 BOOL created = FALSE;
179 TRACE("handle=%p access=%08x name=%s objattr=%08x root=%p sec=%p io=%p alloc_size=%p "
180 "attr=%08x sharing=%08x disp=%d options=%08x ea=%p.0x%08x\n",
181 handle, access, debugstr_us(attr->ObjectName), attr->Attributes,
182 attr->RootDirectory, attr->SecurityDescriptor, io, alloc_size,
183 attributes, sharing, disposition, options, ea_buffer, ea_length );
185 if (!attr || !attr->ObjectName) return STATUS_INVALID_PARAMETER;
187 if (alloc_size) FIXME( "alloc_size not supported\n" );
189 if (options & FILE_OPEN_BY_FILE_ID)
190 io->u.Status = file_id_to_unix_file_name( attr, &unix_name );
191 else
192 io->u.Status = nt_to_unix_file_name_attr( attr, &unix_name, disposition );
194 if (io->u.Status == STATUS_BAD_DEVICE_TYPE)
196 SERVER_START_REQ( open_file_object )
198 req->access = access;
199 req->attributes = attr->Attributes;
200 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
201 req->sharing = sharing;
202 req->options = options;
203 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
204 io->u.Status = wine_server_call( req );
205 *handle = wine_server_ptr_handle( reply->handle );
207 SERVER_END_REQ;
208 if (io->u.Status == STATUS_SUCCESS) io->Information = FILE_OPENED;
209 return io->u.Status;
212 if (io->u.Status == STATUS_NO_SUCH_FILE &&
213 disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
215 created = TRUE;
216 io->u.Status = STATUS_SUCCESS;
219 if (io->u.Status == STATUS_SUCCESS)
221 struct security_descriptor *sd;
222 struct object_attributes objattr;
224 objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
225 objattr.name_len = 0;
226 io->u.Status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
227 if (io->u.Status != STATUS_SUCCESS)
229 RtlFreeAnsiString( &unix_name );
230 return io->u.Status;
233 SERVER_START_REQ( create_file )
235 req->access = access;
236 req->attributes = attr->Attributes;
237 req->sharing = sharing;
238 req->create = disposition;
239 req->options = options;
240 req->attrs = attributes;
241 wine_server_add_data( req, &objattr, sizeof(objattr) );
242 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
243 wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
244 io->u.Status = wine_server_call( req );
245 *handle = wine_server_ptr_handle( reply->handle );
247 SERVER_END_REQ;
248 NTDLL_free_struct_sd( sd );
249 RtlFreeAnsiString( &unix_name );
251 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
253 if (io->u.Status == STATUS_SUCCESS)
255 if (created) io->Information = FILE_CREATED;
256 else switch(disposition)
258 case FILE_SUPERSEDE:
259 io->Information = FILE_SUPERSEDED;
260 break;
261 case FILE_CREATE:
262 io->Information = FILE_CREATED;
263 break;
264 case FILE_OPEN:
265 case FILE_OPEN_IF:
266 io->Information = FILE_OPENED;
267 break;
268 case FILE_OVERWRITE:
269 case FILE_OVERWRITE_IF:
270 io->Information = FILE_OVERWRITTEN;
271 break;
274 else if (io->u.Status == STATUS_TOO_MANY_OPENED_FILES)
276 static int once;
277 if (!once++) ERR_(winediag)( "Too many open files, ulimit -n probably needs to be increased\n" );
280 return io->u.Status;
283 /**************************************************************************
284 * NtOpenFile [NTDLL.@]
285 * ZwOpenFile [NTDLL.@]
287 * Open a file.
289 * PARAMS
290 * handle [O] Variable that receives the file handle on return
291 * access [I] Access desired by the caller to the file
292 * attr [I] Structure describing the file to be opened
293 * io [O] Receives details about the result of the operation
294 * sharing [I] Type of shared access the caller requires
295 * options [I] Options for the file open
297 * RETURNS
298 * Success: 0. FileHandle and IoStatusBlock are updated.
299 * Failure: An NTSTATUS error code describing the error.
301 NTSTATUS WINAPI NtOpenFile( PHANDLE handle, ACCESS_MASK access,
302 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK io,
303 ULONG sharing, ULONG options )
305 return FILE_CreateFile( handle, access, attr, io, NULL, 0,
306 sharing, FILE_OPEN, options, NULL, 0 );
309 /**************************************************************************
310 * NtCreateFile [NTDLL.@]
311 * ZwCreateFile [NTDLL.@]
313 * Either create a new file or directory, or open an existing file, device,
314 * directory or volume.
316 * PARAMS
317 * handle [O] Points to a variable which receives the file handle on return
318 * access [I] Desired access to the file
319 * attr [I] Structure describing the file
320 * io [O] Receives information about the operation on return
321 * alloc_size [I] Initial size of the file in bytes
322 * attributes [I] Attributes to create the file with
323 * sharing [I] Type of shared access the caller would like to the file
324 * disposition [I] Specifies what to do, depending on whether the file already exists
325 * options [I] Options for creating a new file
326 * ea_buffer [I] Pointer to an extended attributes buffer
327 * ea_length [I] Length of ea_buffer
329 * RETURNS
330 * Success: 0. handle and io are updated.
331 * Failure: An NTSTATUS error code describing the error.
333 NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
334 PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
335 ULONG attributes, ULONG sharing, ULONG disposition,
336 ULONG options, PVOID ea_buffer, ULONG ea_length )
338 return FILE_CreateFile( handle, access, attr, io, alloc_size, attributes,
339 sharing, disposition, options, ea_buffer, ea_length );
342 /***********************************************************************
343 * Asynchronous file I/O *
346 struct async_fileio
348 struct async_fileio *next;
349 HANDLE handle;
350 PIO_APC_ROUTINE apc;
351 void *apc_arg;
354 struct async_fileio_read
356 struct async_fileio io;
357 char* buffer;
358 unsigned int already;
359 unsigned int count;
360 BOOL avail_mode;
363 struct async_fileio_write
365 struct async_fileio io;
366 const char *buffer;
367 unsigned int already;
368 unsigned int count;
371 struct async_irp
373 struct async_fileio io;
374 HANDLE event; /* async event */
375 void *buffer; /* buffer for output */
376 ULONG size; /* size of buffer */
379 static struct async_fileio *fileio_freelist;
381 static void release_fileio( struct async_fileio *io )
383 for (;;)
385 struct async_fileio *next = fileio_freelist;
386 io->next = next;
387 if (interlocked_cmpxchg_ptr( (void **)&fileio_freelist, io, next ) == next) return;
391 static struct async_fileio *alloc_fileio( DWORD size, HANDLE handle, PIO_APC_ROUTINE apc, void *arg )
393 /* first free remaining previous fileinfos */
395 struct async_fileio *io = interlocked_xchg_ptr( (void **)&fileio_freelist, NULL );
397 while (io)
399 struct async_fileio *next = io->next;
400 RtlFreeHeap( GetProcessHeap(), 0, io );
401 io = next;
404 if ((io = RtlAllocateHeap( GetProcessHeap(), 0, size )))
406 io->handle = handle;
407 io->apc = apc;
408 io->apc_arg = arg;
410 return io;
413 /* callback for irp async I/O completion */
414 static NTSTATUS irp_completion( void *user, IO_STATUS_BLOCK *io, NTSTATUS status, void **apc, void **arg )
416 struct async_irp *async = user;
418 if (status == STATUS_ALERTED)
420 SERVER_START_REQ( get_irp_result )
422 req->handle = wine_server_obj_handle( async->io.handle );
423 req->user_arg = wine_server_client_ptr( async );
424 wine_server_set_reply( req, async->buffer, async->size );
425 status = wine_server_call( req );
426 if (status != STATUS_PENDING) io->Information = reply->size;
428 SERVER_END_REQ;
430 if (status != STATUS_PENDING)
432 io->u.Status = status;
433 *apc = async->io.apc;
434 *arg = async->io.apc_arg;
435 release_fileio( &async->io );
437 return status;
440 /***********************************************************************
441 * FILE_GetNtStatus(void)
443 * Retrieve the Nt Status code from errno.
444 * Try to be consistent with FILE_SetDosError().
446 NTSTATUS FILE_GetNtStatus(void)
448 int err = errno;
450 TRACE( "errno = %d\n", errno );
451 switch (err)
453 case EAGAIN: return STATUS_SHARING_VIOLATION;
454 case EBADF: return STATUS_INVALID_HANDLE;
455 case EBUSY: return STATUS_DEVICE_BUSY;
456 case ENOSPC: return STATUS_DISK_FULL;
457 case EPERM:
458 case EROFS:
459 case EACCES: return STATUS_ACCESS_DENIED;
460 case ENOTDIR: return STATUS_OBJECT_PATH_NOT_FOUND;
461 case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND;
462 case EISDIR: return STATUS_FILE_IS_A_DIRECTORY;
463 case EMFILE:
464 case ENFILE: return STATUS_TOO_MANY_OPENED_FILES;
465 case EINVAL: return STATUS_INVALID_PARAMETER;
466 case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
467 case EPIPE: return STATUS_PIPE_DISCONNECTED;
468 case EIO: return STATUS_DEVICE_NOT_READY;
469 #ifdef ENOMEDIUM
470 case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE;
471 #endif
472 case ENXIO: return STATUS_NO_SUCH_DEVICE;
473 case ENOTTY:
474 case EOPNOTSUPP:return STATUS_NOT_SUPPORTED;
475 case ECONNRESET:return STATUS_PIPE_DISCONNECTED;
476 case EFAULT: return STATUS_ACCESS_VIOLATION;
477 case ESPIPE: return STATUS_ILLEGAL_FUNCTION;
478 #ifdef ETIME /* Missing on FreeBSD */
479 case ETIME: return STATUS_IO_TIMEOUT;
480 #endif
481 case ENOEXEC: /* ?? */
482 case EEXIST: /* ?? */
483 default:
484 FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
485 return STATUS_UNSUCCESSFUL;
489 /***********************************************************************
490 * FILE_AsyncReadService (INTERNAL)
492 static NTSTATUS FILE_AsyncReadService( void *user, IO_STATUS_BLOCK *iosb,
493 NTSTATUS status, void **apc, void **arg )
495 struct async_fileio_read *fileio = user;
496 int fd, needs_close, result;
498 switch (status)
500 case STATUS_ALERTED: /* got some new data */
501 /* check to see if the data is ready (non-blocking) */
502 if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
503 &needs_close, NULL, NULL )))
504 break;
506 result = read(fd, &fileio->buffer[fileio->already], fileio->count - fileio->already);
507 if (needs_close) close( fd );
509 if (result < 0)
511 if (errno == EAGAIN || errno == EINTR)
512 status = STATUS_PENDING;
513 else /* check to see if the transfer is complete */
514 status = FILE_GetNtStatus();
516 else if (result == 0)
518 status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN;
520 else
522 fileio->already += result;
523 if (fileio->already >= fileio->count || fileio->avail_mode)
524 status = STATUS_SUCCESS;
525 else
527 /* if we only have to read the available data, and none is available,
528 * simply cancel the request. If data was available, it has been read
529 * while in by previous call (NtDelayExecution)
531 status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING;
534 break;
536 case STATUS_TIMEOUT:
537 case STATUS_IO_TIMEOUT:
538 if (fileio->already) status = STATUS_SUCCESS;
539 break;
541 if (status != STATUS_PENDING)
543 iosb->u.Status = status;
544 iosb->Information = fileio->already;
545 *apc = fileio->io.apc;
546 *arg = fileio->io.apc_arg;
547 release_fileio( &fileio->io );
549 return status;
552 /* do a read call through the server */
553 static NTSTATUS server_read_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_context,
554 IO_STATUS_BLOCK *io, void *buffer, ULONG size,
555 LARGE_INTEGER *offset, ULONG *key )
557 struct async_irp *async;
558 NTSTATUS status;
559 HANDLE wait_handle;
560 ULONG options;
561 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
563 if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), handle, apc, apc_context )))
564 return STATUS_NO_MEMORY;
566 async->event = event;
567 async->buffer = buffer;
568 async->size = size;
570 SERVER_START_REQ( read )
572 req->blocking = !apc && !event && !cvalue;
573 req->async.handle = wine_server_obj_handle( handle );
574 req->async.callback = wine_server_client_ptr( irp_completion );
575 req->async.iosb = wine_server_client_ptr( io );
576 req->async.arg = wine_server_client_ptr( async );
577 req->async.event = wine_server_obj_handle( event );
578 req->async.cvalue = cvalue;
579 req->pos = offset ? offset->QuadPart : 0;
580 wine_server_set_reply( req, buffer, size );
581 status = wine_server_call( req );
582 wait_handle = wine_server_ptr_handle( reply->wait );
583 options = reply->options;
584 if (status != STATUS_PENDING) io->Information = wine_server_reply_size( reply );
586 SERVER_END_REQ;
588 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
590 if (wait_handle)
592 NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL );
593 status = io->u.Status;
594 NtClose( wait_handle );
597 return status;
600 /* do a write call through the server */
601 static NTSTATUS server_write_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_context,
602 IO_STATUS_BLOCK *io, const void *buffer, ULONG size,
603 LARGE_INTEGER *offset, ULONG *key )
605 struct async_irp *async;
606 NTSTATUS status;
607 HANDLE wait_handle;
608 ULONG options;
609 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
611 if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), handle, apc, apc_context )))
612 return STATUS_NO_MEMORY;
614 async->event = event;
615 async->buffer = NULL;
616 async->size = 0;
618 SERVER_START_REQ( write )
620 req->blocking = !apc && !event && !cvalue;
621 req->async.handle = wine_server_obj_handle( handle );
622 req->async.callback = wine_server_client_ptr( irp_completion );
623 req->async.iosb = wine_server_client_ptr( io );
624 req->async.arg = wine_server_client_ptr( async );
625 req->async.event = wine_server_obj_handle( event );
626 req->async.cvalue = cvalue;
627 req->pos = offset ? offset->QuadPart : 0;
628 wine_server_add_data( req, buffer, size );
629 status = wine_server_call( req );
630 wait_handle = wine_server_ptr_handle( reply->wait );
631 options = reply->options;
632 if (status != STATUS_PENDING) io->Information = reply->size;
634 SERVER_END_REQ;
636 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
638 if (wait_handle)
640 NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL );
641 status = io->u.Status;
642 NtClose( wait_handle );
645 return status;
648 struct io_timeouts
650 int interval; /* max interval between two bytes */
651 int total; /* total timeout for the whole operation */
652 int end_time; /* absolute time of end of operation */
655 /* retrieve the I/O timeouts to use for a given handle */
656 static NTSTATUS get_io_timeouts( HANDLE handle, enum server_fd_type type, ULONG count, BOOL is_read,
657 struct io_timeouts *timeouts )
659 NTSTATUS status = STATUS_SUCCESS;
661 timeouts->interval = timeouts->total = -1;
663 switch(type)
665 case FD_TYPE_SERIAL:
667 /* GetCommTimeouts */
668 SERIAL_TIMEOUTS st;
669 IO_STATUS_BLOCK io;
671 status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
672 IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
673 if (status) break;
675 if (is_read)
677 if (st.ReadIntervalTimeout)
678 timeouts->interval = st.ReadIntervalTimeout;
680 if (st.ReadTotalTimeoutMultiplier || st.ReadTotalTimeoutConstant)
682 timeouts->total = st.ReadTotalTimeoutConstant;
683 if (st.ReadTotalTimeoutMultiplier != MAXDWORD)
684 timeouts->total += count * st.ReadTotalTimeoutMultiplier;
686 else if (st.ReadIntervalTimeout == MAXDWORD)
687 timeouts->interval = timeouts->total = 0;
689 else /* write */
691 if (st.WriteTotalTimeoutMultiplier || st.WriteTotalTimeoutConstant)
693 timeouts->total = st.WriteTotalTimeoutConstant;
694 if (st.WriteTotalTimeoutMultiplier != MAXDWORD)
695 timeouts->total += count * st.WriteTotalTimeoutMultiplier;
699 break;
700 case FD_TYPE_MAILSLOT:
701 if (is_read)
703 timeouts->interval = 0; /* return as soon as we got something */
704 SERVER_START_REQ( set_mailslot_info )
706 req->handle = wine_server_obj_handle( handle );
707 req->flags = 0;
708 if (!(status = wine_server_call( req )) &&
709 reply->read_timeout != TIMEOUT_INFINITE)
710 timeouts->total = reply->read_timeout / -10000;
712 SERVER_END_REQ;
714 break;
715 case FD_TYPE_SOCKET:
716 case FD_TYPE_PIPE:
717 case FD_TYPE_CHAR:
718 if (is_read) timeouts->interval = 0; /* return as soon as we got something */
719 break;
720 default:
721 break;
723 if (timeouts->total != -1) timeouts->end_time = NtGetTickCount() + timeouts->total;
724 return STATUS_SUCCESS;
728 /* retrieve the timeout for the next wait, in milliseconds */
729 static inline int get_next_io_timeout( const struct io_timeouts *timeouts, ULONG already )
731 int ret = -1;
733 if (timeouts->total != -1)
735 ret = timeouts->end_time - NtGetTickCount();
736 if (ret < 0) ret = 0;
738 if (already && timeouts->interval != -1)
740 if (ret == -1 || ret > timeouts->interval) ret = timeouts->interval;
742 return ret;
746 /* retrieve the avail_mode flag for async reads */
747 static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL *avail_mode )
749 NTSTATUS status = STATUS_SUCCESS;
751 switch(type)
753 case FD_TYPE_SERIAL:
755 /* GetCommTimeouts */
756 SERIAL_TIMEOUTS st;
757 IO_STATUS_BLOCK io;
759 status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
760 IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
761 if (status) break;
762 *avail_mode = (!st.ReadTotalTimeoutMultiplier &&
763 !st.ReadTotalTimeoutConstant &&
764 st.ReadIntervalTimeout == MAXDWORD);
766 break;
767 case FD_TYPE_MAILSLOT:
768 case FD_TYPE_SOCKET:
769 case FD_TYPE_PIPE:
770 case FD_TYPE_CHAR:
771 *avail_mode = TRUE;
772 break;
773 default:
774 *avail_mode = FALSE;
775 break;
777 return status;
781 /******************************************************************************
782 * NtReadFile [NTDLL.@]
783 * ZwReadFile [NTDLL.@]
785 * Read from an open file handle.
787 * PARAMS
788 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
789 * Event [I] Event to signal upon completion (or NULL)
790 * ApcRoutine [I] Callback to call upon completion (or NULL)
791 * ApcContext [I] Context for ApcRoutine (or NULL)
792 * IoStatusBlock [O] Receives information about the operation on return
793 * Buffer [O] Destination for the data read
794 * Length [I] Size of Buffer
795 * ByteOffset [O] Destination for the new file pointer position (or NULL)
796 * Key [O] Function unknown (may be NULL)
798 * RETURNS
799 * Success: 0. IoStatusBlock is updated, and the Information member contains
800 * The number of bytes read.
801 * Failure: An NTSTATUS error code describing the error.
803 NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
804 PIO_APC_ROUTINE apc, void* apc_user,
805 PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
806 PLARGE_INTEGER offset, PULONG key)
808 int result, unix_handle, needs_close;
809 unsigned int options;
810 struct io_timeouts timeouts;
811 NTSTATUS status;
812 ULONG total = 0;
813 enum server_fd_type type;
814 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
815 BOOL send_completion = FALSE, async_read, timeout_init_done = FALSE;
817 TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
818 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
820 if (!io_status) return STATUS_ACCESS_VIOLATION;
822 status = server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
823 &needs_close, &type, &options );
824 if (status == STATUS_BAD_DEVICE_TYPE)
825 return server_read_file( hFile, hEvent, apc, apc_user, io_status, buffer, length, offset, key );
827 if (status) return status;
829 async_read = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
831 if (!virtual_check_buffer_for_write( buffer, length ))
833 status = STATUS_ACCESS_VIOLATION;
834 goto done;
837 if (type == FD_TYPE_FILE)
839 if (async_read && (!offset || offset->QuadPart < 0))
841 status = STATUS_INVALID_PARAMETER;
842 goto done;
845 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
847 /* async I/O doesn't make sense on regular files */
848 while ((result = pread( unix_handle, buffer, length, offset->QuadPart )) == -1)
850 if (errno != EINTR)
852 status = FILE_GetNtStatus();
853 goto done;
856 if (!async_read)
857 /* update file pointer position */
858 lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
860 total = result;
861 status = (total || !length) ? STATUS_SUCCESS : STATUS_END_OF_FILE;
862 goto done;
865 else if (type == FD_TYPE_SERIAL || type == FD_TYPE_DEVICE)
867 if (async_read && (!offset || offset->QuadPart < 0))
869 status = STATUS_INVALID_PARAMETER;
870 goto done;
874 for (;;)
876 if ((result = read( unix_handle, (char *)buffer + total, length - total )) >= 0)
878 total += result;
879 if (!result || total == length)
881 if (total)
883 status = STATUS_SUCCESS;
884 goto done;
886 switch (type)
888 case FD_TYPE_FILE:
889 case FD_TYPE_CHAR:
890 case FD_TYPE_DEVICE:
891 status = length ? STATUS_END_OF_FILE : STATUS_SUCCESS;
892 goto done;
893 case FD_TYPE_SERIAL:
894 break;
895 default:
896 status = STATUS_PIPE_BROKEN;
897 goto done;
900 else if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
902 else if (errno != EAGAIN)
904 if (errno == EINTR) continue;
905 if (!total) status = FILE_GetNtStatus();
906 goto done;
909 if (async_read)
911 struct async_fileio_read *fileio;
912 BOOL avail_mode;
914 if ((status = get_io_avail_mode( hFile, type, &avail_mode )))
915 goto err;
916 if (total && avail_mode)
918 status = STATUS_SUCCESS;
919 goto done;
922 fileio = (struct async_fileio_read *)alloc_fileio( sizeof(*fileio), hFile, apc, apc_user );
923 if (!fileio)
925 status = STATUS_NO_MEMORY;
926 goto err;
928 fileio->already = total;
929 fileio->count = length;
930 fileio->buffer = buffer;
931 fileio->avail_mode = avail_mode;
933 SERVER_START_REQ( register_async )
935 req->type = ASYNC_TYPE_READ;
936 req->count = length;
937 req->async.handle = wine_server_obj_handle( hFile );
938 req->async.event = wine_server_obj_handle( hEvent );
939 req->async.callback = wine_server_client_ptr( FILE_AsyncReadService );
940 req->async.iosb = wine_server_client_ptr( io_status );
941 req->async.arg = wine_server_client_ptr( fileio );
942 req->async.cvalue = cvalue;
943 status = wine_server_call( req );
945 SERVER_END_REQ;
947 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
948 goto err;
950 else /* synchronous read, wait for the fd to become ready */
952 struct pollfd pfd;
953 int ret, timeout;
955 if (!timeout_init_done)
957 timeout_init_done = TRUE;
958 if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts )))
959 goto err;
960 if (hEvent) NtResetEvent( hEvent, NULL );
962 timeout = get_next_io_timeout( &timeouts, total );
964 pfd.fd = unix_handle;
965 pfd.events = POLLIN;
967 if (!timeout || !(ret = poll( &pfd, 1, timeout )))
969 if (total) /* return with what we got so far */
970 status = STATUS_SUCCESS;
971 else
972 status = (type == FD_TYPE_MAILSLOT) ? STATUS_IO_TIMEOUT : STATUS_TIMEOUT;
973 goto done;
975 if (ret == -1 && errno != EINTR)
977 status = FILE_GetNtStatus();
978 goto done;
980 /* will now restart the read */
984 done:
985 send_completion = cvalue != 0;
987 err:
988 if (needs_close) close( unix_handle );
989 if (status == STATUS_SUCCESS || (status == STATUS_END_OF_FILE && !async_read))
991 io_status->u.Status = status;
992 io_status->Information = total;
993 TRACE("= SUCCESS (%u)\n", total);
994 if (hEvent) NtSetEvent( hEvent, NULL );
995 if (apc && !status) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
996 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
998 else
1000 TRACE("= 0x%08x\n", status);
1001 if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
1004 if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total );
1006 return status;
1010 /******************************************************************************
1011 * NtReadFileScatter [NTDLL.@]
1012 * ZwReadFileScatter [NTDLL.@]
1014 NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1015 PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
1016 ULONG length, PLARGE_INTEGER offset, PULONG key )
1018 int result, unix_handle, needs_close;
1019 unsigned int options;
1020 NTSTATUS status;
1021 ULONG pos = 0, total = 0;
1022 enum server_fd_type type;
1023 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1024 BOOL send_completion = FALSE;
1026 TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
1027 file, event, apc, apc_user, io_status, segments, length, offset, key);
1029 if (length % page_size) return STATUS_INVALID_PARAMETER;
1030 if (!io_status) return STATUS_ACCESS_VIOLATION;
1032 status = server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
1033 &needs_close, &type, &options );
1034 if (status) return status;
1036 if ((type != FD_TYPE_FILE) ||
1037 (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
1038 !(options & FILE_NO_INTERMEDIATE_BUFFERING))
1040 status = STATUS_INVALID_PARAMETER;
1041 goto error;
1044 while (length)
1046 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
1047 result = pread( unix_handle, (char *)segments->Buffer + pos,
1048 page_size - pos, offset->QuadPart + total );
1049 else
1050 result = read( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
1052 if (result == -1)
1054 if (errno == EINTR) continue;
1055 status = FILE_GetNtStatus();
1056 break;
1058 if (!result)
1060 status = STATUS_END_OF_FILE;
1061 break;
1063 total += result;
1064 length -= result;
1065 if ((pos += result) == page_size)
1067 pos = 0;
1068 segments++;
1072 send_completion = cvalue != 0;
1074 error:
1075 if (needs_close) close( unix_handle );
1076 if (status == STATUS_SUCCESS)
1078 io_status->u.Status = status;
1079 io_status->Information = total;
1080 TRACE("= SUCCESS (%u)\n", total);
1081 if (event) NtSetEvent( event, NULL );
1082 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1083 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1085 else
1087 TRACE("= 0x%08x\n", status);
1088 if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
1091 if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total );
1093 return status;
1097 /***********************************************************************
1098 * FILE_AsyncWriteService (INTERNAL)
1100 static NTSTATUS FILE_AsyncWriteService( void *user, IO_STATUS_BLOCK *iosb,
1101 NTSTATUS status, void **apc, void **arg )
1103 struct async_fileio_write *fileio = user;
1104 int result, fd, needs_close;
1105 enum server_fd_type type;
1107 switch (status)
1109 case STATUS_ALERTED:
1110 /* write some data (non-blocking) */
1111 if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
1112 &needs_close, &type, NULL )))
1113 break;
1115 if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
1116 result = send( fd, fileio->buffer, 0, 0 );
1117 else
1118 result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already );
1120 if (needs_close) close( fd );
1122 if (result < 0)
1124 if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING;
1125 else status = FILE_GetNtStatus();
1127 else
1129 fileio->already += result;
1130 status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
1132 break;
1134 case STATUS_TIMEOUT:
1135 case STATUS_IO_TIMEOUT:
1136 if (fileio->already) status = STATUS_SUCCESS;
1137 break;
1139 if (status != STATUS_PENDING)
1141 iosb->u.Status = status;
1142 iosb->Information = fileio->already;
1143 *apc = fileio->io.apc;
1144 *arg = fileio->io.apc_arg;
1145 release_fileio( &fileio->io );
1147 return status;
1150 static NTSTATUS set_pending_write( HANDLE device )
1152 NTSTATUS status;
1154 SERVER_START_REQ( set_serial_info )
1156 req->handle = wine_server_obj_handle( device );
1157 req->flags = SERIALINFO_PENDING_WRITE;
1158 status = wine_server_call( req );
1160 SERVER_END_REQ;
1161 return status;
1164 /******************************************************************************
1165 * NtWriteFile [NTDLL.@]
1166 * ZwWriteFile [NTDLL.@]
1168 * Write to an open file handle.
1170 * PARAMS
1171 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1172 * Event [I] Event to signal upon completion (or NULL)
1173 * ApcRoutine [I] Callback to call upon completion (or NULL)
1174 * ApcContext [I] Context for ApcRoutine (or NULL)
1175 * IoStatusBlock [O] Receives information about the operation on return
1176 * Buffer [I] Source for the data to write
1177 * Length [I] Size of Buffer
1178 * ByteOffset [O] Destination for the new file pointer position (or NULL)
1179 * Key [O] Function unknown (may be NULL)
1181 * RETURNS
1182 * Success: 0. IoStatusBlock is updated, and the Information member contains
1183 * The number of bytes written.
1184 * Failure: An NTSTATUS error code describing the error.
1186 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
1187 PIO_APC_ROUTINE apc, void* apc_user,
1188 PIO_STATUS_BLOCK io_status,
1189 const void* buffer, ULONG length,
1190 PLARGE_INTEGER offset, PULONG key)
1192 int result, unix_handle, needs_close;
1193 unsigned int options;
1194 struct io_timeouts timeouts;
1195 NTSTATUS status;
1196 ULONG total = 0;
1197 enum server_fd_type type;
1198 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1199 BOOL send_completion = FALSE, async_write, append_write = FALSE, timeout_init_done = FALSE;
1200 LARGE_INTEGER offset_eof;
1202 TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)!\n",
1203 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
1205 if (!io_status) return STATUS_ACCESS_VIOLATION;
1207 status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
1208 &needs_close, &type, &options );
1209 if (status == STATUS_BAD_DEVICE_TYPE)
1210 return server_write_file( hFile, hEvent, apc, apc_user, io_status, buffer, length, offset, key );
1212 if (status == STATUS_ACCESS_DENIED)
1214 status = server_get_unix_fd( hFile, FILE_APPEND_DATA, &unix_handle,
1215 &needs_close, &type, &options );
1216 append_write = TRUE;
1218 if (status) return status;
1220 if (!virtual_check_buffer_for_read( buffer, length ))
1222 status = STATUS_INVALID_USER_BUFFER;
1223 goto done;
1226 async_write = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
1228 if (type == FD_TYPE_FILE)
1230 if (async_write &&
1231 (!offset || (offset->QuadPart < 0 && offset->QuadPart != FILE_WRITE_TO_END_OF_FILE)))
1233 status = STATUS_INVALID_PARAMETER;
1234 goto done;
1237 if (append_write)
1239 offset_eof.QuadPart = FILE_WRITE_TO_END_OF_FILE;
1240 offset = &offset_eof;
1243 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
1245 off_t off = offset->QuadPart;
1247 if (offset->QuadPart == FILE_WRITE_TO_END_OF_FILE)
1249 struct stat st;
1251 if (fstat( unix_handle, &st ) == -1)
1253 status = FILE_GetNtStatus();
1254 goto done;
1256 off = st.st_size;
1258 else if (offset->QuadPart < 0)
1260 status = STATUS_INVALID_PARAMETER;
1261 goto done;
1264 /* async I/O doesn't make sense on regular files */
1265 while ((result = pwrite( unix_handle, buffer, length, off )) == -1)
1267 if (errno != EINTR)
1269 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
1270 else status = FILE_GetNtStatus();
1271 goto done;
1275 if (!async_write)
1276 /* update file pointer position */
1277 lseek( unix_handle, off + result, SEEK_SET );
1279 total = result;
1280 status = STATUS_SUCCESS;
1281 goto done;
1284 else if (type == FD_TYPE_SERIAL || type == FD_TYPE_DEVICE)
1286 if (async_write &&
1287 (!offset || (offset->QuadPart < 0 && offset->QuadPart != FILE_WRITE_TO_END_OF_FILE)))
1289 status = STATUS_INVALID_PARAMETER;
1290 goto done;
1294 for (;;)
1296 /* zero-length writes on sockets may not work with plain write(2) */
1297 if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
1298 result = send( unix_handle, buffer, 0, 0 );
1299 else
1300 result = write( unix_handle, (const char *)buffer + total, length - total );
1302 if (result >= 0)
1304 total += result;
1305 if (total == length)
1307 status = STATUS_SUCCESS;
1308 goto done;
1310 if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
1312 else if (errno != EAGAIN)
1314 if (errno == EINTR) continue;
1315 if (!total)
1317 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
1318 else status = FILE_GetNtStatus();
1320 goto done;
1323 if (async_write)
1325 struct async_fileio_write *fileio;
1327 fileio = (struct async_fileio_write *)alloc_fileio( sizeof(*fileio), hFile, apc, apc_user );
1328 if (!fileio)
1330 status = STATUS_NO_MEMORY;
1331 goto err;
1333 fileio->already = total;
1334 fileio->count = length;
1335 fileio->buffer = buffer;
1337 SERVER_START_REQ( register_async )
1339 req->type = ASYNC_TYPE_WRITE;
1340 req->count = length;
1341 req->async.handle = wine_server_obj_handle( hFile );
1342 req->async.event = wine_server_obj_handle( hEvent );
1343 req->async.callback = wine_server_client_ptr( FILE_AsyncWriteService );
1344 req->async.iosb = wine_server_client_ptr( io_status );
1345 req->async.arg = wine_server_client_ptr( fileio );
1346 req->async.cvalue = cvalue;
1347 status = wine_server_call( req );
1349 SERVER_END_REQ;
1351 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
1352 goto err;
1354 else /* synchronous write, wait for the fd to become ready */
1356 struct pollfd pfd;
1357 int ret, timeout;
1359 if (!timeout_init_done)
1361 timeout_init_done = TRUE;
1362 if ((status = get_io_timeouts( hFile, type, length, FALSE, &timeouts )))
1363 goto err;
1364 if (hEvent) NtResetEvent( hEvent, NULL );
1366 timeout = get_next_io_timeout( &timeouts, total );
1368 pfd.fd = unix_handle;
1369 pfd.events = POLLOUT;
1371 if (!timeout || !(ret = poll( &pfd, 1, timeout )))
1373 /* return with what we got so far */
1374 status = total ? STATUS_SUCCESS : STATUS_TIMEOUT;
1375 goto done;
1377 if (ret == -1 && errno != EINTR)
1379 status = FILE_GetNtStatus();
1380 goto done;
1382 /* will now restart the write */
1386 done:
1387 send_completion = cvalue != 0;
1389 err:
1390 if (needs_close) close( unix_handle );
1392 if (type == FD_TYPE_SERIAL && (status == STATUS_SUCCESS || status == STATUS_PENDING))
1393 set_pending_write( hFile );
1395 if (status == STATUS_SUCCESS)
1397 io_status->u.Status = status;
1398 io_status->Information = total;
1399 TRACE("= SUCCESS (%u)\n", total);
1400 if (hEvent) NtSetEvent( hEvent, NULL );
1401 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1402 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1404 else
1406 TRACE("= 0x%08x\n", status);
1407 if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
1410 if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total );
1412 return status;
1416 /******************************************************************************
1417 * NtWriteFileGather [NTDLL.@]
1418 * ZwWriteFileGather [NTDLL.@]
1420 NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1421 PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
1422 ULONG length, PLARGE_INTEGER offset, PULONG key )
1424 int result, unix_handle, needs_close;
1425 unsigned int options;
1426 NTSTATUS status;
1427 ULONG pos = 0, total = 0;
1428 enum server_fd_type type;
1429 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1430 BOOL send_completion = FALSE;
1432 TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
1433 file, event, apc, apc_user, io_status, segments, length, offset, key);
1435 if (length % page_size) return STATUS_INVALID_PARAMETER;
1436 if (!io_status) return STATUS_ACCESS_VIOLATION;
1438 status = server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
1439 &needs_close, &type, &options );
1440 if (status) return status;
1442 if ((type != FD_TYPE_FILE) ||
1443 (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
1444 !(options & FILE_NO_INTERMEDIATE_BUFFERING))
1446 status = STATUS_INVALID_PARAMETER;
1447 goto error;
1450 while (length)
1452 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
1453 result = pwrite( unix_handle, (char *)segments->Buffer + pos,
1454 page_size - pos, offset->QuadPart + total );
1455 else
1456 result = write( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
1458 if (result == -1)
1460 if (errno == EINTR) continue;
1461 if (errno == EFAULT)
1463 status = STATUS_INVALID_USER_BUFFER;
1464 goto error;
1466 status = FILE_GetNtStatus();
1467 break;
1469 if (!result)
1471 status = STATUS_DISK_FULL;
1472 break;
1474 total += result;
1475 length -= result;
1476 if ((pos += result) == page_size)
1478 pos = 0;
1479 segments++;
1483 send_completion = cvalue != 0;
1485 error:
1486 if (needs_close) close( unix_handle );
1487 if (status == STATUS_SUCCESS)
1489 io_status->u.Status = status;
1490 io_status->Information = total;
1491 TRACE("= SUCCESS (%u)\n", total);
1492 if (event) NtSetEvent( event, NULL );
1493 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1494 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1496 else
1498 TRACE("= 0x%08x\n", status);
1499 if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
1502 if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total );
1504 return status;
1508 /* do an ioctl call through the server */
1509 static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
1510 PIO_APC_ROUTINE apc, PVOID apc_context,
1511 IO_STATUS_BLOCK *io, ULONG code,
1512 const void *in_buffer, ULONG in_size,
1513 PVOID out_buffer, ULONG out_size )
1515 struct async_irp *async;
1516 NTSTATUS status;
1517 HANDLE wait_handle;
1518 ULONG options;
1519 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
1521 if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), handle, apc, apc_context )))
1522 return STATUS_NO_MEMORY;
1523 async->event = event;
1524 async->buffer = out_buffer;
1525 async->size = out_size;
1527 SERVER_START_REQ( ioctl )
1529 req->code = code;
1530 req->blocking = !apc && !event && !cvalue;
1531 req->async.handle = wine_server_obj_handle( handle );
1532 req->async.callback = wine_server_client_ptr( irp_completion );
1533 req->async.iosb = wine_server_client_ptr( io );
1534 req->async.arg = wine_server_client_ptr( async );
1535 req->async.event = wine_server_obj_handle( event );
1536 req->async.cvalue = cvalue;
1537 wine_server_add_data( req, in_buffer, in_size );
1538 wine_server_set_reply( req, out_buffer, out_size );
1539 status = wine_server_call( req );
1540 wait_handle = wine_server_ptr_handle( reply->wait );
1541 options = reply->options;
1542 if (status != STATUS_PENDING) io->Information = wine_server_reply_size( reply );
1544 SERVER_END_REQ;
1546 if (status == STATUS_NOT_SUPPORTED)
1547 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
1548 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1550 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
1552 if (wait_handle)
1554 NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL );
1555 status = io->u.Status;
1556 NtClose( wait_handle );
1559 return status;
1562 /* Tell Valgrind to ignore any holes in structs we will be passing to the
1563 * server */
1564 static void ignore_server_ioctl_struct_holes (ULONG code, const void *in_buffer,
1565 ULONG in_size)
1567 #ifdef VALGRIND_MAKE_MEM_DEFINED
1568 # define IGNORE_STRUCT_HOLE(buf, size, t, f1, f2) \
1569 do { \
1570 if (FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1) < FIELD_OFFSET(t, f2)) \
1571 if ((size) >= FIELD_OFFSET(t, f2)) \
1572 VALGRIND_MAKE_MEM_DEFINED( \
1573 (const char *)(buf) + FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1), \
1574 FIELD_OFFSET(t, f2) - FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1)); \
1575 } while (0)
1577 switch (code)
1579 case FSCTL_PIPE_WAIT:
1580 IGNORE_STRUCT_HOLE(in_buffer, in_size, FILE_PIPE_WAIT_FOR_BUFFER, TimeoutSpecified, Name);
1581 break;
1583 #endif
1587 /**************************************************************************
1588 * NtDeviceIoControlFile [NTDLL.@]
1589 * ZwDeviceIoControlFile [NTDLL.@]
1591 * Perform an I/O control operation on an open file handle.
1593 * PARAMS
1594 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1595 * event [I] Event to signal upon completion (or NULL)
1596 * apc [I] Callback to call upon completion (or NULL)
1597 * apc_context [I] Context for ApcRoutine (or NULL)
1598 * io [O] Receives information about the operation on return
1599 * code [I] Control code for the operation to perform
1600 * in_buffer [I] Source for any input data required (or NULL)
1601 * in_size [I] Size of InputBuffer
1602 * out_buffer [O] Source for any output data returned (or NULL)
1603 * out_size [I] Size of OutputBuffer
1605 * RETURNS
1606 * Success: 0. IoStatusBlock is updated.
1607 * Failure: An NTSTATUS error code describing the error.
1609 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
1610 PIO_APC_ROUTINE apc, PVOID apc_context,
1611 PIO_STATUS_BLOCK io, ULONG code,
1612 PVOID in_buffer, ULONG in_size,
1613 PVOID out_buffer, ULONG out_size)
1615 ULONG device = (code >> 16);
1616 NTSTATUS status = STATUS_NOT_SUPPORTED;
1618 TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1619 handle, event, apc, apc_context, io, code,
1620 in_buffer, in_size, out_buffer, out_size);
1622 switch(device)
1624 case FILE_DEVICE_DISK:
1625 case FILE_DEVICE_CD_ROM:
1626 case FILE_DEVICE_DVD:
1627 case FILE_DEVICE_CONTROLLER:
1628 case FILE_DEVICE_MASS_STORAGE:
1629 status = CDROM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1630 in_buffer, in_size, out_buffer, out_size);
1631 break;
1632 case FILE_DEVICE_SERIAL_PORT:
1633 status = COMM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1634 in_buffer, in_size, out_buffer, out_size);
1635 break;
1636 case FILE_DEVICE_TAPE:
1637 status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
1638 in_buffer, in_size, out_buffer, out_size);
1639 break;
1642 if (status == STATUS_NOT_SUPPORTED || status == STATUS_BAD_DEVICE_TYPE)
1643 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1644 in_buffer, in_size, out_buffer, out_size );
1646 if (status != STATUS_PENDING) io->u.Status = status;
1647 return status;
1651 /**************************************************************************
1652 * NtFsControlFile [NTDLL.@]
1653 * ZwFsControlFile [NTDLL.@]
1655 * Perform a file system control operation on an open file handle.
1657 * PARAMS
1658 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1659 * event [I] Event to signal upon completion (or NULL)
1660 * apc [I] Callback to call upon completion (or NULL)
1661 * apc_context [I] Context for ApcRoutine (or NULL)
1662 * io [O] Receives information about the operation on return
1663 * code [I] Control code for the operation to perform
1664 * in_buffer [I] Source for any input data required (or NULL)
1665 * in_size [I] Size of InputBuffer
1666 * out_buffer [O] Source for any output data returned (or NULL)
1667 * out_size [I] Size of OutputBuffer
1669 * RETURNS
1670 * Success: 0. IoStatusBlock is updated.
1671 * Failure: An NTSTATUS error code describing the error.
1673 NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
1674 PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code,
1675 PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size)
1677 NTSTATUS status;
1679 TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1680 handle, event, apc, apc_context, io, code,
1681 in_buffer, in_size, out_buffer, out_size);
1683 if (!io) return STATUS_INVALID_PARAMETER;
1685 ignore_server_ioctl_struct_holes( code, in_buffer, in_size );
1687 switch(code)
1689 case FSCTL_DISMOUNT_VOLUME:
1690 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1691 in_buffer, in_size, out_buffer, out_size );
1692 if (!status) status = DIR_unmount_device( handle );
1693 break;
1695 case FSCTL_PIPE_PEEK:
1697 FILE_PIPE_PEEK_BUFFER *buffer = out_buffer;
1698 int avail = 0, fd, needs_close;
1700 if (out_size < FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ))
1702 status = STATUS_INFO_LENGTH_MISMATCH;
1703 break;
1706 if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )))
1707 break;
1709 #ifdef FIONREAD
1710 if (ioctl( fd, FIONREAD, &avail ) != 0)
1712 TRACE("FIONREAD failed reason: %s\n",strerror(errno));
1713 if (needs_close) close( fd );
1714 status = FILE_GetNtStatus();
1715 break;
1717 #endif
1718 if (!avail) /* check for closed pipe */
1720 struct pollfd pollfd;
1721 int ret;
1723 pollfd.fd = fd;
1724 pollfd.events = POLLIN;
1725 pollfd.revents = 0;
1726 ret = poll( &pollfd, 1, 0 );
1727 if (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR))))
1729 if (needs_close) close( fd );
1730 status = STATUS_PIPE_BROKEN;
1731 break;
1734 buffer->NamedPipeState = 0; /* FIXME */
1735 buffer->ReadDataAvailable = avail;
1736 buffer->NumberOfMessages = 0; /* FIXME */
1737 buffer->MessageLength = 0; /* FIXME */
1738 io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1739 status = STATUS_SUCCESS;
1740 if (avail)
1742 ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1743 if (data_size)
1745 int res = recv( fd, buffer->Data, data_size, MSG_PEEK );
1746 if (res >= 0) io->Information += res;
1749 if (needs_close) close( fd );
1751 break;
1753 case FSCTL_PIPE_DISCONNECT:
1754 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1755 in_buffer, in_size, out_buffer, out_size );
1756 if (!status)
1758 int fd = server_remove_fd_from_cache( handle );
1759 if (fd != -1) close( fd );
1761 break;
1763 case FSCTL_PIPE_IMPERSONATE:
1764 FIXME("FSCTL_PIPE_IMPERSONATE: impersonating self\n");
1765 status = RtlImpersonateSelf( SecurityImpersonation );
1766 break;
1768 case FSCTL_IS_VOLUME_MOUNTED:
1769 case FSCTL_LOCK_VOLUME:
1770 case FSCTL_UNLOCK_VOLUME:
1771 FIXME("stub! return success - Unsupported fsctl %x (device=%x access=%x func=%x method=%x)\n",
1772 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1773 status = STATUS_SUCCESS;
1774 break;
1776 case FSCTL_GET_RETRIEVAL_POINTERS:
1778 RETRIEVAL_POINTERS_BUFFER *buffer = (RETRIEVAL_POINTERS_BUFFER *)out_buffer;
1780 FIXME("stub: FSCTL_GET_RETRIEVAL_POINTERS\n");
1782 if (out_size >= sizeof(RETRIEVAL_POINTERS_BUFFER))
1784 buffer->ExtentCount = 1;
1785 buffer->StartingVcn.QuadPart = 1;
1786 buffer->Extents[0].NextVcn.QuadPart = 0;
1787 buffer->Extents[0].Lcn.QuadPart = 0;
1788 io->Information = sizeof(RETRIEVAL_POINTERS_BUFFER);
1789 status = STATUS_SUCCESS;
1791 else
1793 io->Information = 0;
1794 status = STATUS_BUFFER_TOO_SMALL;
1796 break;
1798 case FSCTL_SET_SPARSE:
1799 TRACE("FSCTL_SET_SPARSE: Ignoring request\n");
1800 io->Information = 0;
1801 status = STATUS_SUCCESS;
1802 break;
1803 case FSCTL_PIPE_LISTEN:
1804 case FSCTL_PIPE_WAIT:
1805 default:
1806 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1807 in_buffer, in_size, out_buffer, out_size );
1808 break;
1811 if (status != STATUS_PENDING) io->u.Status = status;
1812 return status;
1816 struct read_changes_fileio
1818 struct async_fileio io;
1819 void *buffer;
1820 ULONG buffer_size;
1821 ULONG data_size;
1822 char data[1];
1825 static NTSTATUS read_changes_apc( void *user, IO_STATUS_BLOCK *iosb,
1826 NTSTATUS status, void **apc, void **arg )
1828 struct read_changes_fileio *fileio = user;
1829 int size = 0;
1831 if (status == STATUS_ALERTED)
1833 SERVER_START_REQ( read_change )
1835 req->handle = wine_server_obj_handle( fileio->io.handle );
1836 wine_server_set_reply( req, fileio->data, fileio->data_size );
1837 status = wine_server_call( req );
1838 size = wine_server_reply_size( reply );
1840 SERVER_END_REQ;
1842 if (status == STATUS_SUCCESS && fileio->buffer)
1844 FILE_NOTIFY_INFORMATION *pfni = fileio->buffer;
1845 int i, left = fileio->buffer_size;
1846 DWORD *last_entry_offset = NULL;
1847 struct filesystem_event *event = (struct filesystem_event*)fileio->data;
1849 while (size && left >= sizeof(*pfni))
1851 /* convert to an NT style path */
1852 for (i = 0; i < event->len; i++)
1853 if (event->name[i] == '/') event->name[i] = '\\';
1855 pfni->Action = event->action;
1856 pfni->FileNameLength = ntdll_umbstowcs( 0, event->name, event->len, pfni->FileName,
1857 (left - offsetof(FILE_NOTIFY_INFORMATION, FileName)) / sizeof(WCHAR));
1858 last_entry_offset = &pfni->NextEntryOffset;
1860 if (pfni->FileNameLength == -1 || pfni->FileNameLength == -2) break;
1862 i = offsetof(FILE_NOTIFY_INFORMATION, FileName[pfni->FileNameLength]);
1863 pfni->FileNameLength *= sizeof(WCHAR);
1864 pfni->NextEntryOffset = i;
1865 pfni = (FILE_NOTIFY_INFORMATION*)((char*)pfni + i);
1866 left -= i;
1868 i = (offsetof(struct filesystem_event, name[event->len])
1869 + sizeof(int)-1) / sizeof(int) * sizeof(int);
1870 event = (struct filesystem_event*)((char*)event + i);
1871 size -= i;
1874 if (size)
1876 status = STATUS_NOTIFY_ENUM_DIR;
1877 size = 0;
1879 else
1881 if (last_entry_offset) *last_entry_offset = 0;
1882 size = fileio->buffer_size - left;
1885 else
1887 status = STATUS_NOTIFY_ENUM_DIR;
1888 size = 0;
1892 if (status != STATUS_PENDING)
1894 iosb->u.Status = status;
1895 iosb->Information = size;
1896 *apc = fileio->io.apc;
1897 *arg = fileio->io.apc_arg;
1898 release_fileio( &fileio->io );
1900 return status;
1903 #define FILE_NOTIFY_ALL ( \
1904 FILE_NOTIFY_CHANGE_FILE_NAME | \
1905 FILE_NOTIFY_CHANGE_DIR_NAME | \
1906 FILE_NOTIFY_CHANGE_ATTRIBUTES | \
1907 FILE_NOTIFY_CHANGE_SIZE | \
1908 FILE_NOTIFY_CHANGE_LAST_WRITE | \
1909 FILE_NOTIFY_CHANGE_LAST_ACCESS | \
1910 FILE_NOTIFY_CHANGE_CREATION | \
1911 FILE_NOTIFY_CHANGE_SECURITY )
1913 /******************************************************************************
1914 * NtNotifyChangeDirectoryFile [NTDLL.@]
1916 NTSTATUS WINAPI NtNotifyChangeDirectoryFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
1917 void *apc_context, PIO_STATUS_BLOCK iosb, void *buffer,
1918 ULONG buffer_size, ULONG filter, BOOLEAN subtree )
1920 struct read_changes_fileio *fileio;
1921 NTSTATUS status;
1922 ULONG size = max( 4096, buffer_size );
1923 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
1925 TRACE( "%p %p %p %p %p %p %u %u %d\n",
1926 handle, event, apc, apc_context, iosb, buffer, buffer_size, filter, subtree );
1928 if (!iosb) return STATUS_ACCESS_VIOLATION;
1929 if (filter == 0 || (filter & ~FILE_NOTIFY_ALL)) return STATUS_INVALID_PARAMETER;
1931 fileio = (struct read_changes_fileio *)alloc_fileio( offsetof(struct read_changes_fileio, data[size]),
1932 handle, apc, apc_context );
1933 if (!fileio) return STATUS_NO_MEMORY;
1935 fileio->buffer = buffer;
1936 fileio->buffer_size = buffer_size;
1937 fileio->data_size = size;
1939 SERVER_START_REQ( read_directory_changes )
1941 req->filter = filter;
1942 req->want_data = (buffer != NULL);
1943 req->subtree = subtree;
1944 req->async.handle = wine_server_obj_handle( handle );
1945 req->async.callback = wine_server_client_ptr( read_changes_apc );
1946 req->async.iosb = wine_server_client_ptr( iosb );
1947 req->async.arg = wine_server_client_ptr( fileio );
1948 req->async.event = wine_server_obj_handle( event );
1949 req->async.cvalue = cvalue;
1950 status = wine_server_call( req );
1952 SERVER_END_REQ;
1954 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
1955 return status;
1958 /******************************************************************************
1959 * NtSetVolumeInformationFile [NTDLL.@]
1960 * ZwSetVolumeInformationFile [NTDLL.@]
1962 * Set volume information for an open file handle.
1964 * PARAMS
1965 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1966 * IoStatusBlock [O] Receives information about the operation on return
1967 * FsInformation [I] Source for volume information
1968 * Length [I] Size of FsInformation
1969 * FsInformationClass [I] Type of volume information to set
1971 * RETURNS
1972 * Success: 0. IoStatusBlock is updated.
1973 * Failure: An NTSTATUS error code describing the error.
1975 NTSTATUS WINAPI NtSetVolumeInformationFile(
1976 IN HANDLE FileHandle,
1977 PIO_STATUS_BLOCK IoStatusBlock,
1978 PVOID FsInformation,
1979 ULONG Length,
1980 FS_INFORMATION_CLASS FsInformationClass)
1982 FIXME("(%p,%p,%p,0x%08x,0x%08x) stub\n",
1983 FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
1984 return 0;
1987 #if defined(__ANDROID__) && !defined(HAVE_FUTIMENS)
1988 static int futimens( int fd, const struct timespec spec[2] )
1990 return syscall( __NR_utimensat, fd, NULL, spec, 0 );
1992 #define HAVE_FUTIMENS
1993 #endif /* __ANDROID__ */
1995 #ifndef UTIME_OMIT
1996 #define UTIME_OMIT ((1 << 30) - 2)
1997 #endif
1999 static NTSTATUS set_file_times( int fd, const LARGE_INTEGER *mtime, const LARGE_INTEGER *atime )
2001 NTSTATUS status = STATUS_SUCCESS;
2003 #ifdef HAVE_FUTIMENS
2004 struct timespec tv[2];
2006 tv[0].tv_sec = tv[1].tv_sec = 0;
2007 tv[0].tv_nsec = tv[1].tv_nsec = UTIME_OMIT;
2008 if (atime->QuadPart)
2010 tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
2011 tv[0].tv_nsec = (atime->QuadPart % 10000000) * 100;
2013 if (mtime->QuadPart)
2015 tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
2016 tv[1].tv_nsec = (mtime->QuadPart % 10000000) * 100;
2018 if (futimens( fd, tv ) == -1) status = FILE_GetNtStatus();
2020 #elif defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
2021 struct timeval tv[2];
2022 struct stat st;
2024 if (!atime->QuadPart || !mtime->QuadPart)
2027 tv[0].tv_sec = tv[0].tv_usec = 0;
2028 tv[1].tv_sec = tv[1].tv_usec = 0;
2029 if (!fstat( fd, &st ))
2031 tv[0].tv_sec = st.st_atime;
2032 tv[1].tv_sec = st.st_mtime;
2033 #ifdef HAVE_STRUCT_STAT_ST_ATIM
2034 tv[0].tv_usec = st.st_atim.tv_nsec / 1000;
2035 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
2036 tv[0].tv_usec = st.st_atimespec.tv_nsec / 1000;
2037 #endif
2038 #ifdef HAVE_STRUCT_STAT_ST_MTIM
2039 tv[1].tv_usec = st.st_mtim.tv_nsec / 1000;
2040 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
2041 tv[1].tv_usec = st.st_mtimespec.tv_nsec / 1000;
2042 #endif
2045 if (atime->QuadPart)
2047 tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
2048 tv[0].tv_usec = (atime->QuadPart % 10000000) / 10;
2050 if (mtime->QuadPart)
2052 tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
2053 tv[1].tv_usec = (mtime->QuadPart % 10000000) / 10;
2055 #ifdef HAVE_FUTIMES
2056 if (futimes( fd, tv ) == -1) status = FILE_GetNtStatus();
2057 #elif defined(HAVE_FUTIMESAT)
2058 if (futimesat( fd, NULL, tv ) == -1) status = FILE_GetNtStatus();
2059 #endif
2061 #else /* HAVE_FUTIMES || HAVE_FUTIMESAT */
2062 FIXME( "setting file times not supported\n" );
2063 status = STATUS_NOT_IMPLEMENTED;
2064 #endif
2065 return status;
2068 static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, LARGE_INTEGER *ctime,
2069 LARGE_INTEGER *atime, LARGE_INTEGER *creation )
2071 RtlSecondsSince1970ToTime( st->st_mtime, mtime );
2072 RtlSecondsSince1970ToTime( st->st_ctime, ctime );
2073 RtlSecondsSince1970ToTime( st->st_atime, atime );
2074 #ifdef HAVE_STRUCT_STAT_ST_MTIM
2075 mtime->QuadPart += st->st_mtim.tv_nsec / 100;
2076 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
2077 mtime->QuadPart += st->st_mtimespec.tv_nsec / 100;
2078 #endif
2079 #ifdef HAVE_STRUCT_STAT_ST_CTIM
2080 ctime->QuadPart += st->st_ctim.tv_nsec / 100;
2081 #elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
2082 ctime->QuadPart += st->st_ctimespec.tv_nsec / 100;
2083 #endif
2084 #ifdef HAVE_STRUCT_STAT_ST_ATIM
2085 atime->QuadPart += st->st_atim.tv_nsec / 100;
2086 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
2087 atime->QuadPart += st->st_atimespec.tv_nsec / 100;
2088 #endif
2089 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2090 RtlSecondsSince1970ToTime( st->st_birthtime, creation );
2091 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIM
2092 creation->QuadPart += st->st_birthtim.tv_nsec / 100;
2093 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
2094 creation->QuadPart += st->st_birthtimespec.tv_nsec / 100;
2095 #endif
2096 #elif defined(HAVE_STRUCT_STAT___ST_BIRTHTIME)
2097 RtlSecondsSince1970ToTime( st->__st_birthtime, creation );
2098 #ifdef HAVE_STRUCT_STAT___ST_BIRTHTIM
2099 creation->QuadPart += st->__st_birthtim.tv_nsec / 100;
2100 #endif
2101 #else
2102 *creation = *mtime;
2103 #endif
2106 /* fill in the file information that depends on the stat and attribute info */
2107 NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
2108 FILE_INFORMATION_CLASS class )
2110 switch (class)
2112 case FileBasicInformation:
2114 FILE_BASIC_INFORMATION *info = ptr;
2116 get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
2117 &info->LastAccessTime, &info->CreationTime );
2118 info->FileAttributes = attr;
2120 break;
2121 case FileStandardInformation:
2123 FILE_STANDARD_INFORMATION *info = ptr;
2125 if ((info->Directory = S_ISDIR(st->st_mode)))
2127 info->AllocationSize.QuadPart = 0;
2128 info->EndOfFile.QuadPart = 0;
2129 info->NumberOfLinks = 1;
2131 else
2133 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
2134 info->EndOfFile.QuadPart = st->st_size;
2135 info->NumberOfLinks = st->st_nlink;
2138 break;
2139 case FileInternalInformation:
2141 FILE_INTERNAL_INFORMATION *info = ptr;
2142 info->IndexNumber.QuadPart = st->st_ino;
2144 break;
2145 case FileEndOfFileInformation:
2147 FILE_END_OF_FILE_INFORMATION *info = ptr;
2148 info->EndOfFile.QuadPart = S_ISDIR(st->st_mode) ? 0 : st->st_size;
2150 break;
2151 case FileAllInformation:
2153 FILE_ALL_INFORMATION *info = ptr;
2154 fill_file_info( st, attr, &info->BasicInformation, FileBasicInformation );
2155 fill_file_info( st, attr, &info->StandardInformation, FileStandardInformation );
2156 fill_file_info( st, attr, &info->InternalInformation, FileInternalInformation );
2158 break;
2159 /* all directory structures start with the FileDirectoryInformation layout */
2160 case FileBothDirectoryInformation:
2161 case FileFullDirectoryInformation:
2162 case FileDirectoryInformation:
2164 FILE_DIRECTORY_INFORMATION *info = ptr;
2166 get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
2167 &info->LastAccessTime, &info->CreationTime );
2168 if (S_ISDIR(st->st_mode))
2170 info->AllocationSize.QuadPart = 0;
2171 info->EndOfFile.QuadPart = 0;
2173 else
2175 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
2176 info->EndOfFile.QuadPart = st->st_size;
2178 info->FileAttributes = attr;
2180 break;
2181 case FileIdFullDirectoryInformation:
2183 FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr;
2184 info->FileId.QuadPart = st->st_ino;
2185 fill_file_info( st, attr, info, FileDirectoryInformation );
2187 break;
2188 case FileIdBothDirectoryInformation:
2190 FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr;
2191 info->FileId.QuadPart = st->st_ino;
2192 fill_file_info( st, attr, info, FileDirectoryInformation );
2194 break;
2196 default:
2197 return STATUS_INVALID_INFO_CLASS;
2199 return STATUS_SUCCESS;
2202 NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name )
2204 data_size_t size = 1024;
2205 NTSTATUS ret;
2206 char *name;
2208 for (;;)
2210 name = RtlAllocateHeap( GetProcessHeap(), 0, size + 1 );
2211 if (!name) return STATUS_NO_MEMORY;
2212 unix_name->MaximumLength = size + 1;
2214 SERVER_START_REQ( get_handle_unix_name )
2216 req->handle = wine_server_obj_handle( handle );
2217 wine_server_set_reply( req, name, size );
2218 ret = wine_server_call( req );
2219 size = reply->name_len;
2221 SERVER_END_REQ;
2223 if (!ret)
2225 name[size] = 0;
2226 unix_name->Buffer = name;
2227 unix_name->Length = size;
2228 break;
2230 RtlFreeHeap( GetProcessHeap(), 0, name );
2231 if (ret != STATUS_BUFFER_OVERFLOW) break;
2233 return ret;
2236 static NTSTATUS fill_name_info( const ANSI_STRING *unix_name, FILE_NAME_INFORMATION *info, LONG *name_len )
2238 UNICODE_STRING nt_name;
2239 NTSTATUS status;
2241 if (!(status = wine_unix_to_nt_file_name( unix_name, &nt_name )))
2243 const WCHAR *ptr = nt_name.Buffer;
2244 const WCHAR *end = ptr + (nt_name.Length / sizeof(WCHAR));
2246 /* Skip the volume mount point. */
2247 while (ptr != end && *ptr == '\\') ++ptr;
2248 while (ptr != end && *ptr != '\\') ++ptr;
2249 while (ptr != end && *ptr == '\\') ++ptr;
2250 while (ptr != end && *ptr != '\\') ++ptr;
2252 info->FileNameLength = (end - ptr) * sizeof(WCHAR);
2253 if (*name_len < info->FileNameLength) status = STATUS_BUFFER_OVERFLOW;
2254 else *name_len = info->FileNameLength;
2256 memcpy( info->FileName, ptr, *name_len );
2257 RtlFreeUnicodeString( &nt_name );
2260 return status;
2263 /******************************************************************************
2264 * NtQueryInformationFile [NTDLL.@]
2265 * ZwQueryInformationFile [NTDLL.@]
2267 * Get information about an open file handle.
2269 * PARAMS
2270 * hFile [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2271 * io [O] Receives information about the operation on return
2272 * ptr [O] Destination for file information
2273 * len [I] Size of FileInformation
2274 * class [I] Type of file information to get
2276 * RETURNS
2277 * Success: 0. IoStatusBlock and FileInformation are updated.
2278 * Failure: An NTSTATUS error code describing the error.
2280 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
2281 PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
2283 static const size_t info_sizes[] =
2286 sizeof(FILE_DIRECTORY_INFORMATION), /* FileDirectoryInformation */
2287 sizeof(FILE_FULL_DIRECTORY_INFORMATION), /* FileFullDirectoryInformation */
2288 sizeof(FILE_BOTH_DIRECTORY_INFORMATION), /* FileBothDirectoryInformation */
2289 sizeof(FILE_BASIC_INFORMATION), /* FileBasicInformation */
2290 sizeof(FILE_STANDARD_INFORMATION), /* FileStandardInformation */
2291 sizeof(FILE_INTERNAL_INFORMATION), /* FileInternalInformation */
2292 sizeof(FILE_EA_INFORMATION), /* FileEaInformation */
2293 sizeof(FILE_ACCESS_INFORMATION), /* FileAccessInformation */
2294 sizeof(FILE_NAME_INFORMATION), /* FileNameInformation */
2295 sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
2296 0, /* FileLinkInformation */
2297 sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR), /* FileNamesInformation */
2298 sizeof(FILE_DISPOSITION_INFORMATION), /* FileDispositionInformation */
2299 sizeof(FILE_POSITION_INFORMATION), /* FilePositionInformation */
2300 sizeof(FILE_FULL_EA_INFORMATION), /* FileFullEaInformation */
2301 sizeof(FILE_MODE_INFORMATION), /* FileModeInformation */
2302 sizeof(FILE_ALIGNMENT_INFORMATION), /* FileAlignmentInformation */
2303 sizeof(FILE_ALL_INFORMATION), /* FileAllInformation */
2304 sizeof(FILE_ALLOCATION_INFORMATION), /* FileAllocationInformation */
2305 sizeof(FILE_END_OF_FILE_INFORMATION), /* FileEndOfFileInformation */
2306 0, /* FileAlternateNameInformation */
2307 sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
2308 sizeof(FILE_PIPE_INFORMATION), /* FilePipeInformation */
2309 sizeof(FILE_PIPE_LOCAL_INFORMATION), /* FilePipeLocalInformation */
2310 0, /* FilePipeRemoteInformation */
2311 sizeof(FILE_MAILSLOT_QUERY_INFORMATION), /* FileMailslotQueryInformation */
2312 0, /* FileMailslotSetInformation */
2313 0, /* FileCompressionInformation */
2314 0, /* FileObjectIdInformation */
2315 0, /* FileCompletionInformation */
2316 0, /* FileMoveClusterInformation */
2317 0, /* FileQuotaInformation */
2318 0, /* FileReparsePointInformation */
2319 sizeof(FILE_NETWORK_OPEN_INFORMATION), /* FileNetworkOpenInformation */
2320 0, /* FileAttributeTagInformation */
2321 0, /* FileTrackingInformation */
2322 0, /* FileIdBothDirectoryInformation */
2323 0, /* FileIdFullDirectoryInformation */
2324 0, /* FileValidDataLengthInformation */
2325 0, /* FileShortNameInformation */
2326 0, /* FileIoCompletionNotificationInformation, */
2327 0, /* FileIoStatusBlockRangeInformation */
2328 0, /* FileIoPriorityHintInformation */
2329 0, /* FileSfioReserveInformation */
2330 0, /* FileSfioVolumeInformation */
2331 0, /* FileHardLinkInformation */
2332 0, /* FileProcessIdsUsingFileInformation */
2333 0, /* FileNormalizedNameInformation */
2334 0, /* FileNetworkPhysicalNameInformation */
2335 0, /* FileIdGlobalTxDirectoryInformation */
2336 0, /* FileIsRemoteDeviceInformation */
2337 0, /* FileAttributeCacheInformation */
2338 0, /* FileNumaNodeInformation */
2339 0, /* FileStandardLinkInformation */
2340 0, /* FileRemoteProtocolInformation */
2341 0, /* FileReplaceCompletionInformation */
2344 struct stat st;
2345 int fd, needs_close = FALSE;
2346 ULONG attr;
2348 TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
2350 io->Information = 0;
2352 if (class <= 0 || class >= FileMaximumInformation)
2353 return io->u.Status = STATUS_INVALID_INFO_CLASS;
2354 if (!info_sizes[class])
2356 FIXME("Unsupported class (%d)\n", class);
2357 return io->u.Status = STATUS_NOT_IMPLEMENTED;
2359 if (len < info_sizes[class])
2360 return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
2362 if (class != FilePipeInformation && class != FilePipeLocalInformation)
2364 if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, NULL )))
2365 return io->u.Status;
2368 switch (class)
2370 case FileBasicInformation:
2371 if (fd_get_file_info( fd, &st, &attr ) == -1)
2372 io->u.Status = FILE_GetNtStatus();
2373 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2374 io->u.Status = STATUS_INVALID_INFO_CLASS;
2375 else
2376 fill_file_info( &st, attr, ptr, class );
2377 break;
2378 case FileStandardInformation:
2380 FILE_STANDARD_INFORMATION *info = ptr;
2382 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2383 else
2385 fill_file_info( &st, attr, info, class );
2386 info->DeletePending = FALSE; /* FIXME */
2389 break;
2390 case FilePositionInformation:
2392 FILE_POSITION_INFORMATION *info = ptr;
2393 off_t res = lseek( fd, 0, SEEK_CUR );
2394 if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
2395 else info->CurrentByteOffset.QuadPart = res;
2397 break;
2398 case FileInternalInformation:
2399 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2400 else fill_file_info( &st, attr, ptr, class );
2401 break;
2402 case FileEaInformation:
2404 FILE_EA_INFORMATION *info = ptr;
2405 info->EaSize = 0;
2407 break;
2408 case FileEndOfFileInformation:
2409 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2410 else fill_file_info( &st, attr, ptr, class );
2411 break;
2412 case FileAllInformation:
2414 FILE_ALL_INFORMATION *info = ptr;
2415 ANSI_STRING unix_name;
2417 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2418 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2419 io->u.Status = STATUS_INVALID_INFO_CLASS;
2420 else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2422 LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
2424 fill_file_info( &st, attr, info, FileAllInformation );
2425 info->StandardInformation.DeletePending = FALSE; /* FIXME */
2426 info->EaInformation.EaSize = 0;
2427 info->AccessInformation.AccessFlags = 0; /* FIXME */
2428 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
2429 info->ModeInformation.Mode = 0; /* FIXME */
2430 info->AlignmentInformation.AlignmentRequirement = 1; /* FIXME */
2432 io->u.Status = fill_name_info( &unix_name, &info->NameInformation, &name_len );
2433 RtlFreeAnsiString( &unix_name );
2434 io->Information = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + name_len;
2437 break;
2438 case FileMailslotQueryInformation:
2440 FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
2442 SERVER_START_REQ( set_mailslot_info )
2444 req->handle = wine_server_obj_handle( hFile );
2445 req->flags = 0;
2446 io->u.Status = wine_server_call( req );
2447 if( io->u.Status == STATUS_SUCCESS )
2449 info->MaximumMessageSize = reply->max_msgsize;
2450 info->MailslotQuota = 0;
2451 info->NextMessageSize = 0;
2452 info->MessagesAvailable = 0;
2453 info->ReadTimeout.QuadPart = reply->read_timeout;
2456 SERVER_END_REQ;
2457 if (!io->u.Status)
2459 char *tmpbuf;
2460 ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000;
2461 if (size > 0x10000) size = 0x10000;
2462 if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2464 if (!server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
2466 int res = recv( fd, tmpbuf, size, MSG_PEEK );
2467 info->MessagesAvailable = (res > 0);
2468 info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE;
2469 if (needs_close) close( fd );
2471 RtlFreeHeap( GetProcessHeap(), 0, tmpbuf );
2475 break;
2476 case FilePipeInformation:
2478 FILE_PIPE_INFORMATION* pi = ptr;
2480 SERVER_START_REQ( get_named_pipe_info )
2482 req->handle = wine_server_obj_handle( hFile );
2483 if (!(io->u.Status = wine_server_call( req )))
2485 pi->ReadMode = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_READ) ?
2486 FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
2487 pi->CompletionMode = (reply->flags & NAMED_PIPE_NONBLOCKING_MODE) ?
2488 FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
2491 SERVER_END_REQ;
2493 break;
2494 case FilePipeLocalInformation:
2496 FILE_PIPE_LOCAL_INFORMATION* pli = ptr;
2498 SERVER_START_REQ( get_named_pipe_info )
2500 req->handle = wine_server_obj_handle( hFile );
2501 if (!(io->u.Status = wine_server_call( req )))
2503 pli->NamedPipeType = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ?
2504 FILE_PIPE_TYPE_MESSAGE : FILE_PIPE_TYPE_BYTE;
2505 switch (reply->sharing)
2507 case FILE_SHARE_READ:
2508 pli->NamedPipeConfiguration = FILE_PIPE_OUTBOUND;
2509 break;
2510 case FILE_SHARE_WRITE:
2511 pli->NamedPipeConfiguration = FILE_PIPE_INBOUND;
2512 break;
2513 case FILE_SHARE_READ | FILE_SHARE_WRITE:
2514 pli->NamedPipeConfiguration = FILE_PIPE_FULL_DUPLEX;
2515 break;
2517 pli->MaximumInstances = reply->maxinstances;
2518 pli->CurrentInstances = reply->instances;
2519 pli->InboundQuota = reply->insize;
2520 pli->ReadDataAvailable = 0; /* FIXME */
2521 pli->OutboundQuota = reply->outsize;
2522 pli->WriteQuotaAvailable = 0; /* FIXME */
2523 pli->NamedPipeState = 0; /* FIXME */
2524 pli->NamedPipeEnd = (reply->flags & NAMED_PIPE_SERVER_END) ?
2525 FILE_PIPE_SERVER_END : FILE_PIPE_CLIENT_END;
2528 SERVER_END_REQ;
2530 break;
2531 case FileNameInformation:
2533 FILE_NAME_INFORMATION *info = ptr;
2534 ANSI_STRING unix_name;
2536 if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2538 LONG name_len = len - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2539 io->u.Status = fill_name_info( &unix_name, info, &name_len );
2540 RtlFreeAnsiString( &unix_name );
2541 io->Information = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + name_len;
2544 break;
2545 case FileNetworkOpenInformation:
2547 FILE_NETWORK_OPEN_INFORMATION *info = ptr;
2548 ANSI_STRING unix_name;
2550 if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2552 ULONG attributes;
2553 struct stat st;
2555 if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
2556 io->u.Status = FILE_GetNtStatus();
2557 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2558 io->u.Status = STATUS_INVALID_INFO_CLASS;
2559 else
2561 FILE_BASIC_INFORMATION basic;
2562 FILE_STANDARD_INFORMATION std;
2564 fill_file_info( &st, attributes, &basic, FileBasicInformation );
2565 fill_file_info( &st, attributes, &std, FileStandardInformation );
2567 info->CreationTime = basic.CreationTime;
2568 info->LastAccessTime = basic.LastAccessTime;
2569 info->LastWriteTime = basic.LastWriteTime;
2570 info->ChangeTime = basic.ChangeTime;
2571 info->AllocationSize = std.AllocationSize;
2572 info->EndOfFile = std.EndOfFile;
2573 info->FileAttributes = basic.FileAttributes;
2575 RtlFreeAnsiString( &unix_name );
2578 break;
2579 default:
2580 FIXME("Unsupported class (%d)\n", class);
2581 io->u.Status = STATUS_NOT_IMPLEMENTED;
2582 break;
2584 if (needs_close) close( fd );
2585 if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
2586 return io->u.Status;
2589 /******************************************************************************
2590 * NtSetInformationFile [NTDLL.@]
2591 * ZwSetInformationFile [NTDLL.@]
2593 * Set information about an open file handle.
2595 * PARAMS
2596 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2597 * io [O] Receives information about the operation on return
2598 * ptr [I] Source for file information
2599 * len [I] Size of FileInformation
2600 * class [I] Type of file information to set
2602 * RETURNS
2603 * Success: 0. io is updated.
2604 * Failure: An NTSTATUS error code describing the error.
2606 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
2607 PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
2609 int fd, needs_close;
2611 TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", handle, io, ptr, len, class);
2613 io->u.Status = STATUS_SUCCESS;
2614 switch (class)
2616 case FileBasicInformation:
2617 if (len >= sizeof(FILE_BASIC_INFORMATION))
2619 struct stat st;
2620 const FILE_BASIC_INFORMATION *info = ptr;
2622 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2623 return io->u.Status;
2625 if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
2626 io->u.Status = set_file_times( fd, &info->LastWriteTime, &info->LastAccessTime );
2628 if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
2630 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2631 else
2633 if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
2635 if (S_ISDIR( st.st_mode))
2636 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
2637 else
2638 st.st_mode &= ~0222; /* clear write permission bits */
2640 else
2642 /* add write permission only where we already have read permission */
2643 st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
2645 if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
2649 if (needs_close) close( fd );
2651 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2652 break;
2654 case FilePositionInformation:
2655 if (len >= sizeof(FILE_POSITION_INFORMATION))
2657 const FILE_POSITION_INFORMATION *info = ptr;
2659 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2660 return io->u.Status;
2662 if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
2663 io->u.Status = FILE_GetNtStatus();
2665 if (needs_close) close( fd );
2667 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2668 break;
2670 case FileEndOfFileInformation:
2671 if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
2673 struct stat st;
2674 const FILE_END_OF_FILE_INFORMATION *info = ptr;
2676 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2677 return io->u.Status;
2679 /* first try normal truncate */
2680 if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2682 /* now check for the need to extend the file */
2683 if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
2685 static const char zero;
2687 /* extend the file one byte beyond the requested size and then truncate it */
2688 /* this should work around ftruncate implementations that can't extend files */
2689 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
2690 ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2692 io->u.Status = FILE_GetNtStatus();
2694 if (needs_close) close( fd );
2696 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2697 break;
2699 case FilePipeInformation:
2700 if (len >= sizeof(FILE_PIPE_INFORMATION))
2702 FILE_PIPE_INFORMATION *info = ptr;
2704 if ((info->CompletionMode | info->ReadMode) & ~1)
2706 io->u.Status = STATUS_INVALID_PARAMETER;
2707 break;
2710 SERVER_START_REQ( set_named_pipe_info )
2712 req->handle = wine_server_obj_handle( handle );
2713 req->flags = (info->CompletionMode ? NAMED_PIPE_NONBLOCKING_MODE : 0) |
2714 (info->ReadMode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0);
2715 io->u.Status = wine_server_call( req );
2717 SERVER_END_REQ;
2719 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2720 break;
2722 case FileMailslotSetInformation:
2724 FILE_MAILSLOT_SET_INFORMATION *info = ptr;
2726 SERVER_START_REQ( set_mailslot_info )
2728 req->handle = wine_server_obj_handle( handle );
2729 req->flags = MAILSLOT_SET_READ_TIMEOUT;
2730 req->read_timeout = info->ReadTimeout.QuadPart;
2731 io->u.Status = wine_server_call( req );
2733 SERVER_END_REQ;
2735 break;
2737 case FileCompletionInformation:
2738 if (len >= sizeof(FILE_COMPLETION_INFORMATION))
2740 FILE_COMPLETION_INFORMATION *info = ptr;
2742 SERVER_START_REQ( set_completion_info )
2744 req->handle = wine_server_obj_handle( handle );
2745 req->chandle = wine_server_obj_handle( info->CompletionPort );
2746 req->ckey = info->CompletionKey;
2747 io->u.Status = wine_server_call( req );
2749 SERVER_END_REQ;
2750 } else
2751 io->u.Status = STATUS_INVALID_PARAMETER_3;
2752 break;
2754 case FileAllInformation:
2755 io->u.Status = STATUS_INVALID_INFO_CLASS;
2756 break;
2758 case FileValidDataLengthInformation:
2759 if (len >= sizeof(FILE_VALID_DATA_LENGTH_INFORMATION))
2761 struct stat st;
2762 const FILE_VALID_DATA_LENGTH_INFORMATION *info = ptr;
2764 if ((io->u.Status = server_get_unix_fd( handle, FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL )))
2765 return io->u.Status;
2767 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2768 else if (info->ValidDataLength.QuadPart <= 0 || (off_t)info->ValidDataLength.QuadPart > st.st_size)
2769 io->u.Status = STATUS_INVALID_PARAMETER;
2770 else
2772 #ifdef HAVE_FALLOCATE
2773 if (fallocate( fd, 0, 0, (off_t)info->ValidDataLength.QuadPart ) == -1)
2775 NTSTATUS status = FILE_GetNtStatus();
2776 if (status == STATUS_NOT_SUPPORTED) WARN( "fallocate not supported on this filesystem\n" );
2777 else io->u.Status = status;
2779 #else
2780 FIXME( "setting valid data length not supported\n" );
2781 #endif
2783 if (needs_close) close( fd );
2785 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2786 break;
2788 case FileDispositionInformation:
2789 if (len >= sizeof(FILE_DISPOSITION_INFORMATION))
2791 FILE_DISPOSITION_INFORMATION *info = ptr;
2793 SERVER_START_REQ( set_fd_disp_info )
2795 req->handle = wine_server_obj_handle( handle );
2796 req->unlink = info->DoDeleteFile;
2797 io->u.Status = wine_server_call( req );
2799 SERVER_END_REQ;
2800 } else
2801 io->u.Status = STATUS_INVALID_PARAMETER_3;
2802 break;
2804 case FileRenameInformation:
2805 if (len >= sizeof(FILE_RENAME_INFORMATION))
2807 FILE_RENAME_INFORMATION *info = ptr;
2808 UNICODE_STRING name_str;
2809 OBJECT_ATTRIBUTES attr;
2810 ANSI_STRING unix_name;
2812 name_str.Buffer = info->FileName;
2813 name_str.Length = info->FileNameLength;
2814 name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR);
2816 attr.Length = sizeof(attr);
2817 attr.ObjectName = &name_str;
2818 attr.RootDirectory = info->RootDir;
2819 attr.Attributes = OBJ_CASE_INSENSITIVE;
2821 io->u.Status = nt_to_unix_file_name_attr( &attr, &unix_name, FILE_OPEN_IF );
2822 if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE)
2823 break;
2825 if (!info->Replace && io->u.Status == STATUS_SUCCESS)
2827 RtlFreeAnsiString( &unix_name );
2828 io->u.Status = STATUS_OBJECT_NAME_COLLISION;
2829 break;
2832 SERVER_START_REQ( set_fd_name_info )
2834 req->handle = wine_server_obj_handle( handle );
2835 req->rootdir = wine_server_obj_handle( attr.RootDirectory );
2836 req->link = FALSE;
2837 wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
2838 io->u.Status = wine_server_call( req );
2840 SERVER_END_REQ;
2842 RtlFreeAnsiString( &unix_name );
2844 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2845 break;
2847 case FileLinkInformation:
2848 if (len >= sizeof(FILE_LINK_INFORMATION))
2850 FILE_LINK_INFORMATION *info = ptr;
2851 UNICODE_STRING name_str;
2852 OBJECT_ATTRIBUTES attr;
2853 ANSI_STRING unix_name;
2855 name_str.Buffer = info->FileName;
2856 name_str.Length = info->FileNameLength;
2857 name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR);
2859 attr.Length = sizeof(attr);
2860 attr.ObjectName = &name_str;
2861 attr.RootDirectory = info->RootDirectory;
2862 attr.Attributes = OBJ_CASE_INSENSITIVE;
2864 io->u.Status = nt_to_unix_file_name_attr( &attr, &unix_name, FILE_OPEN_IF );
2865 if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE)
2866 break;
2868 if (!info->ReplaceIfExists && io->u.Status == STATUS_SUCCESS)
2870 RtlFreeAnsiString( &unix_name );
2871 io->u.Status = STATUS_OBJECT_NAME_COLLISION;
2872 break;
2875 SERVER_START_REQ( set_fd_name_info )
2877 req->handle = wine_server_obj_handle( handle );
2878 req->rootdir = wine_server_obj_handle( attr.RootDirectory );
2879 req->link = TRUE;
2880 wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
2881 io->u.Status = wine_server_call( req );
2883 SERVER_END_REQ;
2885 RtlFreeAnsiString( &unix_name );
2887 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2888 break;
2890 default:
2891 FIXME("Unsupported class (%d)\n", class);
2892 io->u.Status = STATUS_NOT_IMPLEMENTED;
2893 break;
2895 io->Information = 0;
2896 return io->u.Status;
2900 /******************************************************************************
2901 * NtQueryFullAttributesFile (NTDLL.@)
2903 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
2904 FILE_NETWORK_OPEN_INFORMATION *info )
2906 ANSI_STRING unix_name;
2907 NTSTATUS status;
2909 if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2911 ULONG attributes;
2912 struct stat st;
2914 if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
2915 status = FILE_GetNtStatus();
2916 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2917 status = STATUS_INVALID_INFO_CLASS;
2918 else
2920 FILE_BASIC_INFORMATION basic;
2921 FILE_STANDARD_INFORMATION std;
2923 fill_file_info( &st, attributes, &basic, FileBasicInformation );
2924 fill_file_info( &st, attributes, &std, FileStandardInformation );
2926 info->CreationTime = basic.CreationTime;
2927 info->LastAccessTime = basic.LastAccessTime;
2928 info->LastWriteTime = basic.LastWriteTime;
2929 info->ChangeTime = basic.ChangeTime;
2930 info->AllocationSize = std.AllocationSize;
2931 info->EndOfFile = std.EndOfFile;
2932 info->FileAttributes = basic.FileAttributes;
2933 if (DIR_is_hidden_file( attr->ObjectName ))
2934 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2936 RtlFreeAnsiString( &unix_name );
2938 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2939 return status;
2943 /******************************************************************************
2944 * NtQueryAttributesFile (NTDLL.@)
2945 * ZwQueryAttributesFile (NTDLL.@)
2947 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
2949 ANSI_STRING unix_name;
2950 NTSTATUS status;
2952 if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2954 ULONG attributes;
2955 struct stat st;
2957 if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
2958 status = FILE_GetNtStatus();
2959 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2960 status = STATUS_INVALID_INFO_CLASS;
2961 else
2963 status = fill_file_info( &st, attributes, info, FileBasicInformation );
2964 if (DIR_is_hidden_file( attr->ObjectName ))
2965 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2967 RtlFreeAnsiString( &unix_name );
2969 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2970 return status;
2974 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2975 /* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */
2976 static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename,
2977 unsigned int flags )
2979 if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename))
2981 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2982 /* Don't assume read-only, let the mount options set it below */
2983 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2985 else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) ||
2986 !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename))
2988 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2989 info->Characteristics |= FILE_REMOTE_DEVICE;
2991 else if (!strcmp("procfs", fstypename))
2992 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2993 else
2994 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2996 if (flags & MNT_RDONLY)
2997 info->Characteristics |= FILE_READ_ONLY_DEVICE;
2999 if (!(flags & MNT_LOCAL))
3001 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
3002 info->Characteristics |= FILE_REMOTE_DEVICE;
3005 #endif
3007 static inline BOOL is_device_placeholder( int fd )
3009 static const char wine_placeholder[] = "Wine device placeholder";
3010 char buffer[sizeof(wine_placeholder)-1];
3012 if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
3013 return FALSE;
3014 return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
3017 /******************************************************************************
3018 * get_device_info
3020 * Implementation of the FileFsDeviceInformation query for NtQueryVolumeInformationFile.
3022 static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
3024 struct stat st;
3026 info->Characteristics = 0;
3027 if (fstat( fd, &st ) < 0) return FILE_GetNtStatus();
3028 if (S_ISCHR( st.st_mode ))
3030 info->DeviceType = FILE_DEVICE_UNKNOWN;
3031 #ifdef linux
3032 switch(major(st.st_rdev))
3034 case MEM_MAJOR:
3035 info->DeviceType = FILE_DEVICE_NULL;
3036 break;
3037 case TTY_MAJOR:
3038 info->DeviceType = FILE_DEVICE_SERIAL_PORT;
3039 break;
3040 case LP_MAJOR:
3041 info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
3042 break;
3043 case SCSI_TAPE_MAJOR:
3044 info->DeviceType = FILE_DEVICE_TAPE;
3045 break;
3047 #endif
3049 else if (S_ISBLK( st.st_mode ))
3051 info->DeviceType = FILE_DEVICE_DISK;
3053 else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
3055 info->DeviceType = FILE_DEVICE_NAMED_PIPE;
3057 else if (is_device_placeholder( fd ))
3059 info->DeviceType = FILE_DEVICE_DISK;
3061 else /* regular file or directory */
3063 #if defined(linux) && defined(HAVE_FSTATFS)
3064 struct statfs stfs;
3066 /* check for floppy disk */
3067 if (major(st.st_dev) == FLOPPY_MAJOR)
3068 info->Characteristics |= FILE_REMOVABLE_MEDIA;
3070 if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
3071 switch (stfs.f_type)
3073 case 0x9660: /* iso9660 */
3074 case 0x9fa1: /* supermount */
3075 case 0x15013346: /* udf */
3076 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
3077 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
3078 break;
3079 case 0x6969: /* nfs */
3080 case 0x517B: /* smbfs */
3081 case 0x564c: /* ncpfs */
3082 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
3083 info->Characteristics |= FILE_REMOTE_DEVICE;
3084 break;
3085 case 0x01021994: /* tmpfs */
3086 case 0x28cd3d45: /* cramfs */
3087 case 0x1373: /* devfs */
3088 case 0x9fa0: /* procfs */
3089 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
3090 break;
3091 default:
3092 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3093 break;
3095 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
3096 struct statfs stfs;
3098 if (fstatfs( fd, &stfs ) < 0)
3099 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3100 else
3101 get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags );
3102 #elif defined(__NetBSD__)
3103 struct statvfs stfs;
3105 if (fstatvfs( fd, &stfs) < 0)
3106 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3107 else
3108 get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag );
3109 #elif defined(sun)
3110 /* Use dkio to work out device types */
3112 # include <sys/dkio.h>
3113 # include <sys/vtoc.h>
3114 struct dk_cinfo dkinf;
3115 int retval = ioctl(fd, DKIOCINFO, &dkinf);
3116 if(retval==-1){
3117 WARN("Unable to get disk device type information - assuming a disk like device\n");
3118 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3120 switch (dkinf.dki_ctype)
3122 case DKC_CDROM:
3123 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
3124 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
3125 break;
3126 case DKC_NCRFLOPPY:
3127 case DKC_SMSFLOPPY:
3128 case DKC_INTEL82072:
3129 case DKC_INTEL82077:
3130 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3131 info->Characteristics |= FILE_REMOVABLE_MEDIA;
3132 break;
3133 case DKC_MD:
3134 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
3135 break;
3136 default:
3137 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3140 #else
3141 static int warned;
3142 if (!warned++) FIXME( "device info not properly supported on this platform\n" );
3143 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
3144 #endif
3145 info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
3147 return STATUS_SUCCESS;
3151 /******************************************************************************
3152 * NtQueryVolumeInformationFile [NTDLL.@]
3153 * ZwQueryVolumeInformationFile [NTDLL.@]
3155 * Get volume information for an open file handle.
3157 * PARAMS
3158 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
3159 * io [O] Receives information about the operation on return
3160 * buffer [O] Destination for volume information
3161 * length [I] Size of FsInformation
3162 * info_class [I] Type of volume information to set
3164 * RETURNS
3165 * Success: 0. io and buffer are updated.
3166 * Failure: An NTSTATUS error code describing the error.
3168 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
3169 PVOID buffer, ULONG length,
3170 FS_INFORMATION_CLASS info_class )
3172 int fd, needs_close;
3173 struct stat st;
3174 static int once;
3176 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
3177 return io->u.Status;
3179 io->u.Status = STATUS_NOT_IMPLEMENTED;
3180 io->Information = 0;
3182 switch( info_class )
3184 case FileFsVolumeInformation:
3185 if (!once++) FIXME( "%p: volume info not supported\n", handle );
3186 break;
3187 case FileFsLabelInformation:
3188 FIXME( "%p: label info not supported\n", handle );
3189 break;
3190 case FileFsSizeInformation:
3191 if (length < sizeof(FILE_FS_SIZE_INFORMATION))
3192 io->u.Status = STATUS_BUFFER_TOO_SMALL;
3193 else
3195 FILE_FS_SIZE_INFORMATION *info = buffer;
3197 if (fstat( fd, &st ) < 0)
3199 io->u.Status = FILE_GetNtStatus();
3200 break;
3202 if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
3204 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
3206 else
3208 ULONGLONG bsize;
3209 /* Linux's fstatvfs is buggy */
3210 #if !defined(linux) || !defined(HAVE_FSTATFS)
3211 struct statvfs stfs;
3213 if (fstatvfs( fd, &stfs ) < 0)
3215 io->u.Status = FILE_GetNtStatus();
3216 break;
3218 bsize = stfs.f_frsize;
3219 #else
3220 struct statfs stfs;
3221 if (fstatfs( fd, &stfs ) < 0)
3223 io->u.Status = FILE_GetNtStatus();
3224 break;
3226 bsize = stfs.f_bsize;
3227 #endif
3228 if (bsize == 2048) /* assume CD-ROM */
3230 info->BytesPerSector = 2048;
3231 info->SectorsPerAllocationUnit = 1;
3233 else
3235 info->BytesPerSector = 512;
3236 info->SectorsPerAllocationUnit = 8;
3238 info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit);
3239 info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit);
3240 io->Information = sizeof(*info);
3241 io->u.Status = STATUS_SUCCESS;
3244 break;
3245 case FileFsDeviceInformation:
3246 if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
3247 io->u.Status = STATUS_BUFFER_TOO_SMALL;
3248 else
3250 FILE_FS_DEVICE_INFORMATION *info = buffer;
3252 if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS)
3253 io->Information = sizeof(*info);
3255 break;
3256 case FileFsAttributeInformation:
3257 if (length < offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[sizeof(ntfsW)/sizeof(WCHAR)] ))
3258 io->u.Status = STATUS_BUFFER_TOO_SMALL;
3259 else
3261 FILE_FS_ATTRIBUTE_INFORMATION *info = buffer;
3263 FIXME( "%p: faking attribute info\n", handle );
3264 info->FileSystemAttribute = FILE_SUPPORTS_ENCRYPTION | FILE_FILE_COMPRESSION |
3265 FILE_PERSISTENT_ACLS | FILE_UNICODE_ON_DISK |
3266 FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH;
3267 info->MaximumComponentNameLength = MAXIMUM_FILENAME_LENGTH - 1;
3268 info->FileSystemNameLength = sizeof(ntfsW);
3269 memcpy(info->FileSystemName, ntfsW, sizeof(ntfsW));
3271 io->Information = sizeof(*info);
3272 io->u.Status = STATUS_SUCCESS;
3274 break;
3275 case FileFsControlInformation:
3276 FIXME( "%p: control info not supported\n", handle );
3277 break;
3278 case FileFsFullSizeInformation:
3279 FIXME( "%p: full size info not supported\n", handle );
3280 break;
3281 case FileFsObjectIdInformation:
3282 FIXME( "%p: object id info not supported\n", handle );
3283 break;
3284 case FileFsMaximumInformation:
3285 FIXME( "%p: maximum info not supported\n", handle );
3286 break;
3287 default:
3288 io->u.Status = STATUS_INVALID_PARAMETER;
3289 break;
3291 if (needs_close) close( fd );
3292 return io->u.Status;
3296 /******************************************************************
3297 * NtQueryEaFile (NTDLL.@)
3299 * Read extended attributes from NTFS files.
3301 * PARAMS
3302 * hFile [I] File handle, must be opened with FILE_READ_EA access
3303 * iosb [O] Receives information about the operation on return
3304 * buffer [O] Output buffer
3305 * length [I] Length of output buffer
3306 * single_entry [I] Only read and return one entry
3307 * ea_list [I] Optional list with names of EAs to return
3308 * ea_list_len [I] Length of ea_list in bytes
3309 * ea_index [I] Optional pointer to 1-based index of attribute to return
3310 * restart [I] restart EA scan
3312 * RETURNS
3313 * Success: 0. Atrributes read into buffer
3314 * Failure: An NTSTATUS error code describing the error.
3316 NTSTATUS WINAPI NtQueryEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length,
3317 BOOLEAN single_entry, PVOID ea_list, ULONG ea_list_len,
3318 PULONG ea_index, BOOLEAN restart )
3320 FIXME("(%p,%p,%p,%d,%d,%p,%d,%p,%d) stub\n",
3321 hFile, iosb, buffer, length, single_entry, ea_list,
3322 ea_list_len, ea_index, restart);
3323 return STATUS_ACCESS_DENIED;
3327 /******************************************************************
3328 * NtSetEaFile (NTDLL.@)
3330 * Update extended attributes for NTFS files.
3332 * PARAMS
3333 * hFile [I] File handle, must be opened with FILE_READ_EA access
3334 * iosb [O] Receives information about the operation on return
3335 * buffer [I] Buffer with EA information
3336 * length [I] Length of buffer
3338 * RETURNS
3339 * Success: 0. Attributes are updated
3340 * Failure: An NTSTATUS error code describing the error.
3342 NTSTATUS WINAPI NtSetEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length )
3344 FIXME("(%p,%p,%p,%d) stub\n", hFile, iosb, buffer, length);
3345 return STATUS_ACCESS_DENIED;
3349 /******************************************************************
3350 * NtFlushBuffersFile (NTDLL.@)
3352 * Flush any buffered data on an open file handle.
3354 * PARAMS
3355 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
3356 * IoStatusBlock [O] Receives information about the operation on return
3358 * RETURNS
3359 * Success: 0. IoStatusBlock is updated.
3360 * Failure: An NTSTATUS error code describing the error.
3362 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
3364 NTSTATUS ret;
3365 HANDLE hEvent = NULL;
3366 enum server_fd_type type;
3367 int fd, needs_close;
3369 ret = server_get_unix_fd( hFile, FILE_WRITE_DATA, &fd, &needs_close, &type, NULL );
3371 if (!ret && type == FD_TYPE_SERIAL)
3373 ret = COMM_FlushBuffersFile( fd );
3375 else
3377 SERVER_START_REQ( flush )
3379 req->blocking = 1; /* always blocking */
3380 req->async.handle = wine_server_obj_handle( hFile );
3381 req->async.iosb = wine_server_client_ptr( IoStatusBlock );
3382 ret = wine_server_call( req );
3383 hEvent = wine_server_ptr_handle( reply->event );
3385 SERVER_END_REQ;
3387 if (hEvent)
3389 NtWaitForSingleObject( hEvent, FALSE, NULL );
3390 NtClose( hEvent );
3391 ret = STATUS_SUCCESS;
3395 if (needs_close) close( fd );
3396 return ret;
3399 /******************************************************************
3400 * NtLockFile (NTDLL.@)
3404 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
3405 PIO_APC_ROUTINE apc, void* apc_user,
3406 PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
3407 PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
3408 BOOLEAN exclusive )
3410 NTSTATUS ret;
3411 HANDLE handle;
3412 BOOLEAN async;
3413 static BOOLEAN warn = TRUE;
3415 if (apc || io_status || key)
3417 FIXME("Unimplemented yet parameter\n");
3418 return STATUS_NOT_IMPLEMENTED;
3421 if (apc_user && warn)
3423 FIXME("I/O completion on lock not implemented yet\n");
3424 warn = FALSE;
3427 for (;;)
3429 SERVER_START_REQ( lock_file )
3431 req->handle = wine_server_obj_handle( hFile );
3432 req->offset = offset->QuadPart;
3433 req->count = count->QuadPart;
3434 req->shared = !exclusive;
3435 req->wait = !dont_wait;
3436 ret = wine_server_call( req );
3437 handle = wine_server_ptr_handle( reply->handle );
3438 async = reply->overlapped;
3440 SERVER_END_REQ;
3441 if (ret != STATUS_PENDING)
3443 if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
3444 return ret;
3447 if (async)
3449 FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
3450 if (handle) NtClose( handle );
3451 return STATUS_PENDING;
3453 if (handle)
3455 NtWaitForSingleObject( handle, FALSE, NULL );
3456 NtClose( handle );
3458 else
3460 LARGE_INTEGER time;
3462 /* Unix lock conflict, sleep a bit and retry */
3463 time.QuadPart = 100 * (ULONGLONG)10000;
3464 time.QuadPart = -time.QuadPart;
3465 NtDelayExecution( FALSE, &time );
3471 /******************************************************************
3472 * NtUnlockFile (NTDLL.@)
3476 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
3477 PLARGE_INTEGER offset, PLARGE_INTEGER count,
3478 PULONG key )
3480 NTSTATUS status;
3482 TRACE( "%p %x%08x %x%08x\n",
3483 hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
3485 if (io_status || key)
3487 FIXME("Unimplemented yet parameter\n");
3488 return STATUS_NOT_IMPLEMENTED;
3491 SERVER_START_REQ( unlock_file )
3493 req->handle = wine_server_obj_handle( hFile );
3494 req->offset = offset->QuadPart;
3495 req->count = count->QuadPart;
3496 status = wine_server_call( req );
3498 SERVER_END_REQ;
3499 return status;
3502 /******************************************************************
3503 * NtCreateNamedPipeFile (NTDLL.@)
3507 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
3508 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
3509 ULONG sharing, ULONG dispo, ULONG options,
3510 ULONG pipe_type, ULONG read_mode,
3511 ULONG completion_mode, ULONG max_inst,
3512 ULONG inbound_quota, ULONG outbound_quota,
3513 PLARGE_INTEGER timeout)
3515 struct security_descriptor *sd = NULL;
3516 struct object_attributes objattr;
3517 NTSTATUS status;
3519 TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n",
3520 handle, access, debugstr_w(attr->ObjectName->Buffer), iosb, sharing, dispo,
3521 options, pipe_type, read_mode, completion_mode, max_inst, inbound_quota,
3522 outbound_quota, timeout);
3524 /* assume we only get relative timeout */
3525 if (timeout->QuadPart > 0)
3526 FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
3528 objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
3529 objattr.sd_len = 0;
3530 objattr.name_len = attr->ObjectName->Length;
3532 status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
3533 if (status != STATUS_SUCCESS) return status;
3535 SERVER_START_REQ( create_named_pipe )
3537 req->access = access;
3538 req->attributes = attr->Attributes;
3539 req->options = options;
3540 req->sharing = sharing;
3541 req->flags =
3542 (pipe_type ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0) |
3543 (read_mode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0) |
3544 (completion_mode ? NAMED_PIPE_NONBLOCKING_MODE : 0);
3545 req->maxinstances = max_inst;
3546 req->outsize = outbound_quota;
3547 req->insize = inbound_quota;
3548 req->timeout = timeout->QuadPart;
3549 wine_server_add_data( req, &objattr, sizeof(objattr) );
3550 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
3551 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
3552 status = wine_server_call( req );
3553 if (!status) *handle = wine_server_ptr_handle( reply->handle );
3555 SERVER_END_REQ;
3557 NTDLL_free_struct_sd( sd );
3558 return status;
3561 /******************************************************************
3562 * NtDeleteFile (NTDLL.@)
3566 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
3568 NTSTATUS status;
3569 HANDLE hFile;
3570 IO_STATUS_BLOCK io;
3572 TRACE("%p\n", ObjectAttributes);
3573 status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE | DELETE,
3574 ObjectAttributes, &io, NULL, 0,
3575 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
3576 FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
3577 if (status == STATUS_SUCCESS) status = NtClose(hFile);
3578 return status;
3581 /******************************************************************
3582 * NtCancelIoFileEx (NTDLL.@)
3586 NTSTATUS WINAPI NtCancelIoFileEx( HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status )
3588 TRACE("%p %p %p\n", hFile, iosb, io_status );
3590 SERVER_START_REQ( cancel_async )
3592 req->handle = wine_server_obj_handle( hFile );
3593 req->iosb = wine_server_client_ptr( iosb );
3594 req->only_thread = FALSE;
3595 io_status->u.Status = wine_server_call( req );
3597 SERVER_END_REQ;
3599 return io_status->u.Status;
3602 /******************************************************************
3603 * NtCancelIoFile (NTDLL.@)
3607 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
3609 TRACE("%p %p\n", hFile, io_status );
3611 SERVER_START_REQ( cancel_async )
3613 req->handle = wine_server_obj_handle( hFile );
3614 req->iosb = 0;
3615 req->only_thread = TRUE;
3616 io_status->u.Status = wine_server_call( req );
3618 SERVER_END_REQ;
3620 return io_status->u.Status;
3623 /******************************************************************************
3624 * NtCreateMailslotFile [NTDLL.@]
3625 * ZwCreateMailslotFile [NTDLL.@]
3627 * PARAMS
3628 * pHandle [O] pointer to receive the handle created
3629 * DesiredAccess [I] access mode (read, write, etc)
3630 * ObjectAttributes [I] fully qualified NT path of the mailslot
3631 * IoStatusBlock [O] receives completion status and other info
3632 * CreateOptions [I]
3633 * MailslotQuota [I]
3634 * MaxMessageSize [I]
3635 * TimeOut [I]
3637 * RETURNS
3638 * An NT status code
3640 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
3641 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
3642 ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
3643 PLARGE_INTEGER TimeOut)
3645 LARGE_INTEGER timeout;
3646 NTSTATUS ret;
3648 TRACE("%p %08x %p %p %08x %08x %08x %p\n",
3649 pHandle, DesiredAccess, attr, IoStatusBlock,
3650 CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
3652 if (!pHandle) return STATUS_ACCESS_VIOLATION;
3653 if (!attr) return STATUS_INVALID_PARAMETER;
3654 if (!attr->ObjectName) return STATUS_OBJECT_PATH_SYNTAX_BAD;
3657 * For a NULL TimeOut pointer set the default timeout value
3659 if (!TimeOut)
3660 timeout.QuadPart = -1;
3661 else
3662 timeout.QuadPart = TimeOut->QuadPart;
3664 SERVER_START_REQ( create_mailslot )
3666 req->access = DesiredAccess;
3667 req->attributes = attr->Attributes;
3668 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
3669 req->max_msgsize = MaxMessageSize;
3670 req->read_timeout = timeout.QuadPart;
3671 wine_server_add_data( req, attr->ObjectName->Buffer,
3672 attr->ObjectName->Length );
3673 ret = wine_server_call( req );
3674 if( ret == STATUS_SUCCESS )
3675 *pHandle = wine_server_ptr_handle( reply->handle );
3677 SERVER_END_REQ;
3679 return ret;