Skip to content

Commit cc40ae0

Browse files
authored
Merge pull request #2851 from deantvv/fix-os-sendfile
Fix os sendfile
2 parents a21ad9e + 3bb4e5d commit cc40ae0

File tree

2 files changed

+71
-29
lines changed

2 files changed

+71
-29
lines changed

Lib/test/test_os.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -3050,7 +3050,6 @@ def handle_error(self):
30503050
raise
30513051

30523052

3053-
@unittest.skip("TODO: RUSTPYTHON")
30543053
@unittest.skipUnless(hasattr(os, 'sendfile'), "test needs os.sendfile()")
30553054
class TestSendfile(unittest.TestCase):
30563055

@@ -3178,11 +3177,12 @@ def test_invalid_offset(self):
31783177

31793178
def test_keywords(self):
31803179
# Keyword arguments should be supported
3181-
os.sendfile(out=self.sockno, offset=0, count=4096,
3182-
**{'in': self.fileno})
3180+
os.sendfile(out_fd=self.sockno, in_fd=self.fileno,
3181+
offset=0, count=4096)
31833182
if self.SUPPORT_HEADERS_TRAILERS:
3184-
os.sendfile(self.sockno, self.fileno, offset=0, count=4096,
3185-
headers=(), trailers=(), flags=0)
3183+
os.sendfile(out_fd=self.sockno, in_fd=self.fileno,
3184+
offset=0, count=4096,
3185+
headers=(), trailers=(), flags=0)
31863186

31873187
# --- headers / trailers tests
31883188

vm/src/stdlib/os.rs

+66-24
Original file line numberDiff line numberDiff line change
@@ -498,34 +498,73 @@ mod _os {
498498
fd.map(|fd| fd.0).map_err(|e| e.into_pyexception(vm))
499499
}
500500

501+
#[cfg(any(target_os = "linux", target_os = "macos"))]
502+
#[derive(FromArgs)]
503+
struct SendFileArgs {
504+
#[pyarg(any)]
505+
out_fd: i32,
506+
#[pyarg(any)]
507+
in_fd: i32,
508+
#[pyarg(any)]
509+
offset: i64,
510+
#[pyarg(any)]
511+
count: i64,
512+
#[cfg(target_os = "macos")]
513+
#[pyarg(any, optional)]
514+
headers: OptionalArg<PyObjectRef>,
515+
#[cfg(target_os = "macos")]
516+
#[pyarg(any, optional)]
517+
trailers: OptionalArg<PyObjectRef>,
518+
#[cfg(target_os = "macos")]
519+
#[allow(dead_code)]
520+
#[pyarg(any, default)]
521+
// TODO: not implemented
522+
flags: OptionalArg<i32>,
523+
}
524+
501525
#[cfg(target_os = "linux")]
502526
#[pyfunction]
503-
fn sendfile(out_fd: i32, in_fd: i32, offset: i64, count: u64, vm: &VirtualMachine) -> PyResult {
504-
let mut file_offset = offset;
527+
fn sendfile(args: SendFileArgs, vm: &VirtualMachine) -> PyResult {
528+
let mut file_offset = args.offset;
505529

506-
let res =
507-
nix::sys::sendfile::sendfile(out_fd, in_fd, Some(&mut file_offset), count as usize)
508-
.map_err(|err| err.into_pyexception(vm))?;
530+
let res = nix::sys::sendfile::sendfile(
531+
args.out_fd,
532+
args.in_fd,
533+
Some(&mut file_offset),
534+
args.count as usize,
535+
)
536+
.map_err(|err| err.into_pyexception(vm))?;
509537
Ok(vm.ctx.new_int(res as u64))
510538
}
511539

512540
#[cfg(target_os = "macos")]
513-
#[pyfunction]
514-
#[allow(clippy::too_many_arguments)]
515-
fn sendfile(
516-
out_fd: i32,
517-
in_fd: i32,
518-
offset: i64,
519-
count: i64,
520-
headers: OptionalArg<PyObjectRef>,
521-
trailers: OptionalArg<PyObjectRef>,
522-
_flags: OptionalArg<i32>,
541+
fn _extract_vec_bytes(
542+
x: OptionalArg,
523543
vm: &VirtualMachine,
524-
) -> PyResult {
525-
let headers = match headers.into_option() {
526-
Some(x) => Some(vm.extract_elements::<PyBytesLike>(&x)?),
544+
) -> PyResult<Option<Vec<PyBytesLike>>> {
545+
let inner = match x.into_option() {
546+
Some(v) => {
547+
let v = vm.extract_elements::<PyBytesLike>(&v)?;
548+
if v.is_empty() {
549+
None
550+
} else {
551+
Some(v)
552+
}
553+
}
527554
None => None,
528555
};
556+
Ok(inner)
557+
}
558+
559+
#[cfg(target_os = "macos")]
560+
#[pyfunction]
561+
fn sendfile(args: SendFileArgs, vm: &VirtualMachine) -> PyResult {
562+
let headers = _extract_vec_bytes(args.headers, vm)?;
563+
let count = headers
564+
.as_ref()
565+
.map(|v| v.iter().map(|s| s.len()).sum())
566+
.unwrap_or(0) as i64
567+
+ args.count;
529568

530569
let headers = headers
531570
.as_ref()
@@ -535,10 +574,7 @@ mod _os {
535574
.map(|v| v.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>());
536575
let headers = headers.as_deref();
537576

538-
let trailers = match trailers.into_option() {
539-
Some(x) => Some(vm.extract_elements::<PyBytesLike>(&x)?),
540-
None => None,
541-
};
577+
let trailers = _extract_vec_bytes(args.trailers, vm)?;
542578

543579
let trailers = trailers
544580
.as_ref()
@@ -548,8 +584,14 @@ mod _os {
548584
.map(|v| v.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>());
549585
let trailers = trailers.as_deref();
550586

551-
let (res, written) =
552-
nix::sys::sendfile::sendfile(in_fd, out_fd, offset, Some(count), headers, trailers);
587+
let (res, written) = nix::sys::sendfile::sendfile(
588+
args.in_fd,
589+
args.out_fd,
590+
args.offset,
591+
Some(count),
592+
headers,
593+
trailers,
594+
);
553595
res.map_err(|err| err.into_pyexception(vm))?;
554596
Ok(vm.ctx.new_int(written as u64))
555597
}

0 commit comments

Comments
 (0)