gdi32: Change an ERR to a WARN for fonts with too-long names.
[wine/multimedia.git] / dlls / ntdll / file.c
blob52320277b9435cc1ec07b27a5b00845499e045ba
1 /*
2 * Copyright 1999, 2000 Juergen Schmied
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include "wine/port.h"
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <assert.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_LINUX_MAJOR_H
31 # include <linux/major.h>
32 #endif
33 #ifdef HAVE_SYS_STATVFS_H
34 # include <sys/statvfs.h>
35 #endif
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
39 #ifdef HAVE_SYS_SYSCALL_H
40 # include <sys/syscall.h>
41 #endif
42 #ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 #endif
45 #ifdef HAVE_SYS_IOCTL_H
46 #include <sys/ioctl.h>
47 #endif
48 #ifdef HAVE_SYS_FILIO_H
49 # include <sys/filio.h>
50 #endif
51 #ifdef HAVE_POLL_H
52 #include <poll.h>
53 #endif
54 #ifdef HAVE_SYS_POLL_H
55 #include <sys/poll.h>
56 #endif
57 #ifdef HAVE_SYS_SOCKET_H
58 #include <sys/socket.h>
59 #endif
60 #ifdef HAVE_UTIME_H
61 # include <utime.h>
62 #endif
63 #ifdef HAVE_SYS_VFS_H
64 # include <sys/vfs.h>
65 #endif
66 #ifdef HAVE_SYS_MOUNT_H
67 # include <sys/mount.h>
68 #endif
69 #ifdef HAVE_SYS_STATFS_H
70 # include <sys/statfs.h>
71 #endif
72 #ifdef HAVE_TERMIOS_H
73 #include <termios.h>
74 #endif
75 #ifdef HAVE_VALGRIND_MEMCHECK_H
76 # include <valgrind/memcheck.h>
77 #endif
79 #define NONAMELESSUNION
80 #define NONAMELESSSTRUCT
81 #include "ntstatus.h"
82 #define WIN32_NO_STATUS
83 #include "wine/unicode.h"
84 #include "wine/debug.h"
85 #include "wine/server.h"
86 #include "ntdll_misc.h"
88 #include "winternl.h"
89 #include "winioctl.h"
90 #include "ddk/ntddk.h"
91 #include "ddk/ntddser.h"
93 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
94 WINE_DECLARE_DEBUG_CHANNEL(winediag);
96 mode_t FILE_umask = 0;
98 #define SECSPERDAY 86400
99 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
101 #define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1)
102 #define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
104 static const WCHAR ntfsW[] = {'N','T','F','S'};
106 /* fetch the attributes of a file */
107 static inline ULONG get_file_attributes( const struct stat *st )
109 ULONG attr;
111 if (S_ISDIR(st->st_mode))
112 attr = FILE_ATTRIBUTE_DIRECTORY;
113 else
114 attr = FILE_ATTRIBUTE_ARCHIVE;
115 if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
116 attr |= FILE_ATTRIBUTE_READONLY;
117 return attr;
120 /* get the stat info and file attributes for a file (by file descriptor) */
121 int fd_get_file_info( int fd, struct stat *st, ULONG *attr )
123 int ret;
125 *attr = 0;
126 ret = fstat( fd, st );
127 if (ret == -1) return ret;
128 *attr |= get_file_attributes( st );
129 return ret;
132 /* get the stat info and file attributes for a file (by name) */
133 int get_file_info( const char *path, struct stat *st, ULONG *attr )
135 int ret;
137 *attr = 0;
138 ret = lstat( path, st );
139 if (ret == -1) return ret;
140 if (S_ISLNK( st->st_mode ))
142 ret = stat( path, st );
143 if (ret == -1) return ret;
144 /* is a symbolic link and a directory, consider these "reparse points" */
145 if (S_ISDIR( st->st_mode )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
147 *attr |= get_file_attributes( st );
148 return ret;
151 /**************************************************************************
152 * FILE_CreateFile (internal)
153 * Open a file.
155 * Parameter set fully identical with NtCreateFile
157 static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
158 PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
159 ULONG attributes, ULONG sharing, ULONG disposition,
160 ULONG options, PVOID ea_buffer, ULONG ea_length )
162 ANSI_STRING unix_name;
163 BOOL created = FALSE;
165 TRACE("handle=%p access=%08x name=%s objattr=%08x root=%p sec=%p io=%p alloc_size=%p "
166 "attr=%08x sharing=%08x disp=%d options=%08x ea=%p.0x%08x\n",
167 handle, access, debugstr_us(attr->ObjectName), attr->Attributes,
168 attr->RootDirectory, attr->SecurityDescriptor, io, alloc_size,
169 attributes, sharing, disposition, options, ea_buffer, ea_length );
171 if (!attr || !attr->ObjectName) return STATUS_INVALID_PARAMETER;
173 if (alloc_size) FIXME( "alloc_size not supported\n" );
175 if (options & FILE_OPEN_BY_FILE_ID)
176 io->u.Status = file_id_to_unix_file_name( attr, &unix_name );
177 else
178 io->u.Status = nt_to_unix_file_name_attr( attr, &unix_name, disposition );
180 if (io->u.Status == STATUS_BAD_DEVICE_TYPE)
182 SERVER_START_REQ( open_file_object )
184 req->access = access;
185 req->attributes = attr->Attributes;
186 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
187 req->sharing = sharing;
188 req->options = options;
189 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
190 io->u.Status = wine_server_call( req );
191 *handle = wine_server_ptr_handle( reply->handle );
193 SERVER_END_REQ;
194 if (io->u.Status == STATUS_SUCCESS) io->Information = FILE_OPENED;
195 return io->u.Status;
198 if (io->u.Status == STATUS_NO_SUCH_FILE &&
199 disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
201 created = TRUE;
202 io->u.Status = STATUS_SUCCESS;
205 if (io->u.Status == STATUS_SUCCESS)
207 struct security_descriptor *sd;
208 struct object_attributes objattr;
210 objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
211 objattr.name_len = 0;
212 io->u.Status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
213 if (io->u.Status != STATUS_SUCCESS)
215 RtlFreeAnsiString( &unix_name );
216 return io->u.Status;
219 SERVER_START_REQ( create_file )
221 req->access = access;
222 req->attributes = attr->Attributes;
223 req->sharing = sharing;
224 req->create = disposition;
225 req->options = options;
226 req->attrs = attributes;
227 wine_server_add_data( req, &objattr, sizeof(objattr) );
228 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
229 wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
230 io->u.Status = wine_server_call( req );
231 *handle = wine_server_ptr_handle( reply->handle );
233 SERVER_END_REQ;
234 NTDLL_free_struct_sd( sd );
235 RtlFreeAnsiString( &unix_name );
237 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
239 if (io->u.Status == STATUS_SUCCESS)
241 if (created) io->Information = FILE_CREATED;
242 else switch(disposition)
244 case FILE_SUPERSEDE:
245 io->Information = FILE_SUPERSEDED;
246 break;
247 case FILE_CREATE:
248 io->Information = FILE_CREATED;
249 break;
250 case FILE_OPEN:
251 case FILE_OPEN_IF:
252 io->Information = FILE_OPENED;
253 break;
254 case FILE_OVERWRITE:
255 case FILE_OVERWRITE_IF:
256 io->Information = FILE_OVERWRITTEN;
257 break;
260 else if (io->u.Status == STATUS_TOO_MANY_OPENED_FILES)
262 static int once;
263 if (!once++) ERR_(winediag)( "Too many open files, ulimit -n probably needs to be increased\n" );
266 return io->u.Status;
269 /**************************************************************************
270 * NtOpenFile [NTDLL.@]
271 * ZwOpenFile [NTDLL.@]
273 * Open a file.
275 * PARAMS
276 * handle [O] Variable that receives the file handle on return
277 * access [I] Access desired by the caller to the file
278 * attr [I] Structure describing the file to be opened
279 * io [O] Receives details about the result of the operation
280 * sharing [I] Type of shared access the caller requires
281 * options [I] Options for the file open
283 * RETURNS
284 * Success: 0. FileHandle and IoStatusBlock are updated.
285 * Failure: An NTSTATUS error code describing the error.
287 NTSTATUS WINAPI NtOpenFile( PHANDLE handle, ACCESS_MASK access,
288 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK io,
289 ULONG sharing, ULONG options )
291 return FILE_CreateFile( handle, access, attr, io, NULL, 0,
292 sharing, FILE_OPEN, options, NULL, 0 );
295 /**************************************************************************
296 * NtCreateFile [NTDLL.@]
297 * ZwCreateFile [NTDLL.@]
299 * Either create a new file or directory, or open an existing file, device,
300 * directory or volume.
302 * PARAMS
303 * handle [O] Points to a variable which receives the file handle on return
304 * access [I] Desired access to the file
305 * attr [I] Structure describing the file
306 * io [O] Receives information about the operation on return
307 * alloc_size [I] Initial size of the file in bytes
308 * attributes [I] Attributes to create the file with
309 * sharing [I] Type of shared access the caller would like to the file
310 * disposition [I] Specifies what to do, depending on whether the file already exists
311 * options [I] Options for creating a new file
312 * ea_buffer [I] Pointer to an extended attributes buffer
313 * ea_length [I] Length of ea_buffer
315 * RETURNS
316 * Success: 0. handle and io are updated.
317 * Failure: An NTSTATUS error code describing the error.
319 NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
320 PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
321 ULONG attributes, ULONG sharing, ULONG disposition,
322 ULONG options, PVOID ea_buffer, ULONG ea_length )
324 return FILE_CreateFile( handle, access, attr, io, alloc_size, attributes,
325 sharing, disposition, options, ea_buffer, ea_length );
328 /***********************************************************************
329 * Asynchronous file I/O *
332 struct async_fileio
334 HANDLE handle;
335 PIO_APC_ROUTINE apc;
336 void *apc_arg;
339 typedef struct
341 struct async_fileio io;
342 char* buffer;
343 unsigned int already;
344 unsigned int count;
345 BOOL avail_mode;
346 } async_fileio_read;
348 typedef struct
350 struct async_fileio io;
351 const char *buffer;
352 unsigned int already;
353 unsigned int count;
354 } async_fileio_write;
357 /* callback for file I/O user APC */
358 static void WINAPI fileio_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved )
360 struct async_fileio *async = arg;
361 if (async->apc) async->apc( async->apc_arg, io, reserved );
362 RtlFreeHeap( GetProcessHeap(), 0, async );
365 /***********************************************************************
366 * FILE_GetNtStatus(void)
368 * Retrieve the Nt Status code from errno.
369 * Try to be consistent with FILE_SetDosError().
371 NTSTATUS FILE_GetNtStatus(void)
373 int err = errno;
375 TRACE( "errno = %d\n", errno );
376 switch (err)
378 case EAGAIN: return STATUS_SHARING_VIOLATION;
379 case EBADF: return STATUS_INVALID_HANDLE;
380 case EBUSY: return STATUS_DEVICE_BUSY;
381 case ENOSPC: return STATUS_DISK_FULL;
382 case EPERM:
383 case EROFS:
384 case EACCES: return STATUS_ACCESS_DENIED;
385 case ENOTDIR: return STATUS_OBJECT_PATH_NOT_FOUND;
386 case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND;
387 case EISDIR: return STATUS_FILE_IS_A_DIRECTORY;
388 case EMFILE:
389 case ENFILE: return STATUS_TOO_MANY_OPENED_FILES;
390 case EINVAL: return STATUS_INVALID_PARAMETER;
391 case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
392 case EPIPE: return STATUS_PIPE_DISCONNECTED;
393 case EIO: return STATUS_DEVICE_NOT_READY;
394 #ifdef ENOMEDIUM
395 case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE;
396 #endif
397 case ENXIO: return STATUS_NO_SUCH_DEVICE;
398 case ENOTTY:
399 case EOPNOTSUPP:return STATUS_NOT_SUPPORTED;
400 case ECONNRESET:return STATUS_PIPE_DISCONNECTED;
401 case EFAULT: return STATUS_ACCESS_VIOLATION;
402 case ESPIPE: return STATUS_ILLEGAL_FUNCTION;
403 #ifdef ETIME /* Missing on FreeBSD */
404 case ETIME: return STATUS_IO_TIMEOUT;
405 #endif
406 case ENOEXEC: /* ?? */
407 case EEXIST: /* ?? */
408 default:
409 FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
410 return STATUS_UNSUCCESSFUL;
414 /***********************************************************************
415 * FILE_AsyncReadService (INTERNAL)
417 static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc)
419 async_fileio_read *fileio = user;
420 int fd, needs_close, result;
422 switch (status)
424 case STATUS_ALERTED: /* got some new data */
425 /* check to see if the data is ready (non-blocking) */
426 if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
427 &needs_close, NULL, NULL )))
428 break;
430 result = read(fd, &fileio->buffer[fileio->already], fileio->count - fileio->already);
431 if (needs_close) close( fd );
433 if (result < 0)
435 if (errno == EAGAIN || errno == EINTR)
436 status = STATUS_PENDING;
437 else /* check to see if the transfer is complete */
438 status = FILE_GetNtStatus();
440 else if (result == 0)
442 status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN;
444 else
446 fileio->already += result;
447 if (fileio->already >= fileio->count || fileio->avail_mode)
448 status = STATUS_SUCCESS;
449 else
451 /* if we only have to read the available data, and none is available,
452 * simply cancel the request. If data was available, it has been read
453 * while in by previous call (NtDelayExecution)
455 status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING;
458 break;
460 case STATUS_TIMEOUT:
461 case STATUS_IO_TIMEOUT:
462 if (fileio->already) status = STATUS_SUCCESS;
463 break;
465 if (status != STATUS_PENDING)
467 iosb->u.Status = status;
468 iosb->Information = fileio->already;
469 *apc = fileio_apc;
471 return status;
474 struct io_timeouts
476 int interval; /* max interval between two bytes */
477 int total; /* total timeout for the whole operation */
478 int end_time; /* absolute time of end of operation */
481 /* retrieve the I/O timeouts to use for a given handle */
482 static NTSTATUS get_io_timeouts( HANDLE handle, enum server_fd_type type, ULONG count, BOOL is_read,
483 struct io_timeouts *timeouts )
485 NTSTATUS status = STATUS_SUCCESS;
487 timeouts->interval = timeouts->total = -1;
489 switch(type)
491 case FD_TYPE_SERIAL:
493 /* GetCommTimeouts */
494 SERIAL_TIMEOUTS st;
495 IO_STATUS_BLOCK io;
497 status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
498 IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
499 if (status) break;
501 if (is_read)
503 if (st.ReadIntervalTimeout)
504 timeouts->interval = st.ReadIntervalTimeout;
506 if (st.ReadTotalTimeoutMultiplier || st.ReadTotalTimeoutConstant)
508 timeouts->total = st.ReadTotalTimeoutConstant;
509 if (st.ReadTotalTimeoutMultiplier != MAXDWORD)
510 timeouts->total += count * st.ReadTotalTimeoutMultiplier;
512 else if (st.ReadIntervalTimeout == MAXDWORD)
513 timeouts->interval = timeouts->total = 0;
515 else /* write */
517 if (st.WriteTotalTimeoutMultiplier || st.WriteTotalTimeoutConstant)
519 timeouts->total = st.WriteTotalTimeoutConstant;
520 if (st.WriteTotalTimeoutMultiplier != MAXDWORD)
521 timeouts->total += count * st.WriteTotalTimeoutMultiplier;
525 break;
526 case FD_TYPE_MAILSLOT:
527 if (is_read)
529 timeouts->interval = 0; /* return as soon as we got something */
530 SERVER_START_REQ( set_mailslot_info )
532 req->handle = wine_server_obj_handle( handle );
533 req->flags = 0;
534 if (!(status = wine_server_call( req )) &&
535 reply->read_timeout != TIMEOUT_INFINITE)
536 timeouts->total = reply->read_timeout / -10000;
538 SERVER_END_REQ;
540 break;
541 case FD_TYPE_SOCKET:
542 case FD_TYPE_PIPE:
543 case FD_TYPE_CHAR:
544 if (is_read) timeouts->interval = 0; /* return as soon as we got something */
545 break;
546 default:
547 break;
549 if (timeouts->total != -1) timeouts->end_time = NtGetTickCount() + timeouts->total;
550 return STATUS_SUCCESS;
554 /* retrieve the timeout for the next wait, in milliseconds */
555 static inline int get_next_io_timeout( const struct io_timeouts *timeouts, ULONG already )
557 int ret = -1;
559 if (timeouts->total != -1)
561 ret = timeouts->end_time - NtGetTickCount();
562 if (ret < 0) ret = 0;
564 if (already && timeouts->interval != -1)
566 if (ret == -1 || ret > timeouts->interval) ret = timeouts->interval;
568 return ret;
572 /* retrieve the avail_mode flag for async reads */
573 static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL *avail_mode )
575 NTSTATUS status = STATUS_SUCCESS;
577 switch(type)
579 case FD_TYPE_SERIAL:
581 /* GetCommTimeouts */
582 SERIAL_TIMEOUTS st;
583 IO_STATUS_BLOCK io;
585 status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
586 IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
587 if (status) break;
588 *avail_mode = (!st.ReadTotalTimeoutMultiplier &&
589 !st.ReadTotalTimeoutConstant &&
590 st.ReadIntervalTimeout == MAXDWORD);
592 break;
593 case FD_TYPE_MAILSLOT:
594 case FD_TYPE_SOCKET:
595 case FD_TYPE_PIPE:
596 case FD_TYPE_CHAR:
597 *avail_mode = TRUE;
598 break;
599 default:
600 *avail_mode = FALSE;
601 break;
603 return status;
607 /******************************************************************************
608 * NtReadFile [NTDLL.@]
609 * ZwReadFile [NTDLL.@]
611 * Read from an open file handle.
613 * PARAMS
614 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
615 * Event [I] Event to signal upon completion (or NULL)
616 * ApcRoutine [I] Callback to call upon completion (or NULL)
617 * ApcContext [I] Context for ApcRoutine (or NULL)
618 * IoStatusBlock [O] Receives information about the operation on return
619 * Buffer [O] Destination for the data read
620 * Length [I] Size of Buffer
621 * ByteOffset [O] Destination for the new file pointer position (or NULL)
622 * Key [O] Function unknown (may be NULL)
624 * RETURNS
625 * Success: 0. IoStatusBlock is updated, and the Information member contains
626 * The number of bytes read.
627 * Failure: An NTSTATUS error code describing the error.
629 NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
630 PIO_APC_ROUTINE apc, void* apc_user,
631 PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
632 PLARGE_INTEGER offset, PULONG key)
634 int result, unix_handle, needs_close;
635 unsigned int options;
636 struct io_timeouts timeouts;
637 NTSTATUS status;
638 ULONG total = 0;
639 enum server_fd_type type;
640 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
641 BOOL send_completion = FALSE, async_read, timeout_init_done = FALSE;
643 TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
644 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
646 if (!io_status) return STATUS_ACCESS_VIOLATION;
648 status = server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
649 &needs_close, &type, &options );
650 if (status) return status;
652 async_read = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
654 if (!virtual_check_buffer_for_write( buffer, length ))
656 status = STATUS_ACCESS_VIOLATION;
657 goto done;
660 if (type == FD_TYPE_FILE)
662 if (async_read && (!offset || offset->QuadPart < 0))
664 status = STATUS_INVALID_PARAMETER;
665 goto done;
668 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
670 /* async I/O doesn't make sense on regular files */
671 while ((result = pread( unix_handle, buffer, length, offset->QuadPart )) == -1)
673 if (errno != EINTR)
675 status = FILE_GetNtStatus();
676 goto done;
679 if (!async_read)
680 /* update file pointer position */
681 lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
683 total = result;
684 status = (total || !length) ? STATUS_SUCCESS : STATUS_END_OF_FILE;
685 goto done;
688 else if (type == FD_TYPE_SERIAL)
690 if (async_read && (!offset || offset->QuadPart < 0))
692 status = STATUS_INVALID_PARAMETER;
693 goto done;
697 for (;;)
699 if ((result = read( unix_handle, (char *)buffer + total, length - total )) >= 0)
701 total += result;
702 if (!result || total == length)
704 if (total)
706 status = STATUS_SUCCESS;
707 goto done;
709 switch (type)
711 case FD_TYPE_FILE:
712 case FD_TYPE_CHAR:
713 status = length ? STATUS_END_OF_FILE : STATUS_SUCCESS;
714 goto done;
715 case FD_TYPE_SERIAL:
716 break;
717 default:
718 status = STATUS_PIPE_BROKEN;
719 goto done;
722 else if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
724 else if (errno != EAGAIN)
726 if (errno == EINTR) continue;
727 if (!total) status = FILE_GetNtStatus();
728 goto done;
731 if (async_read)
733 async_fileio_read *fileio;
734 BOOL avail_mode;
736 if ((status = get_io_avail_mode( hFile, type, &avail_mode )))
737 goto err;
738 if (total && avail_mode)
740 status = STATUS_SUCCESS;
741 goto done;
744 if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio))))
746 status = STATUS_NO_MEMORY;
747 goto err;
749 fileio->io.handle = hFile;
750 fileio->io.apc = apc;
751 fileio->io.apc_arg = apc_user;
752 fileio->already = total;
753 fileio->count = length;
754 fileio->buffer = buffer;
755 fileio->avail_mode = avail_mode;
757 SERVER_START_REQ( register_async )
759 req->type = ASYNC_TYPE_READ;
760 req->count = length;
761 req->async.handle = wine_server_obj_handle( hFile );
762 req->async.event = wine_server_obj_handle( hEvent );
763 req->async.callback = wine_server_client_ptr( FILE_AsyncReadService );
764 req->async.iosb = wine_server_client_ptr( io_status );
765 req->async.arg = wine_server_client_ptr( fileio );
766 req->async.cvalue = cvalue;
767 status = wine_server_call( req );
769 SERVER_END_REQ;
771 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
772 goto err;
774 else /* synchronous read, wait for the fd to become ready */
776 struct pollfd pfd;
777 int ret, timeout;
779 if (!timeout_init_done)
781 timeout_init_done = TRUE;
782 if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts )))
783 goto err;
784 if (hEvent) NtResetEvent( hEvent, NULL );
786 timeout = get_next_io_timeout( &timeouts, total );
788 pfd.fd = unix_handle;
789 pfd.events = POLLIN;
791 if (!timeout || !(ret = poll( &pfd, 1, timeout )))
793 if (total) /* return with what we got so far */
794 status = STATUS_SUCCESS;
795 else
796 status = (type == FD_TYPE_MAILSLOT) ? STATUS_IO_TIMEOUT : STATUS_TIMEOUT;
797 goto done;
799 if (ret == -1 && errno != EINTR)
801 status = FILE_GetNtStatus();
802 goto done;
804 /* will now restart the read */
808 done:
809 send_completion = cvalue != 0;
811 err:
812 if (needs_close) close( unix_handle );
813 if (status == STATUS_SUCCESS || (status == STATUS_END_OF_FILE && !async_read))
815 io_status->u.Status = status;
816 io_status->Information = total;
817 TRACE("= SUCCESS (%u)\n", total);
818 if (hEvent) NtSetEvent( hEvent, NULL );
819 if (apc && !status) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
820 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
822 else
824 TRACE("= 0x%08x\n", status);
825 if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
828 if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total );
830 return status;
834 /******************************************************************************
835 * NtReadFileScatter [NTDLL.@]
836 * ZwReadFileScatter [NTDLL.@]
838 NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
839 PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
840 ULONG length, PLARGE_INTEGER offset, PULONG key )
842 int result, unix_handle, needs_close;
843 unsigned int options;
844 NTSTATUS status;
845 ULONG pos = 0, total = 0;
846 enum server_fd_type type;
847 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
848 BOOL send_completion = FALSE;
850 TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
851 file, event, apc, apc_user, io_status, segments, length, offset, key);
853 if (length % page_size) return STATUS_INVALID_PARAMETER;
854 if (!io_status) return STATUS_ACCESS_VIOLATION;
856 status = server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
857 &needs_close, &type, &options );
858 if (status) return status;
860 if ((type != FD_TYPE_FILE) ||
861 (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
862 !(options & FILE_NO_INTERMEDIATE_BUFFERING))
864 status = STATUS_INVALID_PARAMETER;
865 goto error;
868 while (length)
870 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
871 result = pread( unix_handle, (char *)segments->Buffer + pos,
872 page_size - pos, offset->QuadPart + total );
873 else
874 result = read( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
876 if (result == -1)
878 if (errno == EINTR) continue;
879 status = FILE_GetNtStatus();
880 break;
882 if (!result)
884 status = STATUS_END_OF_FILE;
885 break;
887 total += result;
888 length -= result;
889 if ((pos += result) == page_size)
891 pos = 0;
892 segments++;
896 send_completion = cvalue != 0;
898 error:
899 if (needs_close) close( unix_handle );
900 if (status == STATUS_SUCCESS)
902 io_status->u.Status = status;
903 io_status->Information = total;
904 TRACE("= SUCCESS (%u)\n", total);
905 if (event) NtSetEvent( event, NULL );
906 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
907 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
909 else
911 TRACE("= 0x%08x\n", status);
912 if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
915 if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total );
917 return status;
921 /***********************************************************************
922 * FILE_AsyncWriteService (INTERNAL)
924 static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status, void **apc)
926 async_fileio_write *fileio = user;
927 int result, fd, needs_close;
928 enum server_fd_type type;
930 switch (status)
932 case STATUS_ALERTED:
933 /* write some data (non-blocking) */
934 if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
935 &needs_close, &type, NULL )))
936 break;
938 if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
939 result = send( fd, fileio->buffer, 0, 0 );
940 else
941 result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already );
943 if (needs_close) close( fd );
945 if (result < 0)
947 if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING;
948 else status = FILE_GetNtStatus();
950 else
952 fileio->already += result;
953 status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
955 break;
957 case STATUS_TIMEOUT:
958 case STATUS_IO_TIMEOUT:
959 if (fileio->already) status = STATUS_SUCCESS;
960 break;
962 if (status != STATUS_PENDING)
964 iosb->u.Status = status;
965 iosb->Information = fileio->already;
966 *apc = fileio_apc;
968 return status;
971 static NTSTATUS set_pending_write( HANDLE device )
973 NTSTATUS status;
975 SERVER_START_REQ( set_serial_info )
977 req->handle = wine_server_obj_handle( device );
978 req->flags = SERIALINFO_PENDING_WRITE;
979 status = wine_server_call( req );
981 SERVER_END_REQ;
982 return status;
985 /******************************************************************************
986 * NtWriteFile [NTDLL.@]
987 * ZwWriteFile [NTDLL.@]
989 * Write to an open file handle.
991 * PARAMS
992 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
993 * Event [I] Event to signal upon completion (or NULL)
994 * ApcRoutine [I] Callback to call upon completion (or NULL)
995 * ApcContext [I] Context for ApcRoutine (or NULL)
996 * IoStatusBlock [O] Receives information about the operation on return
997 * Buffer [I] Source for the data to write
998 * Length [I] Size of Buffer
999 * ByteOffset [O] Destination for the new file pointer position (or NULL)
1000 * Key [O] Function unknown (may be NULL)
1002 * RETURNS
1003 * Success: 0. IoStatusBlock is updated, and the Information member contains
1004 * The number of bytes written.
1005 * Failure: An NTSTATUS error code describing the error.
1007 NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
1008 PIO_APC_ROUTINE apc, void* apc_user,
1009 PIO_STATUS_BLOCK io_status,
1010 const void* buffer, ULONG length,
1011 PLARGE_INTEGER offset, PULONG key)
1013 int result, unix_handle, needs_close;
1014 unsigned int options;
1015 struct io_timeouts timeouts;
1016 NTSTATUS status;
1017 ULONG total = 0;
1018 enum server_fd_type type;
1019 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1020 BOOL send_completion = FALSE, async_write, append_write = FALSE, timeout_init_done = FALSE;
1021 LARGE_INTEGER offset_eof;
1023 TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)!\n",
1024 hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
1026 if (!io_status) return STATUS_ACCESS_VIOLATION;
1028 status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
1029 &needs_close, &type, &options );
1030 if (status == STATUS_ACCESS_DENIED)
1032 status = server_get_unix_fd( hFile, FILE_APPEND_DATA, &unix_handle,
1033 &needs_close, &type, &options );
1034 append_write = TRUE;
1036 if (status) return status;
1038 if (!virtual_check_buffer_for_read( buffer, length ))
1040 status = STATUS_INVALID_USER_BUFFER;
1041 goto done;
1044 async_write = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
1046 if (type == FD_TYPE_FILE)
1048 if (async_write &&
1049 (!offset || (offset->QuadPart < 0 && offset->QuadPart != FILE_WRITE_TO_END_OF_FILE)))
1051 status = STATUS_INVALID_PARAMETER;
1052 goto done;
1055 if (append_write)
1057 offset_eof.QuadPart = FILE_WRITE_TO_END_OF_FILE;
1058 offset = &offset_eof;
1061 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
1063 off_t off = offset->QuadPart;
1065 if (offset->QuadPart == FILE_WRITE_TO_END_OF_FILE)
1067 struct stat st;
1069 if (fstat( unix_handle, &st ) == -1)
1071 status = FILE_GetNtStatus();
1072 goto done;
1074 off = st.st_size;
1076 else if (offset->QuadPart < 0)
1078 status = STATUS_INVALID_PARAMETER;
1079 goto done;
1082 /* async I/O doesn't make sense on regular files */
1083 while ((result = pwrite( unix_handle, buffer, length, off )) == -1)
1085 if (errno != EINTR)
1087 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
1088 else status = FILE_GetNtStatus();
1089 goto done;
1093 if (!async_write)
1094 /* update file pointer position */
1095 lseek( unix_handle, off + result, SEEK_SET );
1097 total = result;
1098 status = STATUS_SUCCESS;
1099 goto done;
1102 else if (type == FD_TYPE_SERIAL)
1104 if (async_write &&
1105 (!offset || (offset->QuadPart < 0 && offset->QuadPart != FILE_WRITE_TO_END_OF_FILE)))
1107 status = STATUS_INVALID_PARAMETER;
1108 goto done;
1112 for (;;)
1114 /* zero-length writes on sockets may not work with plain write(2) */
1115 if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
1116 result = send( unix_handle, buffer, 0, 0 );
1117 else
1118 result = write( unix_handle, (const char *)buffer + total, length - total );
1120 if (result >= 0)
1122 total += result;
1123 if (total == length)
1125 status = STATUS_SUCCESS;
1126 goto done;
1128 if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
1130 else if (errno != EAGAIN)
1132 if (errno == EINTR) continue;
1133 if (!total)
1135 if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
1136 else status = FILE_GetNtStatus();
1138 goto done;
1141 if (async_write)
1143 async_fileio_write *fileio;
1145 if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio))))
1147 status = STATUS_NO_MEMORY;
1148 goto err;
1150 fileio->io.handle = hFile;
1151 fileio->io.apc = apc;
1152 fileio->io.apc_arg = apc_user;
1153 fileio->already = total;
1154 fileio->count = length;
1155 fileio->buffer = buffer;
1157 SERVER_START_REQ( register_async )
1159 req->type = ASYNC_TYPE_WRITE;
1160 req->count = length;
1161 req->async.handle = wine_server_obj_handle( hFile );
1162 req->async.event = wine_server_obj_handle( hEvent );
1163 req->async.callback = wine_server_client_ptr( FILE_AsyncWriteService );
1164 req->async.iosb = wine_server_client_ptr( io_status );
1165 req->async.arg = wine_server_client_ptr( fileio );
1166 req->async.cvalue = cvalue;
1167 status = wine_server_call( req );
1169 SERVER_END_REQ;
1171 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
1172 goto err;
1174 else /* synchronous write, wait for the fd to become ready */
1176 struct pollfd pfd;
1177 int ret, timeout;
1179 if (!timeout_init_done)
1181 timeout_init_done = TRUE;
1182 if ((status = get_io_timeouts( hFile, type, length, FALSE, &timeouts )))
1183 goto err;
1184 if (hEvent) NtResetEvent( hEvent, NULL );
1186 timeout = get_next_io_timeout( &timeouts, total );
1188 pfd.fd = unix_handle;
1189 pfd.events = POLLOUT;
1191 if (!timeout || !(ret = poll( &pfd, 1, timeout )))
1193 /* return with what we got so far */
1194 status = total ? STATUS_SUCCESS : STATUS_TIMEOUT;
1195 goto done;
1197 if (ret == -1 && errno != EINTR)
1199 status = FILE_GetNtStatus();
1200 goto done;
1202 /* will now restart the write */
1206 done:
1207 send_completion = cvalue != 0;
1209 err:
1210 if (needs_close) close( unix_handle );
1212 if (type == FD_TYPE_SERIAL && (status == STATUS_SUCCESS || status == STATUS_PENDING))
1213 set_pending_write( hFile );
1215 if (status == STATUS_SUCCESS)
1217 io_status->u.Status = status;
1218 io_status->Information = total;
1219 TRACE("= SUCCESS (%u)\n", total);
1220 if (hEvent) NtSetEvent( hEvent, NULL );
1221 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1222 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1224 else
1226 TRACE("= 0x%08x\n", status);
1227 if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
1230 if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total );
1232 return status;
1236 /******************************************************************************
1237 * NtWriteFileGather [NTDLL.@]
1238 * ZwWriteFileGather [NTDLL.@]
1240 NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1241 PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
1242 ULONG length, PLARGE_INTEGER offset, PULONG key )
1244 int result, unix_handle, needs_close;
1245 unsigned int options;
1246 NTSTATUS status;
1247 ULONG pos = 0, total = 0;
1248 enum server_fd_type type;
1249 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
1250 BOOL send_completion = FALSE;
1252 TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
1253 file, event, apc, apc_user, io_status, segments, length, offset, key);
1255 if (length % page_size) return STATUS_INVALID_PARAMETER;
1256 if (!io_status) return STATUS_ACCESS_VIOLATION;
1258 status = server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
1259 &needs_close, &type, &options );
1260 if (status) return status;
1262 if ((type != FD_TYPE_FILE) ||
1263 (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
1264 !(options & FILE_NO_INTERMEDIATE_BUFFERING))
1266 status = STATUS_INVALID_PARAMETER;
1267 goto error;
1270 while (length)
1272 if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
1273 result = pwrite( unix_handle, (char *)segments->Buffer + pos,
1274 page_size - pos, offset->QuadPart + total );
1275 else
1276 result = write( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
1278 if (result == -1)
1280 if (errno == EINTR) continue;
1281 if (errno == EFAULT)
1283 status = STATUS_INVALID_USER_BUFFER;
1284 goto error;
1286 status = FILE_GetNtStatus();
1287 break;
1289 if (!result)
1291 status = STATUS_DISK_FULL;
1292 break;
1294 total += result;
1295 length -= result;
1296 if ((pos += result) == page_size)
1298 pos = 0;
1299 segments++;
1303 send_completion = cvalue != 0;
1305 error:
1306 if (needs_close) close( unix_handle );
1307 if (status == STATUS_SUCCESS)
1309 io_status->u.Status = status;
1310 io_status->Information = total;
1311 TRACE("= SUCCESS (%u)\n", total);
1312 if (event) NtSetEvent( event, NULL );
1313 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
1314 (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
1316 else
1318 TRACE("= 0x%08x\n", status);
1319 if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
1322 if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total );
1324 return status;
1328 struct async_ioctl
1330 HANDLE handle; /* handle to the device */
1331 HANDLE event; /* async event */
1332 void *buffer; /* buffer for output */
1333 ULONG size; /* size of buffer */
1334 PIO_APC_ROUTINE apc; /* user apc params */
1335 void *apc_arg;
1338 /* callback for ioctl user APC */
1339 static void WINAPI ioctl_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved )
1341 struct async_ioctl *async = arg;
1342 if (async->apc) async->apc( async->apc_arg, io, reserved );
1343 RtlFreeHeap( GetProcessHeap(), 0, async );
1346 /* callback for ioctl async I/O completion */
1347 static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS status, void **apc )
1349 struct async_ioctl *async = arg;
1351 if (status == STATUS_ALERTED)
1353 SERVER_START_REQ( get_ioctl_result )
1355 req->handle = wine_server_obj_handle( async->handle );
1356 req->user_arg = wine_server_client_ptr( async );
1357 wine_server_set_reply( req, async->buffer, async->size );
1358 status = wine_server_call( req );
1359 if (status != STATUS_PENDING) io->Information = wine_server_reply_size( reply );
1361 SERVER_END_REQ;
1363 if (status != STATUS_PENDING)
1365 io->u.Status = status;
1366 if (async->apc || async->event) *apc = ioctl_apc;
1368 return status;
1371 /* do an ioctl call through the server */
1372 static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
1373 PIO_APC_ROUTINE apc, PVOID apc_context,
1374 IO_STATUS_BLOCK *io, ULONG code,
1375 const void *in_buffer, ULONG in_size,
1376 PVOID out_buffer, ULONG out_size )
1378 struct async_ioctl *async;
1379 NTSTATUS status;
1380 HANDLE wait_handle;
1381 ULONG options;
1382 ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
1384 if (!(async = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*async) )))
1385 return STATUS_NO_MEMORY;
1386 async->handle = handle;
1387 async->event = event;
1388 async->buffer = out_buffer;
1389 async->size = out_size;
1390 async->apc = apc;
1391 async->apc_arg = apc_context;
1393 SERVER_START_REQ( ioctl )
1395 req->code = code;
1396 req->blocking = !apc && !event && !cvalue;
1397 req->async.handle = wine_server_obj_handle( handle );
1398 req->async.callback = wine_server_client_ptr( ioctl_completion );
1399 req->async.iosb = wine_server_client_ptr( io );
1400 req->async.arg = wine_server_client_ptr( async );
1401 req->async.event = wine_server_obj_handle( event );
1402 req->async.cvalue = cvalue;
1403 wine_server_add_data( req, in_buffer, in_size );
1404 wine_server_set_reply( req, out_buffer, out_size );
1405 status = wine_server_call( req );
1406 wait_handle = wine_server_ptr_handle( reply->wait );
1407 options = reply->options;
1408 if (status != STATUS_PENDING) io->Information = wine_server_reply_size( reply );
1410 SERVER_END_REQ;
1412 if (status == STATUS_NOT_SUPPORTED)
1413 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
1414 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1416 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
1418 if (wait_handle)
1420 NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL );
1421 status = io->u.Status;
1422 NtClose( wait_handle );
1423 RtlFreeHeap( GetProcessHeap(), 0, async );
1426 return status;
1429 /* Tell Valgrind to ignore any holes in structs we will be passing to the
1430 * server */
1431 static void ignore_server_ioctl_struct_holes (ULONG code, const void *in_buffer,
1432 ULONG in_size)
1434 #ifdef VALGRIND_MAKE_MEM_DEFINED
1435 # define IGNORE_STRUCT_HOLE(buf, size, t, f1, f2) \
1436 do { \
1437 if (FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1) < FIELD_OFFSET(t, f2)) \
1438 if ((size) >= FIELD_OFFSET(t, f2)) \
1439 VALGRIND_MAKE_MEM_DEFINED( \
1440 (const char *)(buf) + FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1), \
1441 FIELD_OFFSET(t, f2) - FIELD_OFFSET(t, f1) + sizeof(((t *)0)->f1)); \
1442 } while (0)
1444 switch (code)
1446 case FSCTL_PIPE_WAIT:
1447 IGNORE_STRUCT_HOLE(in_buffer, in_size, FILE_PIPE_WAIT_FOR_BUFFER, TimeoutSpecified, Name);
1448 break;
1450 #endif
1454 /**************************************************************************
1455 * NtDeviceIoControlFile [NTDLL.@]
1456 * ZwDeviceIoControlFile [NTDLL.@]
1458 * Perform an I/O control operation on an open file handle.
1460 * PARAMS
1461 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1462 * event [I] Event to signal upon completion (or NULL)
1463 * apc [I] Callback to call upon completion (or NULL)
1464 * apc_context [I] Context for ApcRoutine (or NULL)
1465 * io [O] Receives information about the operation on return
1466 * code [I] Control code for the operation to perform
1467 * in_buffer [I] Source for any input data required (or NULL)
1468 * in_size [I] Size of InputBuffer
1469 * out_buffer [O] Source for any output data returned (or NULL)
1470 * out_size [I] Size of OutputBuffer
1472 * RETURNS
1473 * Success: 0. IoStatusBlock is updated.
1474 * Failure: An NTSTATUS error code describing the error.
1476 NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
1477 PIO_APC_ROUTINE apc, PVOID apc_context,
1478 PIO_STATUS_BLOCK io, ULONG code,
1479 PVOID in_buffer, ULONG in_size,
1480 PVOID out_buffer, ULONG out_size)
1482 ULONG device = (code >> 16);
1483 NTSTATUS status = STATUS_NOT_SUPPORTED;
1485 TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1486 handle, event, apc, apc_context, io, code,
1487 in_buffer, in_size, out_buffer, out_size);
1489 switch(device)
1491 case FILE_DEVICE_DISK:
1492 case FILE_DEVICE_CD_ROM:
1493 case FILE_DEVICE_DVD:
1494 case FILE_DEVICE_CONTROLLER:
1495 case FILE_DEVICE_MASS_STORAGE:
1496 status = CDROM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1497 in_buffer, in_size, out_buffer, out_size);
1498 break;
1499 case FILE_DEVICE_SERIAL_PORT:
1500 status = COMM_DeviceIoControl(handle, event, apc, apc_context, io, code,
1501 in_buffer, in_size, out_buffer, out_size);
1502 break;
1503 case FILE_DEVICE_TAPE:
1504 status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
1505 in_buffer, in_size, out_buffer, out_size);
1506 break;
1509 if (status == STATUS_NOT_SUPPORTED || status == STATUS_BAD_DEVICE_TYPE)
1510 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1511 in_buffer, in_size, out_buffer, out_size );
1513 if (status != STATUS_PENDING) io->u.Status = status;
1514 return status;
1518 /**************************************************************************
1519 * NtFsControlFile [NTDLL.@]
1520 * ZwFsControlFile [NTDLL.@]
1522 * Perform a file system control operation on an open file handle.
1524 * PARAMS
1525 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1526 * event [I] Event to signal upon completion (or NULL)
1527 * apc [I] Callback to call upon completion (or NULL)
1528 * apc_context [I] Context for ApcRoutine (or NULL)
1529 * io [O] Receives information about the operation on return
1530 * code [I] Control code for the operation to perform
1531 * in_buffer [I] Source for any input data required (or NULL)
1532 * in_size [I] Size of InputBuffer
1533 * out_buffer [O] Source for any output data returned (or NULL)
1534 * out_size [I] Size of OutputBuffer
1536 * RETURNS
1537 * Success: 0. IoStatusBlock is updated.
1538 * Failure: An NTSTATUS error code describing the error.
1540 NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
1541 PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code,
1542 PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size)
1544 NTSTATUS status;
1546 TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
1547 handle, event, apc, apc_context, io, code,
1548 in_buffer, in_size, out_buffer, out_size);
1550 if (!io) return STATUS_INVALID_PARAMETER;
1552 ignore_server_ioctl_struct_holes( code, in_buffer, in_size );
1554 switch(code)
1556 case FSCTL_DISMOUNT_VOLUME:
1557 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1558 in_buffer, in_size, out_buffer, out_size );
1559 if (!status) status = DIR_unmount_device( handle );
1560 break;
1562 case FSCTL_PIPE_PEEK:
1564 FILE_PIPE_PEEK_BUFFER *buffer = out_buffer;
1565 int avail = 0, fd, needs_close;
1567 if (out_size < FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ))
1569 status = STATUS_INFO_LENGTH_MISMATCH;
1570 break;
1573 if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )))
1574 break;
1576 #ifdef FIONREAD
1577 if (ioctl( fd, FIONREAD, &avail ) != 0)
1579 TRACE("FIONREAD failed reason: %s\n",strerror(errno));
1580 if (needs_close) close( fd );
1581 status = FILE_GetNtStatus();
1582 break;
1584 #endif
1585 if (!avail) /* check for closed pipe */
1587 struct pollfd pollfd;
1588 int ret;
1590 pollfd.fd = fd;
1591 pollfd.events = POLLIN;
1592 pollfd.revents = 0;
1593 ret = poll( &pollfd, 1, 0 );
1594 if (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR))))
1596 if (needs_close) close( fd );
1597 status = STATUS_PIPE_BROKEN;
1598 break;
1601 buffer->NamedPipeState = 0; /* FIXME */
1602 buffer->ReadDataAvailable = avail;
1603 buffer->NumberOfMessages = 0; /* FIXME */
1604 buffer->MessageLength = 0; /* FIXME */
1605 io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1606 status = STATUS_SUCCESS;
1607 if (avail)
1609 ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
1610 if (data_size)
1612 int res = recv( fd, buffer->Data, data_size, MSG_PEEK );
1613 if (res >= 0) io->Information += res;
1616 if (needs_close) close( fd );
1618 break;
1620 case FSCTL_PIPE_DISCONNECT:
1621 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1622 in_buffer, in_size, out_buffer, out_size );
1623 if (!status)
1625 int fd = server_remove_fd_from_cache( handle );
1626 if (fd != -1) close( fd );
1628 break;
1630 case FSCTL_PIPE_IMPERSONATE:
1631 FIXME("FSCTL_PIPE_IMPERSONATE: impersonating self\n");
1632 status = RtlImpersonateSelf( SecurityImpersonation );
1633 break;
1635 case FSCTL_IS_VOLUME_MOUNTED:
1636 case FSCTL_LOCK_VOLUME:
1637 case FSCTL_UNLOCK_VOLUME:
1638 FIXME("stub! return success - Unsupported fsctl %x (device=%x access=%x func=%x method=%x)\n",
1639 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1640 status = STATUS_SUCCESS;
1641 break;
1643 case FSCTL_GET_RETRIEVAL_POINTERS:
1645 RETRIEVAL_POINTERS_BUFFER *buffer = (RETRIEVAL_POINTERS_BUFFER *)out_buffer;
1647 FIXME("stub: FSCTL_GET_RETRIEVAL_POINTERS\n");
1649 if (out_size >= sizeof(RETRIEVAL_POINTERS_BUFFER))
1651 buffer->ExtentCount = 1;
1652 buffer->StartingVcn.QuadPart = 1;
1653 buffer->Extents[0].NextVcn.QuadPart = 0;
1654 buffer->Extents[0].Lcn.QuadPart = 0;
1655 io->Information = sizeof(RETRIEVAL_POINTERS_BUFFER);
1656 status = STATUS_SUCCESS;
1658 else
1660 io->Information = 0;
1661 status = STATUS_BUFFER_TOO_SMALL;
1663 break;
1665 case FSCTL_PIPE_LISTEN:
1666 case FSCTL_PIPE_WAIT:
1667 default:
1668 status = server_ioctl_file( handle, event, apc, apc_context, io, code,
1669 in_buffer, in_size, out_buffer, out_size );
1670 break;
1673 if (status != STATUS_PENDING) io->u.Status = status;
1674 return status;
1677 /******************************************************************************
1678 * NtSetVolumeInformationFile [NTDLL.@]
1679 * ZwSetVolumeInformationFile [NTDLL.@]
1681 * Set volume information for an open file handle.
1683 * PARAMS
1684 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1685 * IoStatusBlock [O] Receives information about the operation on return
1686 * FsInformation [I] Source for volume information
1687 * Length [I] Size of FsInformation
1688 * FsInformationClass [I] Type of volume information to set
1690 * RETURNS
1691 * Success: 0. IoStatusBlock is updated.
1692 * Failure: An NTSTATUS error code describing the error.
1694 NTSTATUS WINAPI NtSetVolumeInformationFile(
1695 IN HANDLE FileHandle,
1696 PIO_STATUS_BLOCK IoStatusBlock,
1697 PVOID FsInformation,
1698 ULONG Length,
1699 FS_INFORMATION_CLASS FsInformationClass)
1701 FIXME("(%p,%p,%p,0x%08x,0x%08x) stub\n",
1702 FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass);
1703 return 0;
1706 #if defined(__ANDROID__) && !defined(HAVE_FUTIMENS)
1707 static int futimens( int fd, const struct timespec spec[2] )
1709 return syscall( __NR_utimensat, fd, NULL, spec, 0 );
1711 #define HAVE_FUTIMENS
1712 #endif /* __ANDROID__ */
1714 #ifndef UTIME_OMIT
1715 #define UTIME_OMIT ((1 << 30) - 2)
1716 #endif
1718 static NTSTATUS set_file_times( int fd, const LARGE_INTEGER *mtime, const LARGE_INTEGER *atime )
1720 NTSTATUS status = STATUS_SUCCESS;
1722 #ifdef HAVE_FUTIMENS
1723 struct timespec tv[2];
1725 tv[0].tv_sec = tv[1].tv_sec = 0;
1726 tv[0].tv_nsec = tv[1].tv_nsec = UTIME_OMIT;
1727 if (atime->QuadPart)
1729 tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
1730 tv[0].tv_nsec = (atime->QuadPart % 10000000) * 100;
1732 if (mtime->QuadPart)
1734 tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
1735 tv[1].tv_nsec = (mtime->QuadPart % 10000000) * 100;
1737 if (futimens( fd, tv ) == -1) status = FILE_GetNtStatus();
1739 #elif defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
1740 struct timeval tv[2];
1741 struct stat st;
1743 if (!atime->QuadPart || !mtime->QuadPart)
1746 tv[0].tv_sec = tv[0].tv_usec = 0;
1747 tv[1].tv_sec = tv[1].tv_usec = 0;
1748 if (!fstat( fd, &st ))
1750 tv[0].tv_sec = st.st_atime;
1751 tv[1].tv_sec = st.st_mtime;
1752 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1753 tv[0].tv_usec = st.st_atim.tv_nsec / 1000;
1754 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
1755 tv[0].tv_usec = st.st_atimespec.tv_nsec / 1000;
1756 #endif
1757 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1758 tv[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1759 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
1760 tv[1].tv_usec = st.st_mtimespec.tv_nsec / 1000;
1761 #endif
1764 if (atime->QuadPart)
1766 tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
1767 tv[0].tv_usec = (atime->QuadPart % 10000000) / 10;
1769 if (mtime->QuadPart)
1771 tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
1772 tv[1].tv_usec = (mtime->QuadPart % 10000000) / 10;
1774 #ifdef HAVE_FUTIMES
1775 if (futimes( fd, tv ) == -1) status = FILE_GetNtStatus();
1776 #elif defined(HAVE_FUTIMESAT)
1777 if (futimesat( fd, NULL, tv ) == -1) status = FILE_GetNtStatus();
1778 #endif
1780 #else /* HAVE_FUTIMES || HAVE_FUTIMESAT */
1781 FIXME( "setting file times not supported\n" );
1782 status = STATUS_NOT_IMPLEMENTED;
1783 #endif
1784 return status;
1787 static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, LARGE_INTEGER *ctime,
1788 LARGE_INTEGER *atime, LARGE_INTEGER *creation )
1790 RtlSecondsSince1970ToTime( st->st_mtime, mtime );
1791 RtlSecondsSince1970ToTime( st->st_ctime, ctime );
1792 RtlSecondsSince1970ToTime( st->st_atime, atime );
1793 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1794 mtime->QuadPart += st->st_mtim.tv_nsec / 100;
1795 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
1796 mtime->QuadPart += st->st_mtimespec.tv_nsec / 100;
1797 #endif
1798 #ifdef HAVE_STRUCT_STAT_ST_CTIM
1799 ctime->QuadPart += st->st_ctim.tv_nsec / 100;
1800 #elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
1801 ctime->QuadPart += st->st_ctimespec.tv_nsec / 100;
1802 #endif
1803 #ifdef HAVE_STRUCT_STAT_ST_ATIM
1804 atime->QuadPart += st->st_atim.tv_nsec / 100;
1805 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
1806 atime->QuadPart += st->st_atimespec.tv_nsec / 100;
1807 #endif
1808 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
1809 RtlSecondsSince1970ToTime( st->st_birthtime, creation );
1810 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIM
1811 creation->QuadPart += st->st_birthtim.tv_nsec / 100;
1812 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
1813 creation->QuadPart += st->st_birthtimespec.tv_nsec / 100;
1814 #endif
1815 #elif defined(HAVE_STRUCT_STAT___ST_BIRTHTIME)
1816 RtlSecondsSince1970ToTime( st->__st_birthtime, creation );
1817 #ifdef HAVE_STRUCT_STAT___ST_BIRTHTIM
1818 creation->QuadPart += st->__st_birthtim.tv_nsec / 100;
1819 #endif
1820 #else
1821 *creation = *mtime;
1822 #endif
1825 /* fill in the file information that depends on the stat and attribute info */
1826 NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
1827 FILE_INFORMATION_CLASS class )
1829 switch (class)
1831 case FileBasicInformation:
1833 FILE_BASIC_INFORMATION *info = ptr;
1835 get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
1836 &info->LastAccessTime, &info->CreationTime );
1837 info->FileAttributes = attr;
1839 break;
1840 case FileStandardInformation:
1842 FILE_STANDARD_INFORMATION *info = ptr;
1844 if ((info->Directory = S_ISDIR(st->st_mode)))
1846 info->AllocationSize.QuadPart = 0;
1847 info->EndOfFile.QuadPart = 0;
1848 info->NumberOfLinks = 1;
1850 else
1852 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
1853 info->EndOfFile.QuadPart = st->st_size;
1854 info->NumberOfLinks = st->st_nlink;
1857 break;
1858 case FileInternalInformation:
1860 FILE_INTERNAL_INFORMATION *info = ptr;
1861 info->IndexNumber.QuadPart = st->st_ino;
1863 break;
1864 case FileEndOfFileInformation:
1866 FILE_END_OF_FILE_INFORMATION *info = ptr;
1867 info->EndOfFile.QuadPart = S_ISDIR(st->st_mode) ? 0 : st->st_size;
1869 break;
1870 case FileAllInformation:
1872 FILE_ALL_INFORMATION *info = ptr;
1873 fill_file_info( st, attr, &info->BasicInformation, FileBasicInformation );
1874 fill_file_info( st, attr, &info->StandardInformation, FileStandardInformation );
1875 fill_file_info( st, attr, &info->InternalInformation, FileInternalInformation );
1877 break;
1878 /* all directory structures start with the FileDirectoryInformation layout */
1879 case FileBothDirectoryInformation:
1880 case FileFullDirectoryInformation:
1881 case FileDirectoryInformation:
1883 FILE_DIRECTORY_INFORMATION *info = ptr;
1885 get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
1886 &info->LastAccessTime, &info->CreationTime );
1887 if (S_ISDIR(st->st_mode))
1889 info->AllocationSize.QuadPart = 0;
1890 info->EndOfFile.QuadPart = 0;
1892 else
1894 info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
1895 info->EndOfFile.QuadPart = st->st_size;
1897 info->FileAttributes = attr;
1899 break;
1900 case FileIdFullDirectoryInformation:
1902 FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr;
1903 info->FileId.QuadPart = st->st_ino;
1904 fill_file_info( st, attr, info, FileDirectoryInformation );
1906 break;
1907 case FileIdBothDirectoryInformation:
1909 FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr;
1910 info->FileId.QuadPart = st->st_ino;
1911 fill_file_info( st, attr, info, FileDirectoryInformation );
1913 break;
1915 default:
1916 return STATUS_INVALID_INFO_CLASS;
1918 return STATUS_SUCCESS;
1921 NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name )
1923 data_size_t size = 1024;
1924 NTSTATUS ret;
1925 char *name;
1927 for (;;)
1929 name = RtlAllocateHeap( GetProcessHeap(), 0, size + 1 );
1930 if (!name) return STATUS_NO_MEMORY;
1931 unix_name->MaximumLength = size + 1;
1933 SERVER_START_REQ( get_handle_unix_name )
1935 req->handle = wine_server_obj_handle( handle );
1936 wine_server_set_reply( req, name, size );
1937 ret = wine_server_call( req );
1938 size = reply->name_len;
1940 SERVER_END_REQ;
1942 if (!ret)
1944 name[size] = 0;
1945 unix_name->Buffer = name;
1946 unix_name->Length = size;
1947 break;
1949 RtlFreeHeap( GetProcessHeap(), 0, name );
1950 if (ret != STATUS_BUFFER_OVERFLOW) break;
1952 return ret;
1955 static NTSTATUS fill_name_info( const ANSI_STRING *unix_name, FILE_NAME_INFORMATION *info, LONG *name_len )
1957 UNICODE_STRING nt_name;
1958 NTSTATUS status;
1960 if (!(status = wine_unix_to_nt_file_name( unix_name, &nt_name )))
1962 const WCHAR *ptr = nt_name.Buffer;
1963 const WCHAR *end = ptr + (nt_name.Length / sizeof(WCHAR));
1965 /* Skip the volume mount point. */
1966 while (ptr != end && *ptr == '\\') ++ptr;
1967 while (ptr != end && *ptr != '\\') ++ptr;
1968 while (ptr != end && *ptr == '\\') ++ptr;
1969 while (ptr != end && *ptr != '\\') ++ptr;
1971 info->FileNameLength = (end - ptr) * sizeof(WCHAR);
1972 if (*name_len < info->FileNameLength) status = STATUS_BUFFER_OVERFLOW;
1973 else *name_len = info->FileNameLength;
1975 memcpy( info->FileName, ptr, *name_len );
1976 RtlFreeUnicodeString( &nt_name );
1979 return status;
1982 /******************************************************************************
1983 * NtQueryInformationFile [NTDLL.@]
1984 * ZwQueryInformationFile [NTDLL.@]
1986 * Get information about an open file handle.
1988 * PARAMS
1989 * hFile [I] Handle returned from ZwOpenFile() or ZwCreateFile()
1990 * io [O] Receives information about the operation on return
1991 * ptr [O] Destination for file information
1992 * len [I] Size of FileInformation
1993 * class [I] Type of file information to get
1995 * RETURNS
1996 * Success: 0. IoStatusBlock and FileInformation are updated.
1997 * Failure: An NTSTATUS error code describing the error.
1999 NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
2000 PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
2002 static const size_t info_sizes[] =
2005 sizeof(FILE_DIRECTORY_INFORMATION), /* FileDirectoryInformation */
2006 sizeof(FILE_FULL_DIRECTORY_INFORMATION), /* FileFullDirectoryInformation */
2007 sizeof(FILE_BOTH_DIRECTORY_INFORMATION), /* FileBothDirectoryInformation */
2008 sizeof(FILE_BASIC_INFORMATION), /* FileBasicInformation */
2009 sizeof(FILE_STANDARD_INFORMATION), /* FileStandardInformation */
2010 sizeof(FILE_INTERNAL_INFORMATION), /* FileInternalInformation */
2011 sizeof(FILE_EA_INFORMATION), /* FileEaInformation */
2012 sizeof(FILE_ACCESS_INFORMATION), /* FileAccessInformation */
2013 sizeof(FILE_NAME_INFORMATION), /* FileNameInformation */
2014 sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
2015 0, /* FileLinkInformation */
2016 sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR), /* FileNamesInformation */
2017 sizeof(FILE_DISPOSITION_INFORMATION), /* FileDispositionInformation */
2018 sizeof(FILE_POSITION_INFORMATION), /* FilePositionInformation */
2019 sizeof(FILE_FULL_EA_INFORMATION), /* FileFullEaInformation */
2020 sizeof(FILE_MODE_INFORMATION), /* FileModeInformation */
2021 sizeof(FILE_ALIGNMENT_INFORMATION), /* FileAlignmentInformation */
2022 sizeof(FILE_ALL_INFORMATION), /* FileAllInformation */
2023 sizeof(FILE_ALLOCATION_INFORMATION), /* FileAllocationInformation */
2024 sizeof(FILE_END_OF_FILE_INFORMATION), /* FileEndOfFileInformation */
2025 0, /* FileAlternateNameInformation */
2026 sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
2027 sizeof(FILE_PIPE_INFORMATION), /* FilePipeInformation */
2028 sizeof(FILE_PIPE_LOCAL_INFORMATION), /* FilePipeLocalInformation */
2029 0, /* FilePipeRemoteInformation */
2030 sizeof(FILE_MAILSLOT_QUERY_INFORMATION), /* FileMailslotQueryInformation */
2031 0, /* FileMailslotSetInformation */
2032 0, /* FileCompressionInformation */
2033 0, /* FileObjectIdInformation */
2034 0, /* FileCompletionInformation */
2035 0, /* FileMoveClusterInformation */
2036 0, /* FileQuotaInformation */
2037 0, /* FileReparsePointInformation */
2038 0, /* FileNetworkOpenInformation */
2039 0, /* FileAttributeTagInformation */
2040 0, /* FileTrackingInformation */
2041 0, /* FileIdBothDirectoryInformation */
2042 0, /* FileIdFullDirectoryInformation */
2043 0, /* FileValidDataLengthInformation */
2044 0, /* FileShortNameInformation */
2048 0, /* FileSfioReserveInformation */
2049 0, /* FileSfioVolumeInformation */
2050 0, /* FileHardLinkInformation */
2052 0, /* FileNormalizedNameInformation */
2054 0, /* FileIdGlobalTxDirectoryInformation */
2058 0 /* FileStandardLinkInformation */
2061 struct stat st;
2062 int fd, needs_close = FALSE;
2063 ULONG attr;
2065 TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
2067 io->Information = 0;
2069 if (class <= 0 || class >= FileMaximumInformation)
2070 return io->u.Status = STATUS_INVALID_INFO_CLASS;
2071 if (!info_sizes[class])
2073 FIXME("Unsupported class (%d)\n", class);
2074 return io->u.Status = STATUS_NOT_IMPLEMENTED;
2076 if (len < info_sizes[class])
2077 return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
2079 if (class != FilePipeInformation && class != FilePipeLocalInformation)
2081 if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, NULL )))
2082 return io->u.Status;
2085 switch (class)
2087 case FileBasicInformation:
2088 if (fd_get_file_info( fd, &st, &attr ) == -1)
2089 io->u.Status = FILE_GetNtStatus();
2090 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2091 io->u.Status = STATUS_INVALID_INFO_CLASS;
2092 else
2093 fill_file_info( &st, attr, ptr, class );
2094 break;
2095 case FileStandardInformation:
2097 FILE_STANDARD_INFORMATION *info = ptr;
2099 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2100 else
2102 fill_file_info( &st, attr, info, class );
2103 info->DeletePending = FALSE; /* FIXME */
2106 break;
2107 case FilePositionInformation:
2109 FILE_POSITION_INFORMATION *info = ptr;
2110 off_t res = lseek( fd, 0, SEEK_CUR );
2111 if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
2112 else info->CurrentByteOffset.QuadPart = res;
2114 break;
2115 case FileInternalInformation:
2116 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2117 else fill_file_info( &st, attr, ptr, class );
2118 break;
2119 case FileEaInformation:
2121 FILE_EA_INFORMATION *info = ptr;
2122 info->EaSize = 0;
2124 break;
2125 case FileEndOfFileInformation:
2126 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2127 else fill_file_info( &st, attr, ptr, class );
2128 break;
2129 case FileAllInformation:
2131 FILE_ALL_INFORMATION *info = ptr;
2132 ANSI_STRING unix_name;
2134 if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
2135 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2136 io->u.Status = STATUS_INVALID_INFO_CLASS;
2137 else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2139 LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
2141 fill_file_info( &st, attr, info, FileAllInformation );
2142 info->StandardInformation.DeletePending = FALSE; /* FIXME */
2143 info->EaInformation.EaSize = 0;
2144 info->AccessInformation.AccessFlags = 0; /* FIXME */
2145 info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
2146 info->ModeInformation.Mode = 0; /* FIXME */
2147 info->AlignmentInformation.AlignmentRequirement = 1; /* FIXME */
2149 io->u.Status = fill_name_info( &unix_name, &info->NameInformation, &name_len );
2150 RtlFreeAnsiString( &unix_name );
2151 io->Information = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + name_len;
2154 break;
2155 case FileMailslotQueryInformation:
2157 FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
2159 SERVER_START_REQ( set_mailslot_info )
2161 req->handle = wine_server_obj_handle( hFile );
2162 req->flags = 0;
2163 io->u.Status = wine_server_call( req );
2164 if( io->u.Status == STATUS_SUCCESS )
2166 info->MaximumMessageSize = reply->max_msgsize;
2167 info->MailslotQuota = 0;
2168 info->NextMessageSize = 0;
2169 info->MessagesAvailable = 0;
2170 info->ReadTimeout.QuadPart = reply->read_timeout;
2173 SERVER_END_REQ;
2174 if (!io->u.Status)
2176 char *tmpbuf;
2177 ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000;
2178 if (size > 0x10000) size = 0x10000;
2179 if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2181 if (!server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
2183 int res = recv( fd, tmpbuf, size, MSG_PEEK );
2184 info->MessagesAvailable = (res > 0);
2185 info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE;
2186 if (needs_close) close( fd );
2188 RtlFreeHeap( GetProcessHeap(), 0, tmpbuf );
2192 break;
2193 case FilePipeInformation:
2195 FILE_PIPE_INFORMATION* pi = ptr;
2197 SERVER_START_REQ( get_named_pipe_info )
2199 req->handle = wine_server_obj_handle( hFile );
2200 if (!(io->u.Status = wine_server_call( req )))
2202 pi->ReadMode = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_READ) ?
2203 FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
2204 pi->CompletionMode = (reply->flags & NAMED_PIPE_NONBLOCKING_MODE) ?
2205 FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
2208 SERVER_END_REQ;
2210 break;
2211 case FilePipeLocalInformation:
2213 FILE_PIPE_LOCAL_INFORMATION* pli = ptr;
2215 SERVER_START_REQ( get_named_pipe_info )
2217 req->handle = wine_server_obj_handle( hFile );
2218 if (!(io->u.Status = wine_server_call( req )))
2220 pli->NamedPipeType = (reply->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ?
2221 FILE_PIPE_TYPE_MESSAGE : FILE_PIPE_TYPE_BYTE;
2222 switch (reply->sharing)
2224 case FILE_SHARE_READ:
2225 pli->NamedPipeConfiguration = FILE_PIPE_OUTBOUND;
2226 break;
2227 case FILE_SHARE_WRITE:
2228 pli->NamedPipeConfiguration = FILE_PIPE_INBOUND;
2229 break;
2230 case FILE_SHARE_READ | FILE_SHARE_WRITE:
2231 pli->NamedPipeConfiguration = FILE_PIPE_FULL_DUPLEX;
2232 break;
2234 pli->MaximumInstances = reply->maxinstances;
2235 pli->CurrentInstances = reply->instances;
2236 pli->InboundQuota = reply->insize;
2237 pli->ReadDataAvailable = 0; /* FIXME */
2238 pli->OutboundQuota = reply->outsize;
2239 pli->WriteQuotaAvailable = 0; /* FIXME */
2240 pli->NamedPipeState = 0; /* FIXME */
2241 pli->NamedPipeEnd = (reply->flags & NAMED_PIPE_SERVER_END) ?
2242 FILE_PIPE_SERVER_END : FILE_PIPE_CLIENT_END;
2245 SERVER_END_REQ;
2247 break;
2248 case FileNameInformation:
2250 FILE_NAME_INFORMATION *info = ptr;
2251 ANSI_STRING unix_name;
2253 if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
2255 LONG name_len = len - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2256 io->u.Status = fill_name_info( &unix_name, info, &name_len );
2257 RtlFreeAnsiString( &unix_name );
2258 io->Information = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + name_len;
2261 break;
2262 default:
2263 FIXME("Unsupported class (%d)\n", class);
2264 io->u.Status = STATUS_NOT_IMPLEMENTED;
2265 break;
2267 if (needs_close) close( fd );
2268 if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
2269 return io->u.Status;
2272 /******************************************************************************
2273 * NtSetInformationFile [NTDLL.@]
2274 * ZwSetInformationFile [NTDLL.@]
2276 * Set information about an open file handle.
2278 * PARAMS
2279 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2280 * io [O] Receives information about the operation on return
2281 * ptr [I] Source for file information
2282 * len [I] Size of FileInformation
2283 * class [I] Type of file information to set
2285 * RETURNS
2286 * Success: 0. io is updated.
2287 * Failure: An NTSTATUS error code describing the error.
2289 NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
2290 PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
2292 int fd, needs_close;
2294 TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", handle, io, ptr, len, class);
2296 io->u.Status = STATUS_SUCCESS;
2297 switch (class)
2299 case FileBasicInformation:
2300 if (len >= sizeof(FILE_BASIC_INFORMATION))
2302 struct stat st;
2303 const FILE_BASIC_INFORMATION *info = ptr;
2305 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2306 return io->u.Status;
2308 if (info->LastAccessTime.QuadPart || info->LastWriteTime.QuadPart)
2309 io->u.Status = set_file_times( fd, &info->LastWriteTime, &info->LastAccessTime );
2311 if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
2313 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2314 else
2316 if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
2318 if (S_ISDIR( st.st_mode))
2319 WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
2320 else
2321 st.st_mode &= ~0222; /* clear write permission bits */
2323 else
2325 /* add write permission only where we already have read permission */
2326 st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
2328 if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
2332 if (needs_close) close( fd );
2334 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2335 break;
2337 case FilePositionInformation:
2338 if (len >= sizeof(FILE_POSITION_INFORMATION))
2340 const FILE_POSITION_INFORMATION *info = ptr;
2342 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2343 return io->u.Status;
2345 if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
2346 io->u.Status = FILE_GetNtStatus();
2348 if (needs_close) close( fd );
2350 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2351 break;
2353 case FileEndOfFileInformation:
2354 if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
2356 struct stat st;
2357 const FILE_END_OF_FILE_INFORMATION *info = ptr;
2359 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2360 return io->u.Status;
2362 /* first try normal truncate */
2363 if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2365 /* now check for the need to extend the file */
2366 if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
2368 static const char zero;
2370 /* extend the file one byte beyond the requested size and then truncate it */
2371 /* this should work around ftruncate implementations that can't extend files */
2372 if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
2373 ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
2375 io->u.Status = FILE_GetNtStatus();
2377 if (needs_close) close( fd );
2379 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2380 break;
2382 case FilePipeInformation:
2383 if (len >= sizeof(FILE_PIPE_INFORMATION))
2385 FILE_PIPE_INFORMATION *info = ptr;
2387 if ((info->CompletionMode | info->ReadMode) & ~1)
2389 io->u.Status = STATUS_INVALID_PARAMETER;
2390 break;
2393 SERVER_START_REQ( set_named_pipe_info )
2395 req->handle = wine_server_obj_handle( handle );
2396 req->flags = (info->CompletionMode ? NAMED_PIPE_NONBLOCKING_MODE : 0) |
2397 (info->ReadMode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0);
2398 io->u.Status = wine_server_call( req );
2400 SERVER_END_REQ;
2402 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2403 break;
2405 case FileMailslotSetInformation:
2407 FILE_MAILSLOT_SET_INFORMATION *info = ptr;
2409 SERVER_START_REQ( set_mailslot_info )
2411 req->handle = wine_server_obj_handle( handle );
2412 req->flags = MAILSLOT_SET_READ_TIMEOUT;
2413 req->read_timeout = info->ReadTimeout.QuadPart;
2414 io->u.Status = wine_server_call( req );
2416 SERVER_END_REQ;
2418 break;
2420 case FileCompletionInformation:
2421 if (len >= sizeof(FILE_COMPLETION_INFORMATION))
2423 FILE_COMPLETION_INFORMATION *info = ptr;
2425 SERVER_START_REQ( set_completion_info )
2427 req->handle = wine_server_obj_handle( handle );
2428 req->chandle = wine_server_obj_handle( info->CompletionPort );
2429 req->ckey = info->CompletionKey;
2430 io->u.Status = wine_server_call( req );
2432 SERVER_END_REQ;
2433 } else
2434 io->u.Status = STATUS_INVALID_PARAMETER_3;
2435 break;
2437 case FileAllInformation:
2438 io->u.Status = STATUS_INVALID_INFO_CLASS;
2439 break;
2441 case FileValidDataLengthInformation:
2442 if (len >= sizeof(FILE_VALID_DATA_LENGTH_INFORMATION))
2444 struct stat st;
2445 const FILE_VALID_DATA_LENGTH_INFORMATION *info = ptr;
2447 if ((io->u.Status = server_get_unix_fd( handle, FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL )))
2448 return io->u.Status;
2450 if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
2451 else if (info->ValidDataLength.QuadPart <= 0 || (off_t)info->ValidDataLength.QuadPart > st.st_size)
2452 io->u.Status = STATUS_INVALID_PARAMETER;
2453 else
2455 #ifdef HAVE_FALLOCATE
2456 if (fallocate( fd, 0, 0, (off_t)info->ValidDataLength.QuadPart ) == -1)
2458 NTSTATUS status = FILE_GetNtStatus();
2459 if (status == STATUS_NOT_SUPPORTED) WARN( "fallocate not supported on this filesystem\n" );
2460 else io->u.Status = status;
2462 #else
2463 FIXME( "setting valid data length not supported\n" );
2464 #endif
2466 if (needs_close) close( fd );
2468 else io->u.Status = STATUS_INVALID_PARAMETER_3;
2469 break;
2471 default:
2472 FIXME("Unsupported class (%d)\n", class);
2473 io->u.Status = STATUS_NOT_IMPLEMENTED;
2474 break;
2476 io->Information = 0;
2477 return io->u.Status;
2481 /******************************************************************************
2482 * NtQueryFullAttributesFile (NTDLL.@)
2484 NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
2485 FILE_NETWORK_OPEN_INFORMATION *info )
2487 ANSI_STRING unix_name;
2488 NTSTATUS status;
2490 if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2492 ULONG attributes;
2493 struct stat st;
2495 if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
2496 status = FILE_GetNtStatus();
2497 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2498 status = STATUS_INVALID_INFO_CLASS;
2499 else
2501 FILE_BASIC_INFORMATION basic;
2502 FILE_STANDARD_INFORMATION std;
2504 fill_file_info( &st, attributes, &basic, FileBasicInformation );
2505 fill_file_info( &st, attributes, &std, FileStandardInformation );
2507 info->CreationTime = basic.CreationTime;
2508 info->LastAccessTime = basic.LastAccessTime;
2509 info->LastWriteTime = basic.LastWriteTime;
2510 info->ChangeTime = basic.ChangeTime;
2511 info->AllocationSize = std.AllocationSize;
2512 info->EndOfFile = std.EndOfFile;
2513 info->FileAttributes = basic.FileAttributes;
2514 if (DIR_is_hidden_file( attr->ObjectName ))
2515 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2517 RtlFreeAnsiString( &unix_name );
2519 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2520 return status;
2524 /******************************************************************************
2525 * NtQueryAttributesFile (NTDLL.@)
2526 * ZwQueryAttributesFile (NTDLL.@)
2528 NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info )
2530 ANSI_STRING unix_name;
2531 NTSTATUS status;
2533 if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
2535 ULONG attributes;
2536 struct stat st;
2538 if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
2539 status = FILE_GetNtStatus();
2540 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2541 status = STATUS_INVALID_INFO_CLASS;
2542 else
2544 status = fill_file_info( &st, attributes, info, FileBasicInformation );
2545 if (DIR_is_hidden_file( attr->ObjectName ))
2546 info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
2548 RtlFreeAnsiString( &unix_name );
2550 else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
2551 return status;
2555 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2556 /* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */
2557 static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename,
2558 unsigned int flags )
2560 if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename))
2562 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2563 /* Don't assume read-only, let the mount options set it below */
2564 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2566 else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) ||
2567 !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename))
2569 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2570 info->Characteristics |= FILE_REMOTE_DEVICE;
2572 else if (!strcmp("procfs", fstypename))
2573 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2574 else
2575 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2577 if (flags & MNT_RDONLY)
2578 info->Characteristics |= FILE_READ_ONLY_DEVICE;
2580 if (!(flags & MNT_LOCAL))
2582 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2583 info->Characteristics |= FILE_REMOTE_DEVICE;
2586 #endif
2588 static inline BOOL is_device_placeholder( int fd )
2590 static const char wine_placeholder[] = "Wine device placeholder";
2591 char buffer[sizeof(wine_placeholder)-1];
2593 if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
2594 return FALSE;
2595 return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
2598 /******************************************************************************
2599 * get_device_info
2601 * Implementation of the FileFsDeviceInformation query for NtQueryVolumeInformationFile.
2603 static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
2605 struct stat st;
2607 info->Characteristics = 0;
2608 if (fstat( fd, &st ) < 0) return FILE_GetNtStatus();
2609 if (S_ISCHR( st.st_mode ))
2611 info->DeviceType = FILE_DEVICE_UNKNOWN;
2612 #ifdef linux
2613 switch(major(st.st_rdev))
2615 case MEM_MAJOR:
2616 info->DeviceType = FILE_DEVICE_NULL;
2617 break;
2618 case TTY_MAJOR:
2619 info->DeviceType = FILE_DEVICE_SERIAL_PORT;
2620 break;
2621 case LP_MAJOR:
2622 info->DeviceType = FILE_DEVICE_PARALLEL_PORT;
2623 break;
2624 case SCSI_TAPE_MAJOR:
2625 info->DeviceType = FILE_DEVICE_TAPE;
2626 break;
2628 #endif
2630 else if (S_ISBLK( st.st_mode ))
2632 info->DeviceType = FILE_DEVICE_DISK;
2634 else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode ))
2636 info->DeviceType = FILE_DEVICE_NAMED_PIPE;
2638 else if (is_device_placeholder( fd ))
2640 info->DeviceType = FILE_DEVICE_DISK;
2642 else /* regular file or directory */
2644 #if defined(linux) && defined(HAVE_FSTATFS)
2645 struct statfs stfs;
2647 /* check for floppy disk */
2648 if (major(st.st_dev) == FLOPPY_MAJOR)
2649 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2651 if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0;
2652 switch (stfs.f_type)
2654 case 0x9660: /* iso9660 */
2655 case 0x9fa1: /* supermount */
2656 case 0x15013346: /* udf */
2657 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2658 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2659 break;
2660 case 0x6969: /* nfs */
2661 case 0x517B: /* smbfs */
2662 case 0x564c: /* ncpfs */
2663 info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
2664 info->Characteristics |= FILE_REMOTE_DEVICE;
2665 break;
2666 case 0x01021994: /* tmpfs */
2667 case 0x28cd3d45: /* cramfs */
2668 case 0x1373: /* devfs */
2669 case 0x9fa0: /* procfs */
2670 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2671 break;
2672 default:
2673 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2674 break;
2676 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2677 struct statfs stfs;
2679 if (fstatfs( fd, &stfs ) < 0)
2680 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2681 else
2682 get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags );
2683 #elif defined(__NetBSD__)
2684 struct statvfs stfs;
2686 if (fstatvfs( fd, &stfs) < 0)
2687 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2688 else
2689 get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag );
2690 #elif defined(sun)
2691 /* Use dkio to work out device types */
2693 # include <sys/dkio.h>
2694 # include <sys/vtoc.h>
2695 struct dk_cinfo dkinf;
2696 int retval = ioctl(fd, DKIOCINFO, &dkinf);
2697 if(retval==-1){
2698 WARN("Unable to get disk device type information - assuming a disk like device\n");
2699 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2701 switch (dkinf.dki_ctype)
2703 case DKC_CDROM:
2704 info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
2705 info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
2706 break;
2707 case DKC_NCRFLOPPY:
2708 case DKC_SMSFLOPPY:
2709 case DKC_INTEL82072:
2710 case DKC_INTEL82077:
2711 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2712 info->Characteristics |= FILE_REMOVABLE_MEDIA;
2713 break;
2714 case DKC_MD:
2715 info->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
2716 break;
2717 default:
2718 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2721 #else
2722 static int warned;
2723 if (!warned++) FIXME( "device info not properly supported on this platform\n" );
2724 info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
2725 #endif
2726 info->Characteristics |= FILE_DEVICE_IS_MOUNTED;
2728 return STATUS_SUCCESS;
2732 /******************************************************************************
2733 * NtQueryVolumeInformationFile [NTDLL.@]
2734 * ZwQueryVolumeInformationFile [NTDLL.@]
2736 * Get volume information for an open file handle.
2738 * PARAMS
2739 * handle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2740 * io [O] Receives information about the operation on return
2741 * buffer [O] Destination for volume information
2742 * length [I] Size of FsInformation
2743 * info_class [I] Type of volume information to set
2745 * RETURNS
2746 * Success: 0. io and buffer are updated.
2747 * Failure: An NTSTATUS error code describing the error.
2749 NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io,
2750 PVOID buffer, ULONG length,
2751 FS_INFORMATION_CLASS info_class )
2753 int fd, needs_close;
2754 struct stat st;
2755 static int once;
2757 if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
2758 return io->u.Status;
2760 io->u.Status = STATUS_NOT_IMPLEMENTED;
2761 io->Information = 0;
2763 switch( info_class )
2765 case FileFsVolumeInformation:
2766 if (!once++) FIXME( "%p: volume info not supported\n", handle );
2767 break;
2768 case FileFsLabelInformation:
2769 FIXME( "%p: label info not supported\n", handle );
2770 break;
2771 case FileFsSizeInformation:
2772 if (length < sizeof(FILE_FS_SIZE_INFORMATION))
2773 io->u.Status = STATUS_BUFFER_TOO_SMALL;
2774 else
2776 FILE_FS_SIZE_INFORMATION *info = buffer;
2778 if (fstat( fd, &st ) < 0)
2780 io->u.Status = FILE_GetNtStatus();
2781 break;
2783 if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
2785 io->u.Status = STATUS_INVALID_DEVICE_REQUEST;
2787 else
2789 ULONGLONG bsize;
2790 /* Linux's fstatvfs is buggy */
2791 #if !defined(linux) || !defined(HAVE_FSTATFS)
2792 struct statvfs stfs;
2794 if (fstatvfs( fd, &stfs ) < 0)
2796 io->u.Status = FILE_GetNtStatus();
2797 break;
2799 bsize = stfs.f_frsize;
2800 #else
2801 struct statfs stfs;
2802 if (fstatfs( fd, &stfs ) < 0)
2804 io->u.Status = FILE_GetNtStatus();
2805 break;
2807 bsize = stfs.f_bsize;
2808 #endif
2809 if (bsize == 2048) /* assume CD-ROM */
2811 info->BytesPerSector = 2048;
2812 info->SectorsPerAllocationUnit = 1;
2814 else
2816 info->BytesPerSector = 512;
2817 info->SectorsPerAllocationUnit = 8;
2819 info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2820 info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit);
2821 io->Information = sizeof(*info);
2822 io->u.Status = STATUS_SUCCESS;
2825 break;
2826 case FileFsDeviceInformation:
2827 if (length < sizeof(FILE_FS_DEVICE_INFORMATION))
2828 io->u.Status = STATUS_BUFFER_TOO_SMALL;
2829 else
2831 FILE_FS_DEVICE_INFORMATION *info = buffer;
2833 if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS)
2834 io->Information = sizeof(*info);
2836 break;
2837 case FileFsAttributeInformation:
2838 if (length < offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[sizeof(ntfsW)/sizeof(WCHAR)] ))
2839 io->u.Status = STATUS_BUFFER_TOO_SMALL;
2840 else
2842 FILE_FS_ATTRIBUTE_INFORMATION *info = buffer;
2844 FIXME( "%p: faking attribute info\n", handle );
2845 info->FileSystemAttribute = FILE_SUPPORTS_ENCRYPTION | FILE_FILE_COMPRESSION |
2846 FILE_PERSISTENT_ACLS | FILE_UNICODE_ON_DISK |
2847 FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH;
2848 info->MaximumComponentNameLength = MAXIMUM_FILENAME_LENGTH - 1;
2849 info->FileSystemNameLength = sizeof(ntfsW);
2850 memcpy(info->FileSystemName, ntfsW, sizeof(ntfsW));
2852 io->Information = sizeof(*info);
2853 io->u.Status = STATUS_SUCCESS;
2855 break;
2856 case FileFsControlInformation:
2857 FIXME( "%p: control info not supported\n", handle );
2858 break;
2859 case FileFsFullSizeInformation:
2860 FIXME( "%p: full size info not supported\n", handle );
2861 break;
2862 case FileFsObjectIdInformation:
2863 FIXME( "%p: object id info not supported\n", handle );
2864 break;
2865 case FileFsMaximumInformation:
2866 FIXME( "%p: maximum info not supported\n", handle );
2867 break;
2868 default:
2869 io->u.Status = STATUS_INVALID_PARAMETER;
2870 break;
2872 if (needs_close) close( fd );
2873 return io->u.Status;
2877 /******************************************************************
2878 * NtQueryEaFile (NTDLL.@)
2880 * Read extended attributes from NTFS files.
2882 * PARAMS
2883 * hFile [I] File handle, must be opened with FILE_READ_EA access
2884 * iosb [O] Receives information about the operation on return
2885 * buffer [O] Output buffer
2886 * length [I] Length of output buffer
2887 * single_entry [I] Only read and return one entry
2888 * ea_list [I] Optional list with names of EAs to return
2889 * ea_list_len [I] Length of ea_list in bytes
2890 * ea_index [I] Optional pointer to 1-based index of attribute to return
2891 * restart [I] restart EA scan
2893 * RETURNS
2894 * Success: 0. Atrributes read into buffer
2895 * Failure: An NTSTATUS error code describing the error.
2897 NTSTATUS WINAPI NtQueryEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length,
2898 BOOLEAN single_entry, PVOID ea_list, ULONG ea_list_len,
2899 PULONG ea_index, BOOLEAN restart )
2901 FIXME("(%p,%p,%p,%d,%d,%p,%d,%p,%d) stub\n",
2902 hFile, iosb, buffer, length, single_entry, ea_list,
2903 ea_list_len, ea_index, restart);
2904 return STATUS_ACCESS_DENIED;
2908 /******************************************************************
2909 * NtSetEaFile (NTDLL.@)
2911 * Update extended attributes for NTFS files.
2913 * PARAMS
2914 * hFile [I] File handle, must be opened with FILE_READ_EA access
2915 * iosb [O] Receives information about the operation on return
2916 * buffer [I] Buffer with EA information
2917 * length [I] Length of buffer
2919 * RETURNS
2920 * Success: 0. Attributes are updated
2921 * Failure: An NTSTATUS error code describing the error.
2923 NTSTATUS WINAPI NtSetEaFile( HANDLE hFile, PIO_STATUS_BLOCK iosb, PVOID buffer, ULONG length )
2925 FIXME("(%p,%p,%p,%d) stub\n", hFile, iosb, buffer, length);
2926 return STATUS_ACCESS_DENIED;
2930 /******************************************************************
2931 * NtFlushBuffersFile (NTDLL.@)
2933 * Flush any buffered data on an open file handle.
2935 * PARAMS
2936 * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile()
2937 * IoStatusBlock [O] Receives information about the operation on return
2939 * RETURNS
2940 * Success: 0. IoStatusBlock is updated.
2941 * Failure: An NTSTATUS error code describing the error.
2943 NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock )
2945 NTSTATUS ret;
2946 HANDLE hEvent = NULL;
2947 enum server_fd_type type;
2948 int fd, needs_close;
2950 ret = server_get_unix_fd( hFile, FILE_WRITE_DATA, &fd, &needs_close, &type, NULL );
2952 if (!ret && type == FD_TYPE_SERIAL)
2954 ret = COMM_FlushBuffersFile( fd );
2956 else
2958 SERVER_START_REQ( flush_file )
2960 req->handle = wine_server_obj_handle( hFile );
2961 ret = wine_server_call( req );
2962 hEvent = wine_server_ptr_handle( reply->event );
2964 SERVER_END_REQ;
2965 if (!ret && hEvent)
2967 ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
2968 NtClose( hEvent );
2972 if (needs_close) close( fd );
2973 return ret;
2976 /******************************************************************
2977 * NtLockFile (NTDLL.@)
2981 NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event,
2982 PIO_APC_ROUTINE apc, void* apc_user,
2983 PIO_STATUS_BLOCK io_status, PLARGE_INTEGER offset,
2984 PLARGE_INTEGER count, ULONG* key, BOOLEAN dont_wait,
2985 BOOLEAN exclusive )
2987 NTSTATUS ret;
2988 HANDLE handle;
2989 BOOLEAN async;
2990 static BOOLEAN warn = TRUE;
2992 if (apc || io_status || key)
2994 FIXME("Unimplemented yet parameter\n");
2995 return STATUS_NOT_IMPLEMENTED;
2998 if (apc_user && warn)
3000 FIXME("I/O completion on lock not implemented yet\n");
3001 warn = FALSE;
3004 for (;;)
3006 SERVER_START_REQ( lock_file )
3008 req->handle = wine_server_obj_handle( hFile );
3009 req->offset = offset->QuadPart;
3010 req->count = count->QuadPart;
3011 req->shared = !exclusive;
3012 req->wait = !dont_wait;
3013 ret = wine_server_call( req );
3014 handle = wine_server_ptr_handle( reply->handle );
3015 async = reply->overlapped;
3017 SERVER_END_REQ;
3018 if (ret != STATUS_PENDING)
3020 if (!ret && lock_granted_event) NtSetEvent(lock_granted_event, NULL);
3021 return ret;
3024 if (async)
3026 FIXME( "Async I/O lock wait not implemented, might deadlock\n" );
3027 if (handle) NtClose( handle );
3028 return STATUS_PENDING;
3030 if (handle)
3032 NtWaitForSingleObject( handle, FALSE, NULL );
3033 NtClose( handle );
3035 else
3037 LARGE_INTEGER time;
3039 /* Unix lock conflict, sleep a bit and retry */
3040 time.QuadPart = 100 * (ULONGLONG)10000;
3041 time.QuadPart = -time.QuadPart;
3042 NtDelayExecution( FALSE, &time );
3048 /******************************************************************
3049 * NtUnlockFile (NTDLL.@)
3053 NTSTATUS WINAPI NtUnlockFile( HANDLE hFile, PIO_STATUS_BLOCK io_status,
3054 PLARGE_INTEGER offset, PLARGE_INTEGER count,
3055 PULONG key )
3057 NTSTATUS status;
3059 TRACE( "%p %x%08x %x%08x\n",
3060 hFile, offset->u.HighPart, offset->u.LowPart, count->u.HighPart, count->u.LowPart );
3062 if (io_status || key)
3064 FIXME("Unimplemented yet parameter\n");
3065 return STATUS_NOT_IMPLEMENTED;
3068 SERVER_START_REQ( unlock_file )
3070 req->handle = wine_server_obj_handle( hFile );
3071 req->offset = offset->QuadPart;
3072 req->count = count->QuadPart;
3073 status = wine_server_call( req );
3075 SERVER_END_REQ;
3076 return status;
3079 /******************************************************************
3080 * NtCreateNamedPipeFile (NTDLL.@)
3084 NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
3085 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
3086 ULONG sharing, ULONG dispo, ULONG options,
3087 ULONG pipe_type, ULONG read_mode,
3088 ULONG completion_mode, ULONG max_inst,
3089 ULONG inbound_quota, ULONG outbound_quota,
3090 PLARGE_INTEGER timeout)
3092 struct security_descriptor *sd = NULL;
3093 struct object_attributes objattr;
3094 NTSTATUS status;
3096 TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n",
3097 handle, access, debugstr_w(attr->ObjectName->Buffer), iosb, sharing, dispo,
3098 options, pipe_type, read_mode, completion_mode, max_inst, inbound_quota,
3099 outbound_quota, timeout);
3101 /* assume we only get relative timeout */
3102 if (timeout->QuadPart > 0)
3103 FIXME("Wrong time %s\n", wine_dbgstr_longlong(timeout->QuadPart));
3105 objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
3106 objattr.sd_len = 0;
3107 objattr.name_len = attr->ObjectName->Length;
3109 status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
3110 if (status != STATUS_SUCCESS) return status;
3112 SERVER_START_REQ( create_named_pipe )
3114 req->access = access;
3115 req->attributes = attr->Attributes;
3116 req->options = options;
3117 req->sharing = sharing;
3118 req->flags =
3119 (pipe_type ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0) |
3120 (read_mode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0) |
3121 (completion_mode ? NAMED_PIPE_NONBLOCKING_MODE : 0);
3122 req->maxinstances = max_inst;
3123 req->outsize = outbound_quota;
3124 req->insize = inbound_quota;
3125 req->timeout = timeout->QuadPart;
3126 wine_server_add_data( req, &objattr, sizeof(objattr) );
3127 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
3128 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
3129 status = wine_server_call( req );
3130 if (!status) *handle = wine_server_ptr_handle( reply->handle );
3132 SERVER_END_REQ;
3134 NTDLL_free_struct_sd( sd );
3135 return status;
3138 /******************************************************************
3139 * NtDeleteFile (NTDLL.@)
3143 NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
3145 NTSTATUS status;
3146 HANDLE hFile;
3147 IO_STATUS_BLOCK io;
3149 TRACE("%p\n", ObjectAttributes);
3150 status = NtCreateFile( &hFile, GENERIC_READ | GENERIC_WRITE | DELETE,
3151 ObjectAttributes, &io, NULL, 0,
3152 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
3153 FILE_OPEN, FILE_DELETE_ON_CLOSE, NULL, 0 );
3154 if (status == STATUS_SUCCESS) status = NtClose(hFile);
3155 return status;
3158 /******************************************************************
3159 * NtCancelIoFileEx (NTDLL.@)
3163 NTSTATUS WINAPI NtCancelIoFileEx( HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status )
3165 LARGE_INTEGER timeout;
3167 TRACE("%p %p %p\n", hFile, iosb, io_status );
3169 SERVER_START_REQ( cancel_async )
3171 req->handle = wine_server_obj_handle( hFile );
3172 req->iosb = wine_server_client_ptr( iosb );
3173 req->only_thread = FALSE;
3174 io_status->u.Status = wine_server_call( req );
3176 SERVER_END_REQ;
3177 if (io_status->u.Status)
3178 return io_status->u.Status;
3180 /* Let some APC be run, so that we can run the remaining APCs on hFile
3181 * either the cancelation of the pending one, but also the execution
3182 * of the queued APC, but not yet run. This is needed to ensure proper
3183 * clean-up of allocated data.
3185 timeout.QuadPart = 0;
3186 NtDelayExecution( TRUE, &timeout );
3187 return io_status->u.Status;
3190 /******************************************************************
3191 * NtCancelIoFile (NTDLL.@)
3195 NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
3197 LARGE_INTEGER timeout;
3199 TRACE("%p %p\n", hFile, io_status );
3201 SERVER_START_REQ( cancel_async )
3203 req->handle = wine_server_obj_handle( hFile );
3204 req->iosb = 0;
3205 req->only_thread = TRUE;
3206 io_status->u.Status = wine_server_call( req );
3208 SERVER_END_REQ;
3209 if (io_status->u.Status)
3210 return io_status->u.Status;
3212 /* Let some APC be run, so that we can run the remaining APCs on hFile
3213 * either the cancelation of the pending one, but also the execution
3214 * of the queued APC, but not yet run. This is needed to ensure proper
3215 * clean-up of allocated data.
3217 timeout.QuadPart = 0;
3218 NtDelayExecution( TRUE, &timeout );
3219 return io_status->u.Status;
3222 /******************************************************************************
3223 * NtCreateMailslotFile [NTDLL.@]
3224 * ZwCreateMailslotFile [NTDLL.@]
3226 * PARAMS
3227 * pHandle [O] pointer to receive the handle created
3228 * DesiredAccess [I] access mode (read, write, etc)
3229 * ObjectAttributes [I] fully qualified NT path of the mailslot
3230 * IoStatusBlock [O] receives completion status and other info
3231 * CreateOptions [I]
3232 * MailslotQuota [I]
3233 * MaxMessageSize [I]
3234 * TimeOut [I]
3236 * RETURNS
3237 * An NT status code
3239 NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
3240 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK IoStatusBlock,
3241 ULONG CreateOptions, ULONG MailslotQuota, ULONG MaxMessageSize,
3242 PLARGE_INTEGER TimeOut)
3244 LARGE_INTEGER timeout;
3245 NTSTATUS ret;
3247 TRACE("%p %08x %p %p %08x %08x %08x %p\n",
3248 pHandle, DesiredAccess, attr, IoStatusBlock,
3249 CreateOptions, MailslotQuota, MaxMessageSize, TimeOut);
3251 if (!pHandle) return STATUS_ACCESS_VIOLATION;
3252 if (!attr) return STATUS_INVALID_PARAMETER;
3253 if (!attr->ObjectName) return STATUS_OBJECT_PATH_SYNTAX_BAD;
3256 * For a NULL TimeOut pointer set the default timeout value
3258 if (!TimeOut)
3259 timeout.QuadPart = -1;
3260 else
3261 timeout.QuadPart = TimeOut->QuadPart;
3263 SERVER_START_REQ( create_mailslot )
3265 req->access = DesiredAccess;
3266 req->attributes = attr->Attributes;
3267 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
3268 req->max_msgsize = MaxMessageSize;
3269 req->read_timeout = timeout.QuadPart;
3270 wine_server_add_data( req, attr->ObjectName->Buffer,
3271 attr->ObjectName->Length );
3272 ret = wine_server_call( req );
3273 if( ret == STATUS_SUCCESS )
3274 *pHandle = wine_server_ptr_handle( reply->handle );
3276 SERVER_END_REQ;
3278 return ret;