how to solve IOerror (windows power shell) - rust

Please find the code I try to run below.
extern crate image;
use image::GenericImageView;
fn main() {
println!("Hello, world!");
// Use the open function to load an image from a Path.
// `open` returns a `DynamicImage` on success.
let img = image::open(
"C:/Users/hp/Desktop/Multiprocessor real-time scheduling/Project2/data/aLIEz.jpg",
)
.unwrap();
// The dimensions method returns the images width and height.
println!("dimensions {:?}", img.dimensions());
// The color method returns the image's `ColorType`.
println!("{:?}", img.color());
// Write the contents of this image to the Writer in PNG format.
img.save("C:/Users/hp/Desktop/Multiprocessor real-time scheduling/Project2/data/test.png")
.unwrap();
}
The error I want to solve (in the last line img.save) :
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: IoError(Os { code: 5, kind: PermissionDenied, message: "Accès refusé." })', src\main.rs:18:96

Related

Rust Axum Multipart Length Limit Exceeded

Referenced Axum documentation: docs.rs
Hello all, I am trying to create a simple file upload using HTML5 forms and Rust Axum.
The issue is that, while any normal file works, larger files (particularly video files) which I want to upload are too large. Axum (subsequently Tokio) panics because the Field size is too large for the file upload.
I can't seem to find any helpful information about either expanding the stream limit.
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="filename" accept="video/mp4">
<input type="submit" value="Upload video">
</form>
async fn upload(mut multipart: Multipart) {
while let Some(mut field) = multipart.next_field().await.unwrap() {
let name = field.name().unwrap().to_string();
let data = field.bytes().await.unwrap();
println!("Length of `{}` is {} bytes", name, data.len());
}
}
thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: MultipartError { source: failed to read stream: failed to read stream: length limit exceeded }', src/main.rs:84:40
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: MultipartError { source: failed to read stream: failed to read stream: length limit exceeded }', src/main.rs:84:40
thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: MultipartError { source: failed to read stream: failed to read stream: length limit exceeded }', src/main.rs:84:40
To not take away from the primary part of this code, I have omitted the router, but its application is: .route("/upload", post(upload)) as per the example shown in the Axum documentation.
Quick note: to enable Multipart file uploads, you must add the Cargo feature flag "multipart" with Axum.
Any help is appreciated. Thank you.
Have you tried using Axum's DefaultBodyLimit service?
use axum::{
Router,
routing::post,
body::Body,
extract::{DefaultBodyLimit, RawBody},
http::Request,
};
let app = Router::new()
.route(
"/",
// even with `DefaultBodyLimit` the request body is still just `Body`
post(|request: Request<Body>| async {}),
)
.layer(DefaultBodyLimit::max(1024));
I found this example here

`EPERM` on `pidfd_getfd` with socket

