[PATCH 0/1] MR9732: ntdll: Support FSCTL_DUPLICATE_EXTENTS_TO_FILE
Implement FSCTL_DUPLICATE_EXTENTS_TO_FILE handling in ntdll on Linux by wiring the IOCTL to FICLONERANGE/FICLONE where available and returning STATUS_INVALID_DEVICE_REQUEST otherwise. Adds the necessary constants/types when missing. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9732
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
Thanks for the patch. We're currently in code freeze, so I'm afraid new features won't be accepted right now, but I'll offer some review regardless: * First of all, is there an application that actually needs this? Or is this another attempt to address prefix size? This approach has more or less been rejected by Alexandre. If there's no application that specifically needs this, I don't think we want to spend effort on it. * Public definitions should be added to our headers. FSCTL_DUPLICATE_EXTENTS_TO_FILE already exists, so you shouldn't need to redefine it, and DUPLICATE_EXTENTS_DATA should be added to winioctl.h as it is in Microsoft's headers. * Please avoid forward-declaring where not necessary. * If there is an application that needs this, it needs tests. ``` +static NTSTATUS unix_fsctl_duplicate_extents_to_file( HANDLE dst_handle, const void *in_buf, ULONG in_len ) ``` "duplicate_extents_to_file" would be a better name; no need for that prefix. ``` + const DUPLICATE_EXTENTS_DATA *dx = in_buf; ``` "data" would be a better name. ``` + 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; ``` Should we really be passing 0 access mask here? "options" isn't used, so you could just pass NULL. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9732#note_125245
`GetVolumeInformation` should also be advertising `FILE_SUPPORTS_BLOCK_REFCOUNTING` for volumes that support this. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9732#note_125248
participants (4)
-
Brendan Shanks (@bshanks) -
Elizabeth Figura (@zfigura) -
nikita pushkarev (@strudelll) -
strudelll