diff --git a/src/libos/src/fs/file_ops/sendfile.rs b/src/libos/src/fs/file_ops/sendfile.rs index 5a885ced..3f261aec 100644 --- a/src/libos/src/fs/file_ops/sendfile.rs +++ b/src/libos/src/fs/file_ops/sendfile.rs @@ -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 { + 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)) }