From: strudelll <strudelll@etersoft.ru> --- dlls/ntdll/unix/file.c | 59 ++++++++++++++++++++++++++++++++++++++++++ include/winioctl.h | 10 +++++++ 2 files changed, 69 insertions(+) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index fdc0c32fc4f..b6641f31eb9 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,57 @@ static void ignore_server_ioctl_struct_holes( ULONG code, const void *in_buffer, #endif } +static NTSTATUS duplicate_extents_to_file( HANDLE dst_handle, const void *in_buf, ULONG in_len ) +{ + const DUPLICATE_EXTENTS_DATA *data = in_buf; + NTSTATUS status; + int dst_fd = -1, src_fd = -1; + int needs_close_dst = 0, needs_close_src = 0; + + if (!data || in_len < sizeof(*data)) return STATUS_BUFFER_TOO_SMALL; + + status = server_get_unix_fd( dst_handle, FILE_WRITE_DATA, &dst_fd, &needs_close_dst, NULL, NULL ); + if (status) return status; + status = server_get_unix_fd( data->FileHandle, FILE_READ_DATA, &src_fd, &needs_close_src, NULL, NULL ); + if (status) goto done; + +#ifdef FICLONERANGE + struct file_clone_range r = + { + .src_fd = src_fd, + .src_offset = data->SourceFileOffset.QuadPart, + .src_length = data->ByteCount.QuadPart, + .dest_offset = data->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 (!data->SourceFileOffset.QuadPart && !data->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; +} + /****************************************************************************** * NtFsControlFile (NTDLL.@) @@ -6733,6 +6787,11 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap break; } + case FSCTL_DUPLICATE_EXTENTS_TO_FILE: + status = duplicate_extents_to_file( handle, in_buffer, in_size ); + break; + + case FSCTL_SET_SPARSE: TRACE("FSCTL_SET_SPARSE: Ignoring request\n"); status = STATUS_SUCCESS; diff --git a/include/winioctl.h b/include/winioctl.h index 08fb307a321..3bb26f4dc42 100644 --- a/include/winioctl.h +++ b/include/winioctl.h @@ -315,6 +315,16 @@ #define FSCTL_DELETE_CORRUPTED_REFS_CONTAINER CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 253, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_SCRUB_UNDISCOVERABLE_ID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 254, METHOD_BUFFERED, FILE_ANY_ACCESS) +#ifndef _DUPLICATE_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 _DUPLICATE_EXTENTS_DATA_DEFINED +#endif + #define FSCTL_PIPE_ASSIGN_EVENT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_PIPE_DISCONNECT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_PIPE_LISTEN CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9732