[libos] Fix error handling of sendfile

This commit is contained in:
ClawSeven 2022-05-31 08:36:11 +08:00 committed by Tate, Hongliang Tian
parent eba7e08453
commit 40ad9d1648

@ -22,28 +22,66 @@ pub fn do_sendfile(
None => in_file.seek(SeekFrom::Current(0))?,
} as usize;
// read from specified offset and write new offset back
let mut bytes_read = 0;
while bytes_read < count {
let len = min(buffer.len(), count - bytes_read);
let read_len = in_file.read_at(read_offset, &mut buffer[..len])?;
if read_len == 0 {
break;
}
bytes_read += read_len;
read_offset += read_len;
// write_file is used to write buffer into out_file, the closure avoids complex loop structure
let mut write_file = |buffer: &[u8]| -> Result<usize> {
let buffer_len = buffer.len();
let mut bytes_written = 0;
while bytes_written < read_len {
let write_len = out_file.write(&buffer[bytes_written..read_len])?;
if write_len == 0 {
return_errno!(EBADF, "sendfile write return 0");
let mut write_error = None;
while bytes_written < buffer_len {
match out_file.write(&buffer[bytes_written..]) {
Ok(write_len) => {
debug_assert!(write_len > 0);
bytes_written += write_len;
}
Err(e) => {
// handle sendmsg return err
write_error = Some(e);
break;
}
}
}
if bytes_written > 0 {
Ok(bytes_written)
} else {
// if bytes_written = 0, write_error must be Some(e).
Err(write_error.unwrap())
}
};
// read from specified offset and write new offset back
let mut bytes_sent = 0;
let mut send_error = None;
while bytes_sent < count {
let len = min(buffer.len(), count - bytes_sent);
match in_file.read_at(read_offset, &mut buffer[..len]) {
Ok(read_len) if read_len > 0 => match write_file(&buffer[..read_len]) {
Ok(write_len) => {
bytes_sent += write_len;
read_offset += write_len;
}
Err(e) => {
send_error = Some(e);
break;
}
},
Ok(..) => break,
Err(e) => {
send_error = Some(e);
break;
}
bytes_written += write_len;
}
}
if offset.is_none() {
in_file.seek(SeekFrom::Current(bytes_read as i64))?;
in_file.seek(SeekFrom::Current(bytes_sent as i64))?;
}
if bytes_sent > 0 {
Ok((bytes_sent, read_offset))
} else {
send_error.map_or_else(|| Ok((0, read_offset)), |e| Err(e))
}
Ok((bytes_read, read_offset))
}