I want to transfer a socket between 2 unrelated processes.
Process 1 creates and listens on the socket, it then attaches shared memory and stores the socket file descriptor in this shared memory and awaits on signal SIGUSR1.
Process 2 attaches to the shared, attempts to transfer the file descriptor, then sends the signal SIGUSR1.
On calling pidfd_getfd in process 2, I get the error EPERM.
Process 1 output
fd: Data { socket: 3, pid: Pid(167046) }
Process 2 output
fd: Data { socket: 3, pid: Pid(167046) }
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: EPERM', src/bin/receive.rs:44:74
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Process 1
use std::os::fd::{AsRawFd, RawFd};
use nix::fcntl;
use nix::sys::{
mman, signal,
socket::{self, SockaddrLike},
};
use nix::unistd::{ftruncate, Pid};
#[derive(Debug)]
#[repr(C)]
struct Data {
socket: RawFd,
pid: Pid,
}
const PATH: &str = "/some_arbitrary_path_3";
fn main() {
// Create a TCP socket listening on localhost:8080
// ---------------------------------------------------------------------------------------------
let socket = socket::socket(
socket::AddressFamily::Inet6,
socket::SockType::Stream,
socket::SockFlag::empty(),
None,
)
.unwrap();
let local_host = libc::in6_addr {
s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
};
let addr = libc::sockaddr_in6 {
sin6_family: u16::try_from(libc::AF_INET6).unwrap(),
sin6_port: 8765,
sin6_flowinfo: u32::default(),
sin6_addr: local_host,
sin6_scope_id: u32::default(),
};
let addr = unsafe {
socket::SockaddrIn6::from_raw(
std::ptr::addr_of!(addr).cast(),
Some(u32::try_from(std::mem::size_of::<libc::sockaddr_in6>()).unwrap()),
)
.unwrap()
};
socket::bind(socket, &addr).unwrap();
socket::listen(socket, 64).unwrap();
// Store socket file descriptor in shared memory
// ---------------------------------------------------------------------------------------------
let shared_memory_object = std::mem::ManuallyDrop::new(
mman::shm_open(
PATH,
fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CREAT | fcntl::OFlag::O_EXCL,
// TODO: Restrict these to minimum (likely read+write group)
// Uses full permissions
nix::sys::stat::Mode::all(),
)
.unwrap(),
);
let length = std::mem::size_of::<Data>();
ftruncate(shared_memory_object.as_raw_fd(), length as i64).unwrap();
let mapped_shared_memory = unsafe {
mman::mmap(
None,
std::num::NonZeroUsize::new(length).unwrap(),
mman::ProtFlags::PROT_WRITE | mman::ProtFlags::PROT_READ,
mman::MapFlags::MAP_SHARED,
Some(&*shared_memory_object),
0,
)
.unwrap()
};
let ptr = mapped_shared_memory.cast::<Data>();
let pid = Pid::this();
unsafe {
std::ptr::write(ptr, Data { socket, pid });
}
println!("fd: {:?}", unsafe { &*ptr });
// Await SIGUSR1
// ---------------------------------------------------------------------------------------------
let mut sigset = signal::SigSet::empty();
sigset.add(signal::Signal::SIGUSR1);
sigset.wait().unwrap();
}
Process 2
use std::os::fd::AsRawFd;
use std::os::fd::RawFd;
use nix::fcntl;
use nix::sys::{mman, pidfd, signal::Signal};
use nix::unistd::Pid;
#[derive(Debug)]
#[repr(C)]
struct Data {
socket: RawFd,
pid: Pid,
}
const PATH: &str = "/some_arbitrary_path_3";
fn main() {
// Get shared memory object.
let shared_memory_object = std::mem::ManuallyDrop::new(
mman::shm_open(PATH, fcntl::OFlag::O_RDWR, nix::sys::stat::Mode::all()).unwrap(),
);
let length = std::mem::size_of::<Data>();
// Map shared memory.
let mapped_shared_memory = unsafe {
mman::mmap(
None,
std::num::NonZeroUsize::new(length).unwrap(),
mman::ProtFlags::PROT_WRITE | mman::ProtFlags::PROT_READ,
mman::MapFlags::MAP_SHARED,
Some(&*shared_memory_object),
0,
)
.unwrap()
};
// Read data.
let ptr = mapped_shared_memory.cast::<Data>();
let data = unsafe { &mut *ptr };
println!("fd: {:?}", data);
// Transfer socket file descriptor.
let pid_fd = pidfd::pid_open(data.pid, false).unwrap();
let new_socket = pidfd::pidfd_getfd(pid_fd.as_raw_fd(), data.socket).unwrap();
data.socket = new_socket.as_raw_fd();
// Send SIGUSR1
pidfd::pidfd_send_signal(pid_fd, Signal::SIGUSR1, None).unwrap();
}
Dependencies
The dependencies I'm using here are:
nix = { git = "https://github.com/JonathanWoollett-Light/nix", rev = "747b7abf9e2dd57d6e52b7d9288f836780f0ec15" }
libc = "0.2.139" # https://crates.io/crates/libc/0.2.139
There are a few ways to circumvent this.
Run the process as privileged (e.g. sudo).
Use ptrace in the ancestor to give the successor permissions. While this can work, it is very tricky and it is using an extremely over-complicated tool for what we are doing here.
Send the file descriptor over a UDS (Unix Domain Socket), this works, but sending file descriptors over a UDS is ugly.
Enable the SO_REUSEPORT option on the socket such that the new process can use the socket without needing to transfer the file descriptor. This is my preferred solution.

