Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
46 changes: 31 additions & 15 deletions java_runtime/src/classes/java/io/file_descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use java_class_proto::{JavaFieldProto, JavaMethodProto};
use java_constants::{FieldAccessFlags, MethodAccessFlags};
use jvm::{ClassInstanceRef, Jvm, Result};

use crate::{File, RuntimeClassProto, RuntimeContext};
use crate::{RuntimeClassProto, RuntimeContext};

// class java.io.FileDescriptor
pub struct FileDescriptor;
Expand All @@ -20,7 +20,7 @@ impl FileDescriptor {
JavaMethodProto::new("<clinit>", "()V", Self::cl_init, MethodAccessFlags::STATIC),
],
fields: vec![
JavaFieldProto::new("raw", "[B", Default::default()),
JavaFieldProto::new("fd", "I", Default::default()),
JavaFieldProto::new("err", "Ljava/io/FileDescriptor;", FieldAccessFlags::STATIC),
JavaFieldProto::new("in", "Ljava/io/FileDescriptor;", FieldAccessFlags::STATIC),
JavaFieldProto::new("out", "Ljava/io/FileDescriptor;", FieldAccessFlags::STATIC),
Expand All @@ -32,28 +32,28 @@ impl FileDescriptor {
async fn cl_init(jvm: &Jvm, runtime: &mut RuntimeContext) -> Result<()> {
tracing::debug!("java.io.FileDescriptor::<clinit>()");

let stderr_file = runtime.stderr();
if let Ok(stderr_file) = stderr_file {
let stderr_fd = runtime.stderr();
if let Ok(stderr_fd) = stderr_fd {
let mut stderr = jvm.new_class("java/io/FileDescriptor", "()V", []).await?;
jvm.put_rust_object_field(&mut stderr, "raw", stderr_file).await?;
jvm.put_field(&mut stderr, "fd", "I", stderr_fd.id() as i32).await?;

jvm.put_static_field("java/io/FileDescriptor", "err", "Ljava/io/FileDescriptor;", stderr)
.await?;
}

let stdin_file = runtime.stdin();
if let Ok(stdin_file) = stdin_file {
let stdin_fd = runtime.stdin();
if let Ok(stdin_fd) = stdin_fd {
let mut stdin = jvm.new_class("java/io/FileDescriptor", "()V", []).await?;
jvm.put_rust_object_field(&mut stdin, "raw", stdin_file).await?;
jvm.put_field(&mut stdin, "fd", "I", stdin_fd.id() as i32).await?;

jvm.put_static_field("java/io/FileDescriptor", "in", "Ljava/io/FileDescriptor;", stdin)
.await?;
}

let stdout_file = runtime.stdout();
if let Ok(stdout_file) = stdout_file {
let stdout_fd = runtime.stdout();
if let Ok(stdout_fd) = stdout_fd {
let mut stdout = jvm.new_class("java/io/FileDescriptor", "()V", []).await?;
jvm.put_rust_object_field(&mut stdout, "raw", stdout_file).await?;
jvm.put_field(&mut stdout, "fd", "I", stdout_fd.id() as i32).await?;

jvm.put_static_field("java/io/FileDescriptor", "out", "Ljava/io/FileDescriptor;", stdout)
.await?;
Expand All @@ -70,14 +70,30 @@ impl FileDescriptor {
Ok(())
}

pub async fn from_file(jvm: &Jvm, file: Box<dyn File>) -> Result<ClassInstanceRef<Self>> {
pub async fn from_fd(jvm: &Jvm, fd: crate::FileDescriptorId) -> Result<ClassInstanceRef<Self>> {
let mut this = jvm.new_class("java/io/FileDescriptor", "()V", []).await?;
jvm.put_rust_object_field(&mut this, "raw", file).await?;
jvm.put_field(&mut this, "fd", "I", fd.id() as i32).await?;

Ok(this.into())
}

pub async fn file(jvm: &Jvm, this: ClassInstanceRef<Self>) -> Result<Box<dyn File>> {
jvm.get_rust_object_field(&this, "raw").await
pub async fn file(jvm: &Jvm, runtime: &RuntimeContext, this: ClassInstanceRef<Self>) -> Result<Box<dyn crate::File>> {
let fd: i32 = jvm.get_field(&this, "fd", "I").await?;
if fd <= 0 {
return Err(jvm.exception("java/io/IOException", "Invalid file descriptor").await);
}
let fd = crate::FileDescriptorId::new(fd as u32);
match runtime.get_file(fd) {
Ok(file) => Ok(file),
Err(_) => Err(jvm.exception("java/io/IOException", "Invalid file descriptor").await),
}
}

pub async fn close(jvm: &Jvm, runtime: &RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
let fd: i32 = jvm.get_field(&this, "fd", "I").await?;
if fd > 0 {
runtime.close_file(crate::FileDescriptorId::new(fd as u32));
}
Ok(())
}
}
26 changes: 14 additions & 12 deletions java_runtime/src/classes/java/io/file_input_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,12 @@ impl FileInputStream {
let path = jvm.invoke_virtual(&file, "getPath", "()Ljava/lang/String;", ()).await?;
let path = JavaLangString::to_rust_string(jvm, &path).await?;

let rust_file = context.open(&path, false).await;
if rust_file.is_err() {
// TODO correct error handling
let fd = context.open(&path, false).await;
if fd.is_err() {
return Err(jvm.exception("java/io/FileNotFoundException", "File not found").await);
}

let fd = FileDescriptor::from_file(jvm, rust_file.unwrap()).await?;
let fd = FileDescriptor::from_fd(jvm, fd.unwrap()).await?;

let _: () = jvm
.invoke_special(&this, "java/io/FileInputStream", "<init>", "(Ljava/io/FileDescriptor;)V", (fd,))
Expand All @@ -73,11 +72,11 @@ impl FileInputStream {
Ok(())
}

async fn available(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i32> {
async fn available(jvm: &Jvm, context: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i32> {
tracing::debug!("java.io.FileInputStream::available({:?})", &this);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let rust_file = FileDescriptor::file(jvm, fd).await?;
let rust_file = FileDescriptor::file(jvm, context, fd).await?;

// TODO get os buffer size
let stat = rust_file.metadata().await.unwrap();
Expand All @@ -90,7 +89,7 @@ impl FileInputStream {

async fn read_array(
jvm: &Jvm,
_: &mut RuntimeContext,
context: &mut RuntimeContext,
this: ClassInstanceRef<Self>,
mut buf: ClassInstanceRef<Array<i8>>,
offset: i32,
Expand All @@ -99,7 +98,7 @@ impl FileInputStream {
tracing::debug!("java.io.FileInputStream::read({this:?}, {buf:?}, {offset:?}, {length:?})");

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let mut rust_file = FileDescriptor::file(jvm, fd).await?;
let mut rust_file = FileDescriptor::file(jvm, context, fd).await?;

let mut rust_buf = vec![0; length as _];
let read = rust_file.read(&mut rust_buf).await.unwrap();
Expand All @@ -112,11 +111,11 @@ impl FileInputStream {
Ok(read as _)
}

async fn read_byte(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i32> {
async fn read_byte(jvm: &Jvm, context: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i32> {
tracing::debug!("java.io.FileInputStream::read({:?})", &this);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let mut rust_file = FileDescriptor::file(jvm, fd).await?;
let mut rust_file = FileDescriptor::file(jvm, context, fd).await?;

let mut buf = [0; 1];
let read = rust_file.read(&mut buf).await.unwrap();
Expand All @@ -127,8 +126,11 @@ impl FileInputStream {
Ok(buf[0] as i32)
}

async fn close(_jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
tracing::debug!("stub java.io.FileInputStream::close({:?})", &this);
async fn close(jvm: &Jvm, context: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
tracing::debug!("java.io.FileInputStream::close({:?})", &this);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
FileDescriptor::close(jvm, context, fd).await?;

Ok(())
}
Expand Down
19 changes: 11 additions & 8 deletions java_runtime/src/classes/java/io/file_output_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ impl FileOutputStream {
let path = jvm.invoke_virtual(&file, "getPath", "()Ljava/lang/String;", ()).await?;
let path = JavaLangString::to_rust_string(jvm, &path).await?;

let file = context.open(&path, true).await.unwrap();
let fd = FileDescriptor::from_file(jvm, file).await?;
let fd = context.open(&path, true).await.unwrap();
let fd = FileDescriptor::from_fd(jvm, fd).await?;

let _: () = jvm
.invoke_special(&this, "java/io/FileOutputStream", "<init>", "(Ljava/io/FileDescriptor;)V", (fd,))
Expand All @@ -69,7 +69,7 @@ impl FileOutputStream {

async fn write_bytes_offset(
jvm: &Jvm,
_: &mut RuntimeContext,
context: &mut RuntimeContext,
this: ClassInstanceRef<Self>,
buffer: ClassInstanceRef<Array<i8>>,
offset: i32,
Expand All @@ -84,7 +84,7 @@ impl FileOutputStream {
);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let mut file = FileDescriptor::file(jvm, fd).await?;
let mut file = FileDescriptor::file(jvm, context, fd).await?;

let mut buf = vec![0; length as _];
jvm.array_raw_buffer(&buffer).await?.read(offset as _, &mut buf).unwrap();
Expand All @@ -94,19 +94,22 @@ impl FileOutputStream {
Ok(())
}

async fn write(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>, byte: i32) -> Result<()> {
async fn write(jvm: &Jvm, context: &mut RuntimeContext, this: ClassInstanceRef<Self>, byte: i32) -> Result<()> {
tracing::debug!("java.io.FileOutputStream::write({:?}, {:?})", &this, &byte);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let mut file = FileDescriptor::file(jvm, fd).await?;
let mut file = FileDescriptor::file(jvm, context, fd).await?;

file.write(&[byte as u8]).await.unwrap();

Ok(())
}

async fn close(_jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
tracing::debug!("stub java.io.FileInputStream::close({:?})", &this);
async fn close(jvm: &Jvm, context: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
tracing::debug!("java.io.FileOutputStream::close({:?})", &this);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
FileDescriptor::close(jvm, context, fd).await?;

Ok(())
}
Expand Down
36 changes: 19 additions & 17 deletions java_runtime/src/classes/java/io/random_access_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,11 @@ impl RandomAccessFile {

let write = mode.contains('w');

let rust_file = context.open(&name, write).await;
if rust_file.is_err() {
// TODO correct error handling
let fd_id = context.open(&name, write).await;
if fd_id.is_err() {
return Err(jvm.exception("java/io/FileNotFoundException", "File not found").await);
}
let fd = FileDescriptor::from_file(jvm, rust_file.unwrap()).await?;
let fd = FileDescriptor::from_fd(jvm, fd_id.unwrap()).await?;
jvm.put_field(&mut this, "fd", "Ljava/io/FileDescriptor;", fd).await?;

Ok(())
Expand Down Expand Up @@ -103,7 +102,7 @@ impl RandomAccessFile {

async fn read_offset_length(
jvm: &Jvm,
_: &mut RuntimeContext,
context: &mut RuntimeContext,
this: ClassInstanceRef<Self>,
mut buf: ClassInstanceRef<Array<i8>>,
offset: i32,
Expand All @@ -112,7 +111,7 @@ impl RandomAccessFile {
tracing::debug!("java.io.RandomAccessFile::read({:?}, {:?}, {:?}, {:?})", &this, &buf, &offset, &length);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let mut rust_file = FileDescriptor::file(jvm, fd).await?;
let mut rust_file = FileDescriptor::file(jvm, context, fd).await?;

let mut rust_buf = vec![0; length as usize];
let read = rust_file.read(&mut rust_buf).await.unwrap();
Expand All @@ -133,7 +132,7 @@ impl RandomAccessFile {

async fn write_offset_length(
jvm: &Jvm,
_: &mut RuntimeContext,
context: &mut RuntimeContext,
this: ClassInstanceRef<Self>,
buf: ClassInstanceRef<Array<i8>>,
offset: i32,
Expand All @@ -142,7 +141,7 @@ impl RandomAccessFile {
tracing::debug!("java.io.RandomAccessFile::write({:?}, {:?}, {:?}, {:?})", &this, &buf, &offset, &length);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let mut rust_file = FileDescriptor::file(jvm, fd).await?;
let mut rust_file = FileDescriptor::file(jvm, context, fd).await?;

let mut rust_buf = vec![0; length as usize];
jvm.array_raw_buffer(&buf).await?.read(offset as _, &mut rust_buf).unwrap();
Expand All @@ -151,44 +150,44 @@ impl RandomAccessFile {
Ok(())
}

async fn seek(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>, pos: i64) -> Result<()> {
async fn seek(jvm: &Jvm, context: &mut RuntimeContext, this: ClassInstanceRef<Self>, pos: i64) -> Result<()> {
tracing::debug!("java.io.RandomAccessFile::seek({:?}, {:?})", &this, &pos);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let mut rust_file = FileDescriptor::file(jvm, fd).await?;
let mut rust_file = FileDescriptor::file(jvm, context, fd).await?;

rust_file.seek(pos as _).await.unwrap();

Ok(())
}

async fn set_length(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>, new_length: i64) -> Result<()> {
async fn set_length(jvm: &Jvm, context: &mut RuntimeContext, this: ClassInstanceRef<Self>, new_length: i64) -> Result<()> {
tracing::debug!("java.io.RandomAccessFile::setLength({:?}, {:?})", &this, &new_length);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let mut rust_file = FileDescriptor::file(jvm, fd).await?;
let mut rust_file = FileDescriptor::file(jvm, context, fd).await?;

rust_file.set_len(new_length as _).await.unwrap();

Ok(())
}

async fn length(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i64> {
async fn length(jvm: &Jvm, context: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i64> {
tracing::debug!("java.io.RandomAccessFile::length({:?})", &this);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let rust_file = FileDescriptor::file(jvm, fd).await?;
let rust_file = FileDescriptor::file(jvm, context, fd).await?;

let len = rust_file.metadata().await.unwrap().size;

Ok(len as i64)
}

async fn get_file_pointer(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i64> {
async fn get_file_pointer(jvm: &Jvm, context: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<i64> {
tracing::debug!("java.io.RandomAccessFile::getFilePointer({:?})", &this);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
let rust_file = FileDescriptor::file(jvm, fd).await?;
let rust_file = FileDescriptor::file(jvm, context, fd).await?;

let pos = rust_file.tell().await.unwrap();

Expand All @@ -203,9 +202,12 @@ impl RandomAccessFile {
Ok(fd)
}

async fn close(_jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
async fn close(jvm: &Jvm, context: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
tracing::debug!("java.io.RandomAccessFile::close({:?})", &this);

let fd = jvm.get_field(&this, "fd", "Ljava/io/FileDescriptor;").await?;
FileDescriptor::close(jvm, context, fd).await?;

Ok(())
}
}
2 changes: 1 addition & 1 deletion java_runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ mod runtime;

pub use self::{
loader::{get_bootstrap_class_loader, get_runtime_class_proto},
runtime::{File, FileSize, FileStat, FileType, IOError, IOResult, Runtime, SpawnCallback},
runtime::{File, FileDescriptorId, FileSize, FileStat, FileType, IOError, IOResult, Runtime, SpawnCallback},
};

pub type RuntimeContext = dyn runtime::Runtime;
Expand Down
12 changes: 7 additions & 5 deletions java_runtime/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use dyn_clone::{DynClone, clone_trait_object};

use jvm::{ClassDefinition, Jvm, Result as JvmResult};

pub use io::{File, FileSize, FileStat, FileType, IOError, IOResult};
pub use io::{File, FileDescriptorId, FileSize, FileStat, FileType, IOError, IOResult};

#[async_trait::async_trait]
pub trait SpawnCallback: Sync + Send {
Expand All @@ -23,11 +23,13 @@ pub trait Runtime: Sync + Send + DynClone {
fn now(&self) -> u64; // unix time in millis
fn current_task_id(&self) -> u64;

fn stdin(&self) -> IOResult<Box<dyn File>>;
fn stdout(&self) -> IOResult<Box<dyn File>>;
fn stderr(&self) -> IOResult<Box<dyn File>>;
fn stdin(&self) -> IOResult<FileDescriptorId>;
fn stdout(&self) -> IOResult<FileDescriptorId>;
fn stderr(&self) -> IOResult<FileDescriptorId>;

async fn open(&self, path: &str, write: bool) -> IOResult<Box<dyn File>>;
async fn open(&self, path: &str, write: bool) -> IOResult<FileDescriptorId>;
fn get_file(&self, fd: FileDescriptorId) -> IOResult<Box<dyn File>>;
fn close_file(&self, fd: FileDescriptorId);
async fn unlink(&self, path: &str) -> IOResult<()>;
async fn metadata(&self, path: &str) -> IOResult<FileStat>;

Expand Down
13 changes: 13 additions & 0 deletions java_runtime/src/runtime/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@ use alloc::boxed::Box;

use dyn_clone::{DynClone, clone_trait_object};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct FileDescriptorId(u32);

impl FileDescriptorId {
pub fn new(id: u32) -> Self {
Self(id)
}

pub fn id(&self) -> u32 {
self.0
}
}

#[derive(Debug)]
pub enum IOError {
Unsupported,
Expand Down
Loading
Loading