If my understanding is correct, the following code should produce an executable file. However it doesn't; it gets created, but the permissions specified aren't applied. What am I doing wrong?
use std::fs;
use std::os::unix::PermissionsExt;
fn main() {
fs::File::create("somefile").unwrap()
.metadata().unwrap()
.permissions()
.set_mode(0o770);
}
Use OpenOptions:
use std::fs;
use std::os::unix::OpenOptionsExt;
fn main() {
fs::OpenOptions::new()
.create(true)
.write(true)
.mode(0o770)
.open("somefile")
.unwrap();
}
You can also use set_permissions for existing path
use std::fs;
use std::os::unix::fs::PermissionsExt;
fn main(){
fs::set_permissions("/path", fs::Permissions::from_mode(0o655)).unwrap();
}
Related
I have a function foo that can't be modified and contains println! and eprintln! code in it.
fn foo() {
println!("hello");
}
After I call the function, I have to test what it printed so I want to capture the stdout/stderr into a variable.
I strongly recommend against doing this, but if you are using nightly and don't mind using a feature that seems unlikely to ever be stabilized, you can directly capture stdout and stderr using hidden functionality of the standard library:
#![feature(internal_output_capture)]
use std::sync::Arc;
fn foo() {
println!("hello");
eprintln!("world");
}
fn main() {
std::io::set_output_capture(Some(Default::default()));
foo();
let captured = std::io::set_output_capture(None);
let captured = captured.unwrap();
let captured = Arc::try_unwrap(captured).unwrap();
let captured = captured.into_inner().unwrap();
let captured = String::from_utf8(captured).unwrap();
assert_eq!(captured, "hello\nworld\n");
}
It's very rare that a function "cannot be changed", so I'd encourage you to do so and use dependency injection instead. For example, if you are able to edit foo but do not want to change its signature, move all the code to a new function with generics which you can test directly:
use std::io::{self, Write};
fn foo() {
foo_inner(io::stdout(), io::stderr()).unwrap()
}
fn foo_inner(mut out: impl Write, mut err: impl Write) -> io::Result<()> {
writeln!(out, "hello")?;
writeln!(err, "world")?;
Ok(())
}
See also:
How can I test stdin and stdout?
How to take ownership of T from Arc<Mutex<T>>?
How do I convert a Vector of bytes (u8) to a string?
Not sure if this would work on windows, but should work on unix like systems. You should replace the file descriptor to something you can read later. I don't think it is really easy.
I would suggest to use stdio_override which already does that for you using files. You can redirect it, then execute the function and the read the file content.
From the example:
use stdio_override::StdoutOverride;
use std::fs;
let file_name = "./test.txt";
let guard = StdoutOverride::override_file(file_name)?;
println!("Isan to Stdout!");
let contents = fs::read_to_string(file_name)?;
assert_eq!("Isan to Stdout!\n", contents);
drop(guard);
println!("Outside!");
The library also support anything that implements AsRawFd, through the override_raw call. Confirming that it will probably just work on unix.
Otherwise, you can check on the implementation on how it is done internally, and maybe you could bypass a writer instead of a file somehow.
Shadow println!:
use std::{fs::File, io::Write, mem::MaybeUninit, sync::Mutex};
static mut FILE: MaybeUninit<Mutex<File>> = MaybeUninit::uninit();
macro_rules! println {
($($tt:tt)*) => {{
unsafe { writeln!(&mut FILE.assume_init_mut().lock().unwrap(), $($tt)*).unwrap(); }
}}
}
fn foo() {
println!("hello");
}
fn main() {
unsafe {
FILE.write(Mutex::new(File::create("out").unwrap()));
}
foo();
}
why this code return false
use std::path::Path;
fn main() {
println!(
"Ends with? {:?}",
&Path::new("some.file.d.ts").ends_with("ts")
);
}
playground link
The documentation is explicit about this:
Determines whether child is a suffix of self.
Only considers whole path components to match
An extension like ts is not a whole path component.
So, a case where it would be true would be something like:
use std::path::Path;
fn main() {
println!(
"Ends with? {:?}",
&Path::new("/path/to/some.file.d.ts").ends_with("some.file.d.ts")
);
}
In C, I can use rewind back to the start, but I didn't found a similar way in Rust.
I want to open an existed file, and let the file pointer go back to the start point, write new words to it and cover the old one.
But now I can only write something after the last line of the original file and don't know how to change the file pointer.
I known that rust has a crate libc::rewind, but how to use it, or any other ways?
Use seek.
use std::io::{self, Seek, SeekFrom};
use std::fs::File;
fn main() -> io::Result<()> {
let mut file = File::open("foo.bar")?;
file.seek(SeekFrom::Start(0))?;
Ok(())
}
You can use rewind(). It is a syntactic wrapper around SeekFrom::Start(0):
use std::io::{self, Seek};
use std::fs::File;
fn main() -> io::Result<()> {
let mut file = File::open("foo.bar")?;
file.rewind()?;
Ok(())
}
In Bash this would be ${0##*/}.
use std::env;
use std::path::Path;
fn prog() -> String {
let prog = env::args().next().unwrap();
String::from(Path::new(&prog).file_name().unwrap().to_str().unwrap())
}
fn main() {
println!("{}", prog());
}
Is there a better way? (I particularly dislike those numerous unwrap()s.)
If you don't care about why you can't get the program name, you can handle all the potential errors with a judicious mix of map and and_then. Additionally, return an Option to indicate possible failure:
use std::env;
use std::path::Path;
use std::ffi::OsStr;
fn prog() -> Option<String> {
env::args().next()
.as_ref()
.map(Path::new)
.and_then(Path::file_name)
.and_then(OsStr::to_str)
.map(String::from)
}
fn main() {
println!("{:?}", prog());
}
If you wanted to follow delnan's awesome suggestion to use std::env::current_exe (which I just learned about!), replace env::args().next() with env::current_exe().ok().
If you do want to know why you can't get the program name (and knowing why is usually the first step to fixing a problem), then check out ker's answer.
You can also get rid of the unwraps and still report all error causes properly (instead of munching them into a "something failed" None). You aren't even required to specify the full paths to the conversion methods:
fn prog() -> Result<String, ProgError> {
let path = try!(env::current_exe());
let name = try!(path.file_name().ok_or(ProgError::NoFile));
let s_name = try!(name.to_str().ok_or(ProgError::NotUtf8));
Ok(s_name.to_owned())
}
Together with the future questionmark operator this can also be written as a single dot call chain:
fn prog() -> Result<String, ProgError> {
Ok(env::current_exe()?
.file_name().ok_or(ProgError::NoFile)?
.to_str().ok_or(ProgError::NotUtf8)?
.to_owned())
}
Of course this has the prerequisite of the ProgError type:
use std::io::Error;
#[derive(Debug)]
enum ProgError {
NoFile,
NotUtf8,
Io(Error),
}
impl From<Error> for ProgError {
fn from(err: Error) -> ProgError {
ProgError::Io(err)
}
}
try it out on the Playground
Just one more Option version :)
fn prog() -> Option<String> {
std::env::current_exe()
.ok()?
.file_name()?
.to_str()?
.to_owned()
.into()
}
How can I list all the files of a directory in Rust? I am looking for the equivalent of the following Python code.
files = os.listdir('./')
Use std::fs::read_dir(). Here's an example:
use std::fs;
fn main() {
let paths = fs::read_dir("./").unwrap();
for path in paths {
println!("Name: {}", path.unwrap().path().display())
}
}
It will simply iterate over the files and print out their names.
You could also use glob, which is expressly for this purpose.
extern crate glob;
use self::glob::glob;
let files:Vec<Path> = glob("*").collect();
This can be done with glob. Try this on the playground:
extern crate glob;
use glob::glob;
fn main() {
for e in glob("../*").expect("Failed to read glob pattern") {
println!("{}", e.unwrap().display());
}
}
You may see the source.
And for walking directories recursively, you can use the walkdir crate (Playground):
extern crate walkdir;
use walkdir::WalkDir;
fn main() {
for e in WalkDir::new(".").into_iter().filter_map(|e| e.ok()) {
if e.metadata().unwrap().is_file() {
println!("{}", e.path().display());
}
}
}
See also the Directory Traversal section of The Rust Cookbook.