Rust thrussh library client example fails at channel_open_session

In thrussh's documentation they have server and client example code.
Code based on the example server code has been working fine in various projects. However, the client example fails at the line:
let mut channel = session.channel_open_session().await.unwrap();
The error I get is this:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Disconnect', src/main.rs:121:64
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
I'm not sure what is causing the panic as everything works fine up until that point. The server calls both finished_auth() and channel_open_confirmation() but never gets to call channel_open_session(). I've been looking through the source but I can't seem to identify what's wrong.
Here's the full code
use thrussh_keys::*;
use thrussh::*;
let ssh_config = thrussh::client::Config::default();
let ssh_config = Arc::new(ssh_config);
let sh = Client {};
let key = thrussh_keys::load_secret_key("server.key", passphrase).unwrap();
let mut agent = thrussh_keys::agent::client::AgentClient::connect_env().await.unwrap();
agent.add_identity(&key, &[]).await.unwrap();
let mut session = thrussh::client::connect(ssh_config, format!("localhost:{}", config.port), sh)
.await
.unwrap();
println!("connected");
if session
.authenticate_future(config.user, key.clone_public_key(), agent)
.await
.1
.unwrap()
{
println!("session authenticated");
let mut channel = session.channel_open_session().await.unwrap();
channel.data(&b"Hello, world!"[..]).await.unwrap();
if let Some(msg) = channel.wait().await {
println!("{:?}", msg)
}
}
the code on the server side is the same as the server example aside from writing the key to disk so that it can be used in the client code.
I guess the channel open response package was consumed by the fn channel_open_confirmation for some reason. Therefore, the wait_channel_confirmation will be pending for receiving the confirmation package for ever.
If you comment out the function implementation channel_open_confirmation for Client, it should work.
The trait does have a default implementation for this method, which sends out the OpenChannelMsg.
So, the demo is improper, unluckily, I have no access to report this issue.

How can I get the message string from std::io::Error?

This works:
format!("{:?}", error))
// Os { code: 13, kind: PermissionDenied, message: "Permission denied" }
But I want only the message field, not the full debug print. How do I get it?
error.message // unknown field
error.message() // no method named `message` found for type `std::io::Error` in the current scope
I don't think there's anything that will get you exactly "Permission denied". The closest I know of is the Display implementation of the Error, which still includes the underlying error code:
use std::fs::File;
use std::error::Error;
fn main() {
let error = File::open("/does-not-exist").unwrap_err();
println!("{:?}", error);
// Error { repr: Os { code: 2, message: "No such file or directory" } }
println!("{}", error);
// No such file or directory (os error 2)
println!("{}", error.description());
// entity not found
}
If this is suitable, you can use error.to_string().
The standard library gets this string from sys::os, which gets defined based on the platform. For example, on UNIX-like platforms, it uses strerror_r. This function does not appear to be exposed in any public fashion, however.

Why do I get a Bad File Descriptor error when writing to opened File?

Calling write_all on a file returns an error with the description: os error. Debug printing the error outputs: Err(Error { repr: Os(9) })
What does the error mean?
You didn't include any code, so I had to make wild guesses about what you are doing. Here's one piece of code that reproduces your error:
use std::fs;
use std::io::Write;
fn main() {
let mut f = fs::File::open("/").unwrap();
// f.write_all(b"hello").unwrap();
// Error { repr: Os(9) }
match f.write_all(b"hello") {
Ok(..) => {},
Err(e) => println!("{}", e),
}
// Bad file descriptor (os error 9)
}
If you use the Display ({}) format instead of Debug ({:?}), you will see an error message that is nicer than just the error code. Note that unwrap will use the Debug formatter, so you have to use match in this case.
You could also look up the error code in the kernel source. You don't indicate if you are running Windows (unlikely), OS X or Linux, so I guessed Linux.
There are lots of SO questions that then explain what the code can mean, but I'm sure you know how to search through those, now that you have a handle on the problem.

Resources