diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2020-08-28 17:08:24 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-28 17:08:24 +0200 |
commit | 7e946858a4a0a03c1461590c6fc8a315738a627a (patch) | |
tree | 5a6a391fead573b85fb905bb5c4ea8287dc18d13 /cli/ops/fs.rs | |
parent | 31f32ed8c4082d36ad2a4ea460366c0d57a5ddbc (diff) |
refactor: migrate ops to new dispatch wrapper (#7118)
Diffstat (limited to 'cli/ops/fs.rs')
-rw-r--r-- | cli/ops/fs.rs | 1163 |
1 files changed, 874 insertions, 289 deletions
diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs index 28b2a7e55..3b8946057 100644 --- a/cli/ops/fs.rs +++ b/cli/ops/fs.rs @@ -1,21 +1,20 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Some deserializer fields are only used on Unix and Windows build fails without it -use super::dispatch_json::{blocking_json, Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use super::io::std_file_resource; use super::io::{FileMetadata, StreamResource, StreamResourceHolder}; use crate::ops::dispatch_json::JsonResult; use crate::state::State; use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; -use futures::future::FutureExt; use std::cell::RefCell; use std::convert::From; use std::env::{current_dir, set_current_dir, temp_dir}; use std::io; +use std::io::{Seek, SeekFrom}; use std::path::{Path, PathBuf}; use std::rc::Rc; use std::time::SystemTime; @@ -29,30 +28,157 @@ pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { i.register_op("op_open_sync", s.stateful_json_op_sync(t, op_open_sync)); i.register_op("op_open_async", s.stateful_json_op_async(t, op_open_async)); - i.register_op("op_seek", s.stateful_json_op2(op_seek)); - i.register_op("op_fdatasync", s.stateful_json_op2(op_fdatasync)); - i.register_op("op_fsync", s.stateful_json_op2(op_fsync)); - i.register_op("op_fstat", s.stateful_json_op2(op_fstat)); - i.register_op("op_umask", s.stateful_json_op(op_umask)); - i.register_op("op_chdir", s.stateful_json_op(op_chdir)); - i.register_op("op_mkdir", s.stateful_json_op(op_mkdir)); - i.register_op("op_chmod", s.stateful_json_op(op_chmod)); - i.register_op("op_chown", s.stateful_json_op(op_chown)); - i.register_op("op_remove", s.stateful_json_op(op_remove)); - i.register_op("op_copy_file", s.stateful_json_op(op_copy_file)); - i.register_op("op_stat", s.stateful_json_op(op_stat)); - i.register_op("op_realpath", s.stateful_json_op(op_realpath)); - i.register_op("op_read_dir", s.stateful_json_op(op_read_dir)); - i.register_op("op_rename", s.stateful_json_op(op_rename)); - i.register_op("op_link", s.stateful_json_op(op_link)); - i.register_op("op_symlink", s.stateful_json_op(op_symlink)); - i.register_op("op_read_link", s.stateful_json_op(op_read_link)); - i.register_op("op_ftruncate", s.stateful_json_op2(op_ftruncate)); - i.register_op("op_truncate", s.stateful_json_op(op_truncate)); - i.register_op("op_make_temp_dir", s.stateful_json_op(op_make_temp_dir)); - i.register_op("op_make_temp_file", s.stateful_json_op(op_make_temp_file)); - i.register_op("op_cwd", s.stateful_json_op(op_cwd)); - i.register_op("op_utime", s.stateful_json_op(op_utime)); + i.register_op("op_seek_sync", s.stateful_json_op_sync(t, op_seek_sync)); + i.register_op("op_seek_async", s.stateful_json_op_async(t, op_seek_async)); + + i.register_op( + "op_fdatasync_sync", + s.stateful_json_op_sync(t, op_fdatasync_sync), + ); + i.register_op( + "op_fdatasync_async", + s.stateful_json_op_async(t, op_fdatasync_async), + ); + + i.register_op("op_fsync_sync", s.stateful_json_op_sync(t, op_fsync_sync)); + i.register_op( + "op_fsync_async", + s.stateful_json_op_async(t, op_fsync_async), + ); + + i.register_op("op_fstat_sync", s.stateful_json_op_sync(t, op_fstat_sync)); + i.register_op( + "op_fstat_async", + s.stateful_json_op_async(t, op_fstat_async), + ); + + i.register_op("op_umask", s.stateful_json_op_sync(t, op_umask)); + i.register_op("op_chdir", s.stateful_json_op_sync(t, op_chdir)); + + i.register_op("op_mkdir_sync", s.stateful_json_op_sync(t, op_mkdir_sync)); + i.register_op( + "op_mkdir_async", + s.stateful_json_op_async(t, op_mkdir_async), + ); + + i.register_op("op_chmod_sync", s.stateful_json_op_sync(t, op_chmod_sync)); + i.register_op( + "op_chmod_async", + s.stateful_json_op_async(t, op_chmod_async), + ); + + i.register_op("op_chown_sync", s.stateful_json_op_sync(t, op_chown_sync)); + i.register_op( + "op_chown_async", + s.stateful_json_op_async(t, op_chown_async), + ); + + i.register_op("op_remove_sync", s.stateful_json_op_sync(t, op_remove_sync)); + i.register_op( + "op_remove_async", + s.stateful_json_op_async(t, op_remove_async), + ); + + i.register_op( + "op_copy_file_sync", + s.stateful_json_op_sync(t, op_copy_file_sync), + ); + i.register_op( + "op_copy_file_async", + s.stateful_json_op_async(t, op_copy_file_async), + ); + + i.register_op("op_stat_sync", s.stateful_json_op_sync(t, op_stat_sync)); + i.register_op("op_stat_async", s.stateful_json_op_async(t, op_stat_async)); + + i.register_op( + "op_realpath_sync", + s.stateful_json_op_sync(t, op_realpath_sync), + ); + i.register_op( + "op_realpath_async", + s.stateful_json_op_async(t, op_realpath_async), + ); + + i.register_op( + "op_read_dir_sync", + s.stateful_json_op_sync(t, op_read_dir_sync), + ); + i.register_op( + "op_read_dir_async", + s.stateful_json_op_async(t, op_read_dir_async), + ); + + i.register_op("op_rename_sync", s.stateful_json_op_sync(t, op_rename_sync)); + i.register_op( + "op_rename_async", + s.stateful_json_op_async(t, op_rename_async), + ); + + i.register_op("op_link_sync", s.stateful_json_op_sync(t, op_link_sync)); + i.register_op("op_link_async", s.stateful_json_op_async(t, op_link_async)); + + i.register_op( + "op_symlink_sync", + s.stateful_json_op_sync(t, op_symlink_sync), + ); + i.register_op( + "op_symlink_async", + s.stateful_json_op_async(t, op_symlink_async), + ); + + i.register_op( + "op_read_link_sync", + s.stateful_json_op_sync(t, op_read_link_sync), + ); + i.register_op( + "op_read_link_async", + s.stateful_json_op_async(t, op_read_link_async), + ); + + i.register_op( + "op_ftruncate_sync", + s.stateful_json_op_sync(t, op_ftruncate_sync), + ); + i.register_op( + "op_ftruncate_async", + s.stateful_json_op_async(t, op_ftruncate_async), + ); + + i.register_op( + "op_truncate_sync", + s.stateful_json_op_sync(t, op_truncate_sync), + ); + i.register_op( + "op_truncate_async", + s.stateful_json_op_async(t, op_truncate_async), + ); + + i.register_op( + "op_make_temp_dir_sync", + s.stateful_json_op_sync(t, op_make_temp_dir_sync), + ); + i.register_op( + "op_make_temp_dir_async", + s.stateful_json_op_async(t, op_make_temp_dir_async), + ); + + i.register_op( + "op_make_temp_file_sync", + s.stateful_json_op_sync(t, op_make_temp_file_sync), + ); + i.register_op( + "op_make_temp_file_async", + s.stateful_json_op_async(t, op_make_temp_file_async), + ); + + i.register_op("op_cwd", s.stateful_json_op_sync(t, op_cwd)); + + i.register_op("op_utime_sync", s.stateful_json_op_sync(t, op_utime_sync)); + i.register_op( + "op_utime_async", + s.stateful_json_op_async(t, op_utime_async), + ); } fn into_string(s: std::ffi::OsString) -> Result<String, ErrBox> { @@ -165,19 +291,12 @@ async fn op_open_async( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct SeekArgs { - promise_id: Option<u64>, rid: i32, offset: i64, whence: i32, } -fn op_seek( - isolate_state: &mut CoreIsolateState, - _state: &Rc<State>, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { - use std::io::{Seek, SeekFrom}; +fn seek_helper(args: Value) -> Result<(u32, SeekFrom), ErrBox> { let args: SeekArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let offset = args.offset; @@ -192,154 +311,171 @@ fn op_seek( } }; - let resource_table = isolate_state.resource_table.clone(); - let is_sync = args.promise_id.is_none(); + Ok((rid, seek_from)) +} - if is_sync { - let mut resource_table = resource_table.borrow_mut(); - let pos = std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.seek(seek_from).map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot seek on this type of resource")), - })?; - Ok(JsonOp::Sync(json!(pos))) - } else { - // TODO(ry) This is a fake async op. We need to use poll_fn, - // tokio::fs::File::start_seek and tokio::fs::File::poll_complete - let fut = async move { - let mut resource_table = resource_table.borrow_mut(); - let pos = std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.seek(seek_from).map_err(ErrBox::from), - Err(_) => { - Err(ErrBox::type_error("cannot seek on this type of resource")) - } - })?; - Ok(json!(pos)) - }; - Ok(JsonOp::Async(fut.boxed_local())) - } +fn op_seek_sync( + _state: &State, + resource_table: &mut ResourceTable, + args: Value, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result<Value, ErrBox> { + let (rid, seek_from) = seek_helper(args)?; + let pos = std_file_resource(resource_table, rid, |r| match r { + Ok(std_file) => std_file.seek(seek_from).map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot seek on this type of resource".to_string(), + )), + })?; + Ok(json!(pos)) +} + +async fn op_seek_async( + _state: Rc<State>, + resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { + let (rid, seek_from) = seek_helper(args)?; + // TODO(ry) This is a fake async op. We need to use poll_fn, + // tokio::fs::File::start_seek and tokio::fs::File::poll_complete + let mut resource_table = resource_table.borrow_mut(); + let pos = std_file_resource(&mut resource_table, rid, |r| match r { + Ok(std_file) => std_file.seek(seek_from).map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot seek on this type of resource".to_string(), + )), + })?; + Ok(json!(pos)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct FdatasyncArgs { - promise_id: Option<u64>, rid: i32, } -fn op_fdatasync( - isolate_state: &mut CoreIsolateState, - state: &Rc<State>, +fn op_fdatasync_sync( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { state.check_unstable("Deno.fdatasync"); let args: FdatasyncArgs = serde_json::from_value(args)?; let rid = args.rid as u32; + std_file_resource(resource_table, rid, |r| match r { + Ok(std_file) => std_file.sync_data().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot sync this type of resource".to_string(), + )), + })?; + Ok(json!({})) +} - let resource_table = isolate_state.resource_table.clone(); - let is_sync = args.promise_id.is_none(); - - if is_sync { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.sync_data().map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot sync this type of resource")), - })?; - Ok(JsonOp::Sync(json!({}))) - } else { - let fut = async move { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.sync_data().map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot sync this type of resource")), - })?; - Ok(json!({})) - }; - Ok(JsonOp::Async(fut.boxed_local())) - } +async fn op_fdatasync_async( + state: Rc<State>, + resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { + state.check_unstable("Deno.fdatasync"); + let args: FdatasyncArgs = serde_json::from_value(args)?; + let rid = args.rid as u32; + let mut resource_table = resource_table.borrow_mut(); + std_file_resource(&mut resource_table, rid, |r| match r { + Ok(std_file) => std_file.sync_data().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot sync this type of resource".to_string(), + )), + })?; + Ok(json!({})) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct FsyncArgs { - promise_id: Option<u64>, rid: i32, } -fn op_fsync( - isolate_state: &mut CoreIsolateState, - state: &Rc<State>, +fn op_fsync_sync( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { state.check_unstable("Deno.fsync"); let args: FsyncArgs = serde_json::from_value(args)?; let rid = args.rid as u32; + std_file_resource(resource_table, rid, |r| match r { + Ok(std_file) => std_file.sync_all().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot sync this type of resource".to_string(), + )), + })?; + Ok(json!({})) +} - let resource_table = isolate_state.resource_table.clone(); - let is_sync = args.promise_id.is_none(); - - if is_sync { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.sync_all().map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot sync this type of resource")), - })?; - Ok(JsonOp::Sync(json!({}))) - } else { - let fut = async move { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.sync_all().map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot sync this type of resource")), - })?; - Ok(json!({})) - }; - Ok(JsonOp::Async(fut.boxed_local())) - } +async fn op_fsync_async( + state: Rc<State>, + resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { + state.check_unstable("Deno.fsync"); + let args: FsyncArgs = serde_json::from_value(args)?; + let rid = args.rid as u32; + let mut resource_table = resource_table.borrow_mut(); + std_file_resource(&mut resource_table, rid, |r| match r { + Ok(std_file) => std_file.sync_all().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot sync this type of resource".to_string(), + )), + })?; + Ok(json!({})) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct FstatArgs { - promise_id: Option<u64>, rid: i32, } -fn op_fstat( - isolate_state: &mut CoreIsolateState, - state: &Rc<State>, +fn op_fstat_sync( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { state.check_unstable("Deno.fstat"); let args: FstatArgs = serde_json::from_value(args)?; let rid = args.rid as u32; + let metadata = std_file_resource(resource_table, rid, |r| match r { + Ok(std_file) => std_file.metadata().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot stat this type of resource".to_string(), + )), + })?; + Ok(get_stat_json(metadata).unwrap()) +} - let resource_table = isolate_state.resource_table.clone(); - let is_sync = args.promise_id.is_none(); - - if is_sync { - let mut resource_table = resource_table.borrow_mut(); - let metadata = std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.metadata().map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot stat this type of resource")), - })?; - Ok(JsonOp::Sync(get_stat_json(metadata).unwrap())) - } else { - let fut = async move { - let mut resource_table = resource_table.borrow_mut(); - let metadata = - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.metadata().map_err(ErrBox::from), - Err(_) => { - Err(ErrBox::type_error("cannot stat this type of resource")) - } - })?; - Ok(get_stat_json(metadata).unwrap()) - }; - Ok(JsonOp::Async(fut.boxed_local())) - } +async fn op_fstat_async( + state: Rc<State>, + resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { + state.check_unstable("Deno.fstat"); + let args: FstatArgs = serde_json::from_value(args)?; + let rid = args.rid as u32; + let mut resource_table = resource_table.borrow_mut(); + let metadata = std_file_resource(&mut resource_table, rid, |r| match r { + Ok(std_file) => std_file.metadata().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot stat this type of resource".to_string(), + )), + })?; + Ok(get_stat_json(metadata).unwrap()) } #[derive(Deserialize)] @@ -348,10 +484,11 @@ struct UmaskArgs { } fn op_umask( - state: &Rc<State>, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { state.check_unstable("Deno.umask"); let args: UmaskArgs = serde_json::from_value(args)?; // TODO implement umask for Windows @@ -376,7 +513,7 @@ fn op_umask( let _ = umask(prev); prev }; - Ok(JsonOp::Sync(json!(r.bits() as u32))) + Ok(json!(r.bits() as u32)) } } @@ -386,39 +523,59 @@ struct ChdirArgs { } fn op_chdir( - state: &Rc<State>, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { let args: ChdirArgs = serde_json::from_value(args)?; let d = PathBuf::from(&args.directory); state.check_read(&d)?; set_current_dir(&d)?; - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct MkdirArgs { - promise_id: Option<u64>, path: String, recursive: bool, mode: Option<u32>, } -fn op_mkdir( - state: &Rc<State>, +fn op_mkdir_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { let args: MkdirArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); let mode = args.mode.unwrap_or(0o777) & 0o777; - state.check_write(&path)?; + debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive); + let mut builder = std::fs::DirBuilder::new(); + builder.recursive(args.recursive); + #[cfg(unix)] + { + use std::os::unix::fs::DirBuilderExt; + builder.mode(mode); + } + builder.create(path)?; + Ok(json!({})) +} - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { +async fn op_mkdir_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { + let args: MkdirArgs = serde_json::from_value(args)?; + let path = Path::new(&args.path).to_path_buf(); + let mode = args.mode.unwrap_or(0o777) & 0o777; + state.check_write(&path)?; + tokio::task::spawn_blocking(move || { debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive); let mut builder = std::fs::DirBuilder::new(); builder.recursive(args.recursive); @@ -430,30 +587,57 @@ fn op_mkdir( builder.create(path)?; Ok(json!({})) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct ChmodArgs { - promise_id: Option<u64>, path: String, mode: u32, } -fn op_chmod( - state: &Rc<State>, +fn op_chmod_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { let args: ChmodArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); let mode = args.mode & 0o777; state.check_write(&path)?; + debug!("op_chmod_sync {} {:o}", path.display(), mode); + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let permissions = PermissionsExt::from_mode(mode); + std::fs::set_permissions(&path, permissions)?; + Ok(json!({})) + } + // TODO Implement chmod for Windows (#4357) + #[cfg(not(unix))] + { + // Still check file/dir exists on Windows + let _metadata = std::fs::metadata(&path)?; + Err(ErrBox::error("Not implemented")) + } +} - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_chmod {} {:o}", path.display(), mode); +async fn op_chmod_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { + let args: ChmodArgs = serde_json::from_value(args)?; + let path = Path::new(&args.path).to_path_buf(); + let mode = args.mode & 0o777; + state.check_write(&path)?; + tokio::task::spawn_blocking(move || { + debug!("op_chmod_async {} {:o}", path.display(), mode); #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; @@ -469,30 +653,64 @@ fn op_chmod( Err(ErrBox::not_supported()) } }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct ChownArgs { - promise_id: Option<u64>, path: String, uid: Option<u32>, gid: Option<u32>, } -fn op_chown( - state: &Rc<State>, +fn op_chown_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { let args: ChownArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); - state.check_write(&path)?; + debug!( + "op_chown_sync {} {:?} {:?}", + path.display(), + args.uid, + args.gid, + ); + #[cfg(unix)] + { + use nix::unistd::{chown, Gid, Uid}; + let nix_uid = args.uid.map(Uid::from_raw); + let nix_gid = args.gid.map(Gid::from_raw); + chown(&path, nix_uid, nix_gid)?; + Ok(json!({})) + } + // TODO Implement chown for Windows + #[cfg(not(unix))] + { + Err(ErrBox::error("Not implemented")) + } +} - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_chown {} {:?} {:?}", path.display(), args.uid, args.gid,); +async fn op_chown_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { + let args: ChownArgs = serde_json::from_value(args)?; + let path = Path::new(&args.path).to_path_buf(); + state.check_write(&path)?; + tokio::task::spawn_blocking(move || { + debug!( + "op_chown_async {} {:?} {:?}", + path.display(), + args.uid, + args.gid, + ); #[cfg(unix)] { use nix::unistd::{chown, Gid, Uid}; @@ -505,35 +723,80 @@ fn op_chown( #[cfg(not(unix))] Err(ErrBox::not_supported()) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct RemoveArgs { - promise_id: Option<u64>, path: String, recursive: bool, } -fn op_remove( - state: &Rc<State>, +fn op_remove_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + let args: RemoveArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + let recursive = args.recursive; + + state.check_write(&path)?; + + #[cfg(not(unix))] + use std::os::windows::prelude::MetadataExt; + + let metadata = std::fs::symlink_metadata(&path)?; + + debug!("op_remove_sync {} {}", path.display(), recursive); + let file_type = metadata.file_type(); + if file_type.is_file() { + std::fs::remove_file(&path)?; + } else if recursive { + std::fs::remove_dir_all(&path)?; + } else if file_type.is_symlink() { + #[cfg(unix)] + std::fs::remove_file(&path)?; + #[cfg(not(unix))] + { + use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; + if metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 { + std::fs::remove_dir(&path)?; + } else { + std::fs::remove_file(&path)?; + } + } + } else if file_type.is_dir() { + std::fs::remove_dir(&path)?; + } else { + // pipes, sockets, etc... + std::fs::remove_file(&path)?; + } + Ok(json!({})) +} + +async fn op_remove_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { let args: RemoveArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); let recursive = args.recursive; state.check_write(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { + tokio::task::spawn_blocking(move || { #[cfg(not(unix))] use std::os::windows::prelude::MetadataExt; let metadata = std::fs::symlink_metadata(&path)?; - debug!("op_remove {} {}", path.display(), recursive); + debug!("op_remove_async {} {}", path.display(), recursive); let file_type = metadata.file_type(); if file_type.is_file() { std::fs::remove_file(&path)?; @@ -559,21 +822,49 @@ fn op_remove( } Ok(json!({})) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct CopyFileArgs { - promise_id: Option<u64>, from: String, to: String, } -fn op_copy_file( - state: &Rc<State>, +fn op_copy_file_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + let args: CopyFileArgs = serde_json::from_value(args)?; + let from = PathBuf::from(&args.from); + let to = PathBuf::from(&args.to); + + state.check_read(&from)?; + state.check_write(&to)?; + + debug!("op_copy_file_sync {} {}", from.display(), to.display()); + // On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput + // See https://github.com/rust-lang/rust/issues/54800 + // Once the issue is resolved, we should remove this workaround. + if cfg!(unix) && !from.is_file() { + return Err(ErrBox::new("NotFound", "File not found")); + } + + // returns size of from as u64 (we ignore) + std::fs::copy(&from, &to)?; + Ok(json!({})) +} + +async fn op_copy_file_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { let args: CopyFileArgs = serde_json::from_value(args)?; let from = PathBuf::from(&args.from); let to = PathBuf::from(&args.to); @@ -581,9 +872,8 @@ fn op_copy_file( state.check_read(&from)?; state.check_write(&to)?; - debug!("op_copy_file {} {}", from.display(), to.display()); - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { + debug!("op_copy_file_async {} {}", from.display(), to.display()); + tokio::task::spawn_blocking(move || { // On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput // See https://github.com/rust-lang/rust/issues/54800 // Once the issue is resolved, we should remove this workaround. @@ -595,6 +885,8 @@ fn op_copy_file( std::fs::copy(&from, &to)?; Ok(json!({})) }) + .await + .unwrap() } fn to_msec(maybe_time: Result<SystemTime, io::Error>) -> serde_json::Value { @@ -658,25 +950,43 @@ fn get_stat_json(metadata: std::fs::Metadata) -> JsonResult { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct StatArgs { - promise_id: Option<u64>, path: String, lstat: bool, } -fn op_stat( - state: &Rc<State>, +fn op_stat_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + let args: StatArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + let lstat = args.lstat; + state.check_read(&path)?; + debug!("op_stat_sync {} {}", path.display(), lstat); + let metadata = if lstat { + std::fs::symlink_metadata(&path)? + } else { + std::fs::metadata(&path)? + }; + get_stat_json(metadata) +} + +async fn op_stat_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { let args: StatArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); let lstat = args.lstat; state.check_read(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_stat {} {}", path.display(), lstat); + tokio::task::spawn_blocking(move || { + debug!("op_stat_async {} {}", path.display(), lstat); let metadata = if lstat { std::fs::symlink_metadata(&path)? } else { @@ -684,20 +994,22 @@ fn op_stat( }; get_stat_json(metadata) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct RealpathArgs { - promise_id: Option<u64>, path: String, } -fn op_realpath( - state: &Rc<State>, +fn op_realpath_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { let args: RealpathArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); @@ -706,9 +1018,34 @@ fn op_realpath( state.check_read_blind(¤t_dir()?, "CWD")?; } - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_realpath {}", path.display()); + debug!("op_realpath_sync {}", path.display()); + // corresponds to the realpath on Unix and + // CreateFile and GetFinalPathNameByHandle on Windows + let realpath = std::fs::canonicalize(&path)?; + let mut realpath_str = + into_string(realpath.into_os_string())?.replace("\\", "/"); + if cfg!(windows) { + realpath_str = realpath_str.trim_start_matches("//?/").to_string(); + } + Ok(json!(realpath_str)) +} + +async fn op_realpath_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { + let args: RealpathArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + + state.check_read(&path)?; + if path.is_relative() { + state.check_read_blind(¤t_dir()?, "CWD")?; + } + + tokio::task::spawn_blocking(move || { + debug!("op_realpath_async {}", path.display()); // corresponds to the realpath on Unix and // CreateFile and GetFinalPathNameByHandle on Windows let realpath = std::fs::canonicalize(&path)?; @@ -719,28 +1056,62 @@ fn op_realpath( } Ok(json!(realpath_str)) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct ReadDirArgs { - promise_id: Option<u64>, path: String, } -fn op_read_dir( - state: &Rc<State>, +fn op_read_dir_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + let args: ReadDirArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + + state.check_read(&path)?; + + debug!("op_read_dir_sync {}", path.display()); + let entries: Vec<_> = std::fs::read_dir(path)? + .filter_map(|entry| { + let entry = entry.unwrap(); + let file_type = entry.file_type().unwrap(); + // Not all filenames can be encoded as UTF-8. Skip those for now. + if let Ok(name) = into_string(entry.file_name()) { + Some(json!({ + "name": name, + "isFile": file_type.is_file(), + "isDirectory": file_type.is_dir(), + "isSymlink": file_type.is_symlink() + })) + } else { + None + } + }) + .collect(); + + Ok(json!({ "entries": entries })) +} + +async fn op_read_dir_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { let args: ReadDirArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); state.check_read(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_read_dir {}", path.display()); + tokio::task::spawn_blocking(move || { + debug!("op_read_dir_async {}", path.display()); let entries: Vec<_> = std::fs::read_dir(path)? .filter_map(|entry| { let entry = entry.unwrap(); @@ -761,21 +1132,41 @@ fn op_read_dir( Ok(json!({ "entries": entries })) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct RenameArgs { - promise_id: Option<u64>, oldpath: String, newpath: String, } -fn op_rename( - state: &Rc<State>, +fn op_rename_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + let args: RenameArgs = serde_json::from_value(args)?; + let oldpath = PathBuf::from(&args.oldpath); + let newpath = PathBuf::from(&args.newpath); + + state.check_read(&oldpath)?; + state.check_write(&oldpath)?; + state.check_write(&newpath)?; + debug!("op_rename_sync {} {}", oldpath.display(), newpath.display()); + std::fs::rename(&oldpath, &newpath)?; + Ok(json!({})) +} + +async fn op_rename_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { let args: RenameArgs = serde_json::from_value(args)?; let oldpath = PathBuf::from(&args.oldpath); let newpath = PathBuf::from(&args.newpath); @@ -784,27 +1175,51 @@ fn op_rename( state.check_write(&oldpath)?; state.check_write(&newpath)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_rename {} {}", oldpath.display(), newpath.display()); + tokio::task::spawn_blocking(move || { + debug!( + "op_rename_async {} {}", + oldpath.display(), + newpath.display() + ); std::fs::rename(&oldpath, &newpath)?; Ok(json!({})) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct LinkArgs { - promise_id: Option<u64>, oldpath: String, newpath: String, } -fn op_link( - state: &Rc<State>, +fn op_link_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + state.check_unstable("Deno.link"); + let args: LinkArgs = serde_json::from_value(args)?; + let oldpath = PathBuf::from(&args.oldpath); + let newpath = PathBuf::from(&args.newpath); + + state.check_read(&oldpath)?; + state.check_write(&newpath)?; + + debug!("op_link_sync {} {}", oldpath.display(), newpath.display()); + std::fs::hard_link(&oldpath, &newpath)?; + Ok(json!({})) +} + +async fn op_link_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { state.check_unstable("Deno.link"); let args: LinkArgs = serde_json::from_value(args)?; let oldpath = PathBuf::from(&args.oldpath); @@ -813,18 +1228,18 @@ fn op_link( state.check_read(&oldpath)?; state.check_write(&newpath)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_link {} {}", oldpath.display(), newpath.display()); + tokio::task::spawn_blocking(move || { + debug!("op_link_async {} {}", oldpath.display(), newpath.display()); std::fs::hard_link(&oldpath, &newpath)?; Ok(json!({})) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct SymlinkArgs { - promise_id: Option<u64>, oldpath: String, newpath: String, #[cfg(not(unix))] @@ -838,11 +1253,67 @@ struct SymlinkOptions { _type: String, } -fn op_symlink( - state: &Rc<State>, +fn op_symlink_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + state.check_unstable("Deno.symlink"); + let args: SymlinkArgs = serde_json::from_value(args)?; + let oldpath = PathBuf::from(&args.oldpath); + let newpath = PathBuf::from(&args.newpath); + + state.check_write(&newpath)?; + + debug!( + "op_symlink_sync {} {}", + oldpath.display(), + newpath.display() + ); + #[cfg(unix)] + { + use std::os::unix::fs::symlink; + symlink(&oldpath, &newpath)?; + Ok(json!({})) + } + #[cfg(not(unix))] + { + use std::os::windows::fs::{symlink_dir, symlink_file}; + + match args.options { + Some(options) => match options._type.as_ref() { + "file" => symlink_file(&oldpath, &newpath)?, + "dir" => symlink_dir(&oldpath, &newpath)?, + _ => return Err(ErrBox::type_error("unsupported type")), + }, + None => { + let old_meta = std::fs::metadata(&oldpath); + match old_meta { + Ok(metadata) => { + if metadata.is_file() { + symlink_file(&oldpath, &newpath)? + } else if metadata.is_dir() { + symlink_dir(&oldpath, &newpath)? + } + } + Err(_) => return Err(ErrBox::type_error( + "you must pass a `options` argument for non-existent target path in windows" + .to_string(), + )), + } + } + }; + Ok(json!({})) + } +} + +async fn op_symlink_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { state.check_unstable("Deno.symlink"); let args: SymlinkArgs = serde_json::from_value(args)?; let oldpath = PathBuf::from(&args.oldpath); @@ -850,9 +1321,8 @@ fn op_symlink( state.check_write(&newpath)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_symlink {} {}", oldpath.display(), newpath.display()); + tokio::task::spawn_blocking(move || { + debug!("op_symlink_async {} {}", oldpath.display(), newpath.display()); #[cfg(unix)] { use std::os::unix::fs::symlink; @@ -889,106 +1359,141 @@ fn op_symlink( Ok(json!({})) } }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct ReadLinkArgs { - promise_id: Option<u64>, path: String, } -fn op_read_link( - state: &Rc<State>, +fn op_read_link_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { let args: ReadLinkArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); state.check_read(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_read_link {}", path.display()); + debug!("op_read_link_value {}", path.display()); + let target = std::fs::read_link(&path)?.into_os_string(); + let targetstr = into_string(target)?; + Ok(json!(targetstr)) +} + +async fn op_read_link_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { + let args: ReadLinkArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + + state.check_read(&path)?; + + tokio::task::spawn_blocking(move || { + debug!("op_read_link_async {}", path.display()); let target = std::fs::read_link(&path)?.into_os_string(); let targetstr = into_string(target)?; Ok(json!(targetstr)) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct FtruncateArgs { - promise_id: Option<u64>, rid: i32, len: i32, } -fn op_ftruncate( - isolate_state: &mut CoreIsolateState, - state: &Rc<State>, +fn op_ftruncate_sync( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { state.check_unstable("Deno.ftruncate"); let args: FtruncateArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let len = args.len as u64; + std_file_resource(resource_table, rid, |r| match r { + Ok(std_file) => std_file.set_len(len).map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error("cannot truncate this type of resource")), + })?; + Ok(json!({})) +} - let resource_table = isolate_state.resource_table.clone(); - let is_sync = args.promise_id.is_none(); - - if is_sync { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.set_len(len).map_err(ErrBox::from), - Err(_) => { - Err(ErrBox::type_error("cannot truncate this type of resource")) - } - })?; - Ok(JsonOp::Sync(json!({}))) - } else { - let fut = async move { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.set_len(len).map_err(ErrBox::from), - Err(_) => { - Err(ErrBox::type_error("cannot truncate this type of resource")) - } - })?; - Ok(json!({})) - }; - Ok(JsonOp::Async(fut.boxed_local())) - } +async fn op_ftruncate_async( + state: Rc<State>, + resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { + state.check_unstable("Deno.ftruncate"); + let args: FtruncateArgs = serde_json::from_value(args)?; + let rid = args.rid as u32; + let len = args.len as u64; + let mut resource_table = resource_table.borrow_mut(); + std_file_resource(&mut resource_table, rid, |r| match r { + Ok(std_file) => std_file.set_len(len).map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error("cannot truncate this type of resource")), + })?; + Ok(json!({})) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct TruncateArgs { - promise_id: Option<u64>, path: String, len: u64, } -fn op_truncate( - state: &Rc<State>, +fn op_truncate_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + let args: TruncateArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + let len = args.len; + + state.check_write(&path)?; + + debug!("op_truncate_sync {} {}", path.display(), len); + let f = std::fs::OpenOptions::new().write(true).open(&path)?; + f.set_len(len)?; + Ok(json!({})) +} + +async fn op_truncate_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { let args: TruncateArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); let len = args.len; state.check_write(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_truncate {} {}", path.display(), len); + tokio::task::spawn_blocking(move || { + debug!("op_truncate_async {} {}", path.display(), len); let f = std::fs::OpenOptions::new().write(true).open(&path)?; f.set_len(len)?; Ok(json!({})) }) + .await + .unwrap() } fn make_temp( @@ -1039,17 +1544,46 @@ fn make_temp( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct MakeTempArgs { - promise_id: Option<u64>, dir: Option<String>, prefix: Option<String>, suffix: Option<String>, } -fn op_make_temp_dir( - state: &Rc<State>, +fn op_make_temp_dir_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + let args: MakeTempArgs = serde_json::from_value(args)?; + + let dir = args.dir.map(|s| PathBuf::from(&s)); + let prefix = args.prefix.map(String::from); + let suffix = args.suffix.map(String::from); + + state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + + // TODO(piscisaureus): use byte vector for paths, not a string. + // See https://github.com/denoland/deno/issues/627. + // We can't assume that paths are always valid utf8 strings. + let path = make_temp( + // Converting Option<String> to Option<&str> + dir.as_deref(), + prefix.as_deref(), + suffix.as_deref(), + true, + )?; + let path_str = into_string(path.into_os_string())?; + + Ok(json!(path_str)) +} + +async fn op_make_temp_dir_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { let args: MakeTempArgs = serde_json::from_value(args)?; let dir = args.dir.map(|s| PathBuf::from(&s)); @@ -1058,8 +1592,7 @@ fn op_make_temp_dir( state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { + tokio::task::spawn_blocking(move || { // TODO(piscisaureus): use byte vector for paths, not a string. // See https://github.com/denoland/deno/issues/627. // We can't assume that paths are always valid utf8 strings. @@ -1074,13 +1607,45 @@ fn op_make_temp_dir( Ok(json!(path_str)) }) + .await + .unwrap() } -fn op_make_temp_file( - state: &Rc<State>, +fn op_make_temp_file_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + let args: MakeTempArgs = serde_json::from_value(args)?; + + let dir = args.dir.map(|s| PathBuf::from(&s)); + let prefix = args.prefix.map(String::from); + let suffix = args.suffix.map(String::from); + + state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + + // TODO(piscisaureus): use byte vector for paths, not a string. + // See https://github.com/denoland/deno/issues/627. + // We can't assume that paths are always valid utf8 strings. + let path = make_temp( + // Converting Option<String> to Option<&str> + dir.as_deref(), + prefix.as_deref(), + suffix.as_deref(), + false, + )?; + let path_str = into_string(path.into_os_string())?; + + Ok(json!(path_str)) +} + +async fn op_make_temp_file_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { let args: MakeTempArgs = serde_json::from_value(args)?; let dir = args.dir.map(|s| PathBuf::from(&s)); @@ -1089,8 +1654,7 @@ fn op_make_temp_file( state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { + tokio::task::spawn_blocking(move || { // TODO(piscisaureus): use byte vector for paths, not a string. // See https://github.com/denoland/deno/issues/627. // We can't assume that paths are always valid utf8 strings. @@ -1105,22 +1669,41 @@ fn op_make_temp_file( Ok(json!(path_str)) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct UtimeArgs { - promise_id: Option<u64>, path: String, atime: i64, mtime: i64, } -fn op_utime( - state: &Rc<State>, +fn op_utime_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { + state.check_unstable("Deno.utime"); + + let args: UtimeArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + + state.check_write(&path)?; + debug!("op_utime_sync {} {} {}", args.path, args.atime, args.mtime); + utime::set_file_times(args.path, args.atime, args.mtime)?; + Ok(json!({})) +} + +async fn op_utime_async( + state: Rc<State>, + _resource_table: Rc<RefCell<ResourceTable>>, + args: Value, + _zero_copy: BufVec, +) -> Result<Value, ErrBox> { state.check_unstable("Deno.utime"); let args: UtimeArgs = serde_json::from_value(args)?; @@ -1128,21 +1711,23 @@ fn op_utime( state.check_write(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_utime {} {} {}", args.path, args.atime, args.mtime); + tokio::task::spawn_blocking(move || { + debug!("op_utime_async {} {} {}", args.path, args.atime, args.mtime); utime::set_file_times(args.path, args.atime, args.mtime)?; Ok(json!({})) }) + .await + .unwrap() } fn op_cwd( - state: &Rc<State>, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { let path = current_dir()?; state.check_read_blind(&path, "CWD")?; let path_str = into_string(path.into_os_string())?; - Ok(JsonOp::Sync(json!(path_str))) + Ok(json!(path_str)) } |