-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Moved the implementation into a macro
- Loading branch information
Showing
3 changed files
with
90 additions
and
129 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
macro_rules! fd_guard { | ||
($name:ident, guard: $guard_name:ident, FD: $fd:path, name of FD: $doc:ident) => { | ||
mod $doc { | ||
use crate::ffi::{close, dup, dup2}; | ||
use std::fs::OpenOptions; | ||
use std::io; | ||
use std::os::unix::io::IntoRawFd; | ||
use std::os::unix::io::RawFd; | ||
use std::os::unix::prelude::*; | ||
use std::path::Path; | ||
use std::sync::atomic::{AtomicBool, Ordering}; | ||
|
||
static IS_REPLACED: AtomicBool = AtomicBool::new(false); | ||
|
||
const ORDERING: Ordering = Ordering::SeqCst; | ||
|
||
/// A Guard over the File Descriptor change. | ||
/// when this guard is dropped $doc will go back to the original, | ||
/// and the file will be closed. | ||
pub struct $guard_name { | ||
original_fd: RawFd, | ||
file_fd: RawFd, | ||
} | ||
|
||
/// Override the File Descriptor safely. | ||
/// | ||
pub struct $name; | ||
|
||
impl $name { | ||
/// Override the File Descriptor by providing a path. | ||
/// This uses [`File::create`] so it will fail/succeed accordingly. | ||
/// | ||
/// [`File::create`]: https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.create | ||
pub fn override_file<P: AsRef<Path>>(p: P) -> io::Result<$guard_name> { | ||
Self::check_override(); | ||
|
||
let file = OpenOptions::new().read(true).write(true).append(true).create(true).open(p)?; | ||
let file_fd = file.into_raw_fd(); | ||
Self::override_fd(file_fd) | ||
} | ||
|
||
/// Override the File Descriptor by providing something that can be turned into a file descriptor. | ||
/// This will accept Sockets, Files, and even Stdio's. [`AsRawFd`] | ||
/// | ||
/// [`AsRawFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/trait.AsRawFd.html | ||
pub fn override_raw<FD: AsRawFd>(fd: FD) -> io::Result<$guard_name> { | ||
Self::check_override(); | ||
|
||
let file_fd = fd.as_raw_fd(); | ||
Self::override_fd(file_fd) | ||
} | ||
|
||
fn override_fd(file_fd: RawFd) -> io::Result<$guard_name> { | ||
let original_fd = unsafe { dup($fd) }?; | ||
let _ = unsafe { dup2(file_fd, $fd) }?; | ||
|
||
IS_REPLACED.store(true, ORDERING); | ||
|
||
Ok($guard_name { original_fd, file_fd }) | ||
} | ||
|
||
fn check_override() { | ||
if IS_REPLACED.load(ORDERING) { | ||
panic!("Tried to override Stdout twice"); | ||
} | ||
} | ||
} | ||
|
||
impl Drop for $guard_name { | ||
fn drop(&mut self) { | ||
// Ignoring syscalls errors seems to be the most sensible thing to do in a Drop impl | ||
// https://github.com/rust-lang/rust/blob/bd177f3e/src/libstd/sys/unix/fd.rs#L293-L302 | ||
let _ = unsafe { dup2(self.original_fd, $fd) }; | ||
let _ = unsafe { close(self.file_fd) }; | ||
IS_REPLACED.store(false, ORDERING); | ||
} | ||
} | ||
|
||
} | ||
}; | ||
} |
This file was deleted.
Oops, something went wrong.