From: strudelll <strudelll(a)etersoft.ru> --- dlls/ntdll/unix/file.c | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index fdc0c32fc4f..b8bc9078e83 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -52,6 +52,9 @@ #include <sys/socket.h> #include <sys/time.h> #include <sys/ioctl.h> +#ifdef __linux__ +# include <linux/fs.h> +#endif #ifdef HAVE_SYS_ATTR_H #include <sys/attr.h> #endif @@ -6643,6 +6646,22 @@ static void ignore_server_ioctl_struct_holes( ULONG code, const void *in_buffer, #endif } +#ifndef FSCTL_DUPLICATE_EXTENTS_TO_FILE +# define FSCTL_DUPLICATE_EXTENTS_TO_FILE 0x00098344 +#endif + +#ifndef WINE_DUP_EXTENTS_DATA_DEFINED +typedef struct _DUPLICATE_EXTENTS_DATA { + HANDLE FileHandle; + LARGE_INTEGER SourceFileOffset; + LARGE_INTEGER TargetFileOffset; + LARGE_INTEGER ByteCount; +} DUPLICATE_EXTENTS_DATA, *PDUPLICATE_EXTENTS_DATA; +# define WINE_DUP_EXTENTS_DATA_DEFINED +#endif + +static NTSTATUS unix_fsctl_duplicate_extents_to_file( HANDLE dst_handle, const void *in_buf, ULONG in_len ); + /****************************************************************************** * NtFsControlFile (NTDLL.@) @@ -6733,6 +6752,11 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap break; } + case FSCTL_DUPLICATE_EXTENTS_TO_FILE: + status = unix_fsctl_duplicate_extents_to_file( handle, in_buffer, in_size ); + break; + + case FSCTL_SET_SPARSE: TRACE("FSCTL_SET_SPARSE: Ignoring request\n"); status = STATUS_SUCCESS; @@ -7842,3 +7866,63 @@ NTSTATUS WINAPI NtSetInformationObject( HANDLE handle, OBJECT_INFORMATION_CLASS } return status; } + +static NTSTATUS unix_fsctl_duplicate_extents_to_file( HANDLE dst_handle, const void *in_buf, ULONG in_len ) +{ + const DUPLICATE_EXTENTS_DATA *dx = in_buf; + NTSTATUS status; + int dst_fd = -1, src_fd = -1; + int needs_close_dst = 0, needs_close_src = 0; + unsigned int options; + + if (!dx || in_len < sizeof(*dx)) return STATUS_BUFFER_TOO_SMALL; + + status = server_get_unix_fd( dst_handle, 0, &dst_fd, &needs_close_dst, NULL, &options ); + if (status) return status; + status = server_get_unix_fd( dx->FileHandle, 0, &src_fd, &needs_close_src, NULL, &options ); + if (status) goto done; + +#ifdef FICLONERANGE + struct file_clone_range r = + { + .src_fd = src_fd, + .src_offset = dx->SourceFileOffset.QuadPart, + .src_length = dx->ByteCount.QuadPart, + .dest_offset = dx->TargetFileOffset.QuadPart, + }; + + if (!ioctl( dst_fd, FICLONERANGE, &r )) + { + status = STATUS_SUCCESS; + goto done; + } + if (!(errno == EOPNOTSUPP || errno == ENOTTY || errno == EXDEV || errno == EINVAL)) + { + status = errno_to_status( errno ); + goto done; + } +#endif + +#ifdef FICLONE + if (!dx->SourceFileOffset.QuadPart && !dx->TargetFileOffset.QuadPart) + { + if (!ioctl( dst_fd, FICLONE, src_fd )) + { + status = STATUS_SUCCESS; + goto done; + } + if (!(errno == EOPNOTSUPP || errno == ENOTTY || errno == EXDEV)) + { + status = errno_to_status( errno ); + goto done; + } + } +#endif + + status = STATUS_INVALID_DEVICE_REQUEST; + +done: + if (needs_close_src && src_fd != -1) close( src_fd ); + if (needs_close_dst && dst_fd != -1) close( dst_fd ); + return status; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9732