I implemented impl fmt::Write for &File like you suggested and tried a test case with a lazy static file
Doesnt seem to help with mutable reference issue.
In my case, I will eventually have a global lazy_static! { } of
pub struct Tracker {
file: File,
};
Which I tested in test case below.
All this I because I dont want to use
- std:io to write to tracker and tracer files
- to be able to write to these files from possible multiple threads without locks.
#![no_std]
use core::fmt;
use core::sync::atomic::Ordering;
use std::ffi::{CStr, CString};
use std::{io,cmp};
use std::process;
use libc;
use backtrace::Backtrace;
use crate::common::{PUUID, UUID, WISKFD};
const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
const fn max_iov() -> usize {
libc::UIO_MAXIOV as usize
}
pub struct File {
fd: i32,
filename: String,
}
impl File {
pub fn open(filename: &str, flags: i32, mode: i32, relocfd: bool, specificfd: i32) -> io::Result<File> {
// eprintln!("PID: {}, internal_open FLAGS: {}, File: {}",
// process::id(), flags, filename);
cevent!(Level::INFO, "open(filename={}, flags={}, mode={}, relocfd={}, specificfd={})",
filename, flags, mode, relocfd, specificfd);
let fd = if specificfd >= 0 {
let eflags = unsafe { libc::syscall(libc::SYS_fcntl, specificfd, libc::F_GETFD) } as libc::c_int;
if eflags >= 0 {
let buffer: Vec<u8> = vec![0; 1024];
let linkpath = CString::new(format!("/proc/self/fd/{}", specificfd)).unwrap();
let retsize = unsafe { libc::syscall(libc::SYS_readlink, linkpath.as_ptr(), buffer.as_ptr(), 1024) as i32 };
wiskassert!(retsize > 0, "Inherited file descriptor {} does not map to a file. Expected {}", specificfd, filename);
let fname = unsafe { CString::from_raw(buffer.as_ptr() as *mut i8).into_string().unwrap() };
let f = File {
fd: specificfd,
filename: fname,
};
return Ok(f)
}
specificfd
} else {
WISKFD.fetch_add(1, Ordering::Relaxed) as i32
};
let filename = CString::new(filename).unwrap();
let tempfd = unsafe {
libc::syscall(libc::SYS_open, filename.as_ptr(), flags, mode)
// S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
} as i32;
if tempfd < 0 {
return Err(io::Error::last_os_error());
}
cevent!(Level::INFO, "Opened FD: {}, relocating to {}", tempfd, fd);
let retfd = if relocfd {
let retfd = unsafe { libc::syscall(libc::SYS_dup3, tempfd, fd, flags & libc::O_CLOEXEC) } as i32;
if retfd < 0 {
errorexit!("Cannot dup3 fd {} to {}, flags: {}\n{}",
tempfd, fd, flags & libc::O_CLOEXEC, io::Error::last_os_error());
}
unsafe { libc::syscall(libc::SYS_close, tempfd) };
cevent!(Level::INFO, "File Descriptor(Relocated): {} -> {}, File: {}\n",
tempfd, fd, filename.to_string_lossy());
fd
} else {
cevent!(Level::INFO, "File Descriptor(Original): {}, File: {}\n",
tempfd, filename.to_string_lossy());
tempfd
};
let eflags = unsafe { libc::syscall(libc::SYS_fcntl, retfd, libc::F_GETFD) } as libc::c_int;
cevent!(Level::INFO, "internal_open FD: {}, EFLAGS: {}", retfd, eflags);
if eflags < 0 {
errorexit!("Error Creating/Duping FD: {} returned eflasgs: {}, File: {}", retfd, eflags, filename.to_string_lossy());
}
if (eflags & libc::O_CLOEXEC) != 0 {
errorexit!("Error O_CLOEXEC FD: {} returned eflasgs: {}, File: {}", retfd, eflags, filename.to_string_lossy());
}
let f = File {
fd: retfd,
filename: filename.into_string().unwrap(),
};
Ok(f)
}
pub fn as_raw_fd(&self) -> i32 {
self.fd
}
// pub fn sync_all(&self) -> io::Result<()> {
// self.fsync()
// }
// pub fn sync_data(&self) -> io::Result<()> {
// self.datasync()
// }
// pub fn set_len(&self, size: u64) -> io::Result<()> {
// self.truncate(size)
// }
pub fn read(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
let ret = unsafe {
libc::syscall(
libc::SYS_read,
self.fd,
buf.as_mut_ptr() as *mut libc::c_void,
cmp::min(buf.len(), READ_LIMIT))
};
if ret < 0 {
return Err("Error read from FD");
}
Ok(ret as usize)
}
pub fn read_vectored(&self, bufs: &mut [io::IoSliceMut<'_>]) -> Result<usize, &'static str> {
let ret = unsafe {
libc::syscall(
libc::SYS_readv,
self.fd,
bufs.as_ptr() as *const libc::iovec,
cmp::min(bufs.len(), max_iov()) as libc::c_int,
)
};
if ret < 0 {
return Err("Error read_vectored from FD");
}
Ok(ret as usize)
}
pub fn write(&self, buf: &[u8]) -> Result<usize, &'static str> {
let ret = unsafe { libc::syscall(
libc::SYS_write,
self.fd,
buf.as_ptr() as usize,
buf.len()) };
if ret < 0 {
return Err("Error Writing to FD");
}
Ok(ret as usize)
}
pub fn write_all(&self, buf: &[u8]) -> Result<usize, &'static str> {
let x = unsafe { libc::syscall(libc::SYS_write, self.fd, buf.as_ptr() as usize, buf.len()) };
if x < 0 {
return Err("Error Writing to File");
}
Ok(x as usize)
}
}
impl fmt::Write for File {
fn write_str(&mut self, s: &str) -> fmt::Result {
let raw_s = s.as_bytes();
match self.write_all(raw_s) {
Ok(x) => Ok(()),
Err(e) => Err(fmt::Error),
}
// Ok(())
}
fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), fmt::Error> {
fmt::write(self, args)?;
// w.as_str().ok_or(fmt::Error)
Ok(())
}
}
impl fmt::Write for &File {
fn write_str(&mut self, s: &str) -> fmt::Result {
let raw_s = s.as_bytes();
match self.write_all(raw_s) {
Ok(x) => Ok(()),
Err(e) => Err(fmt::Error),
}
}
// fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), fmt::Error> {
// fmt::write(self, args)?;
// // w.as_str().ok_or(fmt::Error)
// Ok(())
// }
}
#[cfg(test)]
mod report_tests {
use std::io;
use libc::{O_CREAT,O_WRONLY,O_TRUNC,O_APPEND,O_LARGEFILE,S_IRUSR,S_IWUSR,S_IRGRP,S_IWGRP};
use std::os::unix::io::{FromRawFd};
use std::fs;
use std::fmt::Write;
use super::*;
use crate::common::{WISKTRACEFD, WISKFD};
lazy_static! {
pub static ref FILE: File = File::open("/tmp/testdataglobal",
(O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE) as i32,
(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) as i32,
true, 850).unwrap();
}
#[test]
fn report_test_006() -> io::Result<()> {
assert_eq!(FILE.as_raw_fd(), 850);
FILE.write_fmt(format_args!("Hello World: {}\n", 1)).unwrap();
assert_eq!(fs::read_to_string("/tmp/testdataglobal").unwrap(), "Hello World: 1\n");
Ok(())
}
}
I am still getting the following error about mutable reference
error[E0596]: cannot borrow data in a dereference of `fs::report_tests::FILE` as mutable
--> src/fs.rs:289:9
|
289 | FILE.write_fmt(format_args!("Hello World: {}\n", 1)).unwrap();
| ^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `fs::report_tests::FILE`