Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/cat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ features = ["fs"]
[target.'cfg(unix)'.dependencies]
unix_socket = "0.5.0"

[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
nix = "0.9.0"

[[bin]]
name = "cat"
path = "../../uumain.rs"
65 changes: 65 additions & 0 deletions src/cat/cat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ extern crate quick_error;
extern crate unix_socket;
#[macro_use]
extern crate uucore;
#[cfg(any(target_os = "linux", target_os = "android"))]
extern crate nix;

// last synced with: cat (GNU coreutils) 8.13
use quick_error::ResultExt;
Expand All @@ -31,6 +33,14 @@ use std::os::unix::fs::FileTypeExt;
#[cfg(unix)]
use unix_socket::UnixStream;

/// Linux splice support
#[cfg(any(target_os = "linux", target_os = "android"))]
use nix::fcntl::{splice, SpliceFFlags};
#[cfg(any(target_os = "linux", target_os = "android"))]
use nix::unistd::pipe;
#[cfg(any(target_os = "linux", target_os = "android"))]
use std::os::unix::io::{AsRawFd, RawFd};

static SYNTAX: &str = "[OPTION]... [FILE]...";
static SUMMARY: &str = "Concatenate FILE(s), or standard input, to standard output
With no FILE, or when FILE is -, read standard input.";
Expand Down Expand Up @@ -100,6 +110,8 @@ struct OutputOptions {

/// Represents an open file handle, stream, or other device
struct InputHandle {
#[cfg(any(target_os = "linux", target_os = "android"))]
file_descriptor: RawFd,
reader: Box<Read>,
is_interactive: bool,
}
Expand Down Expand Up @@ -241,6 +253,8 @@ fn open(path: &str) -> CatResult<InputHandle> {
if path == "-" {
let stdin = stdin();
return Ok(InputHandle {
#[cfg(any(target_os = "linux", target_os = "android"))]
file_descriptor: stdin.as_raw_fd(),
reader: Box::new(stdin) as Box<Read>,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned this on the other PR as well, but could you change this to avoid Box?

is_interactive: is_stdin_interactive(),
});
Expand All @@ -253,13 +267,17 @@ fn open(path: &str) -> CatResult<InputHandle> {
let socket = UnixStream::connect(path).context(path)?;
socket.shutdown(Shutdown::Write).context(path)?;
Ok(InputHandle {
#[cfg(any(target_os = "linux", target_os = "android"))]
file_descriptor: socket.as_raw_fd(),
reader: Box::new(socket) as Box<Read>,
is_interactive: false,
})
}
_ => {
let file = File::open(path).context(path)?;
Ok(InputHandle {
#[cfg(any(target_os = "linux", target_os = "android"))]
file_descriptor: file.as_raw_fd(),
reader: Box::new(file) as Box<Read>,
is_interactive: false,
})
Expand All @@ -275,6 +293,7 @@ fn open(path: &str) -> CatResult<InputHandle> {
///
/// * `files` - There is no short circuit when encountiner an error
/// reading a file in this vector
#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn write_fast(files: Vec<String>) -> CatResult<()> {
let mut writer = stdout();
let mut in_buf = [0; 1024 * 64];
Expand All @@ -300,6 +319,52 @@ fn write_fast(files: Vec<String>) -> CatResult<()> {
_ => Err(CatError::EncounteredErrors(error_count)),
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
Comment thread
ArniDagur marked this conversation as resolved.
fn write_fast(files: Vec<String>) -> CatResult<()> {
const BUF_SIZE: usize = 1024 * 16;
let writer = stdout();
// let _handle = writer.lock();
let (pipe_rd, pipe_wr) = pipe().unwrap();
Comment thread
ArniDagur marked this conversation as resolved.
Outdated
let mut error_count = 0;

for file in files {
match open(&file[..]) {
Ok(handle) => loop {
let res = splice(
handle.file_descriptor,
None,
pipe_wr,
None,
BUF_SIZE,
SpliceFFlags::empty(),
).unwrap();
Comment thread
ArniDagur marked this conversation as resolved.
Outdated
if res == 0 {
// We read 0 bytes from the input,
// which means we're done copying.
break;
}
let _res = splice (
pipe_rd,
None,
writer.as_raw_fd(),
None,
BUF_SIZE,
SpliceFFlags::empty(),
).unwrap();
},
Err(error) => {
writeln!(&mut stderr(), "{}", error)?;
error_count += 1;
}

}
}
match error_count {
0 => Ok(()),
_ => Err(CatError::EncounteredErrors(error_count)),
}
}


/// State that persists between output of each file
struct OutputState {
Expand Down