mirror of
https://github.com/torvalds/linux.git
synced 2026-10-09 20:09:02 +02:00
ksmbd: handle AAPL stream copy length mismatch
macOS can reuse the main file's chunk list when issuing a copychunk request for alternate data streams. The requested source range can therefore exceed the length of the xattr-backed stream and currently fails with STATUS_INVALID_VIEW_SIZE. For AAPL connections copying between two streams, limit the actual copy to the available source data while reporting the requested chunk length as written. Keep the source range validation unchanged for non-AAPL connections and requests involving a regular file. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
parent
8482150a07
commit
f4ce7da9b3
|
|
@ -1859,33 +1859,63 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
|
|||
}
|
||||
|
||||
for (i = 0; i < chunk_count; i++) {
|
||||
bool stream_len_mismatch = false;
|
||||
size_t copy_len;
|
||||
|
||||
src_off = le64_to_cpu(chunks[i].SourceOffset);
|
||||
dst_off = le64_to_cpu(chunks[i].TargetOffset);
|
||||
len = le32_to_cpu(chunks[i].Length);
|
||||
copy_len = len;
|
||||
|
||||
if (src_off + len > src_file_size)
|
||||
if (src_off < 0)
|
||||
return -E2BIG;
|
||||
|
||||
if (src_off > src_file_size || len > src_file_size - src_off) {
|
||||
/*
|
||||
* macOS can reuse the main file's chunk list when copying
|
||||
* streams, so the requested range can exceed the size of
|
||||
* the xattr-backed stream. For an AAPL connection, copy the
|
||||
* available stream data and report the requested length to
|
||||
* avoid a copy length mismatch.
|
||||
*/
|
||||
if (!work->conn->is_aapl ||
|
||||
!ksmbd_stream_fd(src_fp) ||
|
||||
!ksmbd_stream_fd(dst_fp))
|
||||
return -E2BIG;
|
||||
|
||||
stream_len_mismatch = true;
|
||||
if (src_off < src_file_size)
|
||||
copy_len = src_file_size - src_off;
|
||||
else
|
||||
copy_len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_copy_file_range does not support streams or overlapping
|
||||
* ranges within the same file.
|
||||
*/
|
||||
if (ksmbd_stream_fd(src_fp) || ksmbd_stream_fd(dst_fp) ||
|
||||
if (!copy_len) {
|
||||
ret = 0;
|
||||
} else if (ksmbd_stream_fd(src_fp) || ksmbd_stream_fd(dst_fp) ||
|
||||
(file_inode(src_fp->filp) == file_inode(dst_fp->filp) &&
|
||||
dst_off + len > src_off && dst_off < src_off + len))
|
||||
dst_off + copy_len > src_off &&
|
||||
dst_off < src_off + copy_len)) {
|
||||
ret = ksmbd_vfs_copy_file_range_buffered(work, src_fp,
|
||||
dst_fp, src_off,
|
||||
dst_off, len);
|
||||
else {
|
||||
dst_off, copy_len);
|
||||
} else {
|
||||
ret = vfs_copy_file_range(src_fp->filp, src_off,
|
||||
dst_fp->filp, dst_off, len, 0);
|
||||
dst_fp->filp, dst_off, copy_len, 0);
|
||||
if (ret == -EOPNOTSUPP || ret == -EXDEV)
|
||||
ret = vfs_copy_file_range(src_fp->filp, src_off,
|
||||
dst_fp->filp, dst_off,
|
||||
len, COPY_FILE_SPLICE);
|
||||
copy_len,
|
||||
COPY_FILE_SPLICE);
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (stream_len_mismatch)
|
||||
ret = len;
|
||||
|
||||
*chunk_count_written += 1;
|
||||
*total_size_written += ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user