diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2020-03-07 13:20:27 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-07 13:20:27 +0100 |
commit | 88b77da25ca43651a9feb178a5c8d916d983e0a2 (patch) | |
tree | e6d02855c773b715509778771fce9270580cc035 /cli/ops/fs.rs | |
parent | 36c50f442d0ca5e6e751fa3314f8508b24ce7303 (diff) |
refactor: remove cli/ops/files.rs (#4246)
* "op_close" - moved to "cli/ops/resources.rs"
* "op_seek", "op_open" - moved to "cli/ops/fs.rs"
Co-authored-by: Ryan Dahl <ry@tinyclouds.org>
Diffstat (limited to 'cli/ops/fs.rs')
-rw-r--r-- | cli/ops/fs.rs | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs index 84afb1e6e..ad1283c12 100644 --- a/cli/ops/fs.rs +++ b/cli/ops/fs.rs @@ -1,21 +1,28 @@ // 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::io::{FileMetadata, StreamResource}; use crate::fs as deno_fs; use crate::op_error::OpError; use crate::ops::dispatch_json::JsonResult; use crate::state::State; use deno_core::*; +use futures::future::FutureExt; use remove_dir_all::remove_dir_all; +use std; use std::convert::From; use std::fs; +use std::io::SeekFrom; use std::path::Path; use std::time::UNIX_EPOCH; +use tokio; #[cfg(unix)] use std::os::unix::fs::{MetadataExt, PermissionsExt}; pub fn init(i: &mut Isolate, s: &State) { + i.register_op("op_open", s.stateful_json_op(op_open)); + i.register_op("op_seek", s.stateful_json_op(op_seek)); 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)); @@ -37,6 +44,184 @@ pub fn init(i: &mut Isolate, s: &State) { } #[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct OpenArgs { + promise_id: Option<u64>, + path: String, + options: Option<OpenOptions>, + mode: Option<String>, +} + +#[derive(Deserialize, Default, Debug)] +#[serde(rename_all = "camelCase")] +#[serde(default)] +struct OpenOptions { + read: bool, + write: bool, + create: bool, + truncate: bool, + append: bool, + create_new: bool, +} + +fn op_open( + state: &State, + args: Value, + _zero_copy: Option<ZeroCopyBuf>, +) -> Result<JsonOp, OpError> { + let args: OpenArgs = serde_json::from_value(args)?; + let path = deno_fs::resolve_from_cwd(Path::new(&args.path))?; + let state_ = state.clone(); + let mut open_options = tokio::fs::OpenOptions::new(); + + if let Some(options) = args.options { + if options.read { + state.check_read(&path)?; + } + + if options.write || options.append { + state.check_write(&path)?; + } + + open_options + .read(options.read) + .create(options.create) + .write(options.write) + .truncate(options.truncate) + .append(options.append) + .create_new(options.create_new); + } else if let Some(mode) = args.mode { + let mode = mode.as_ref(); + match mode { + "r" => { + state.check_read(&path)?; + } + "w" | "a" | "x" => { + state.check_write(&path)?; + } + &_ => { + state.check_read(&path)?; + state.check_write(&path)?; + } + }; + + match mode { + "r" => { + open_options.read(true); + } + "r+" => { + open_options.read(true).write(true); + } + "w" => { + open_options.create(true).write(true).truncate(true); + } + "w+" => { + open_options + .read(true) + .create(true) + .write(true) + .truncate(true); + } + "a" => { + open_options.create(true).append(true); + } + "a+" => { + open_options.read(true).create(true).append(true); + } + "x" => { + open_options.create_new(true).write(true); + } + "x+" => { + open_options.create_new(true).read(true).write(true); + } + &_ => { + // TODO: this should be type error + return Err(OpError::other("Unknown open mode.".to_string())); + } + } + } else { + return Err(OpError::other( + "Open requires either mode or options.".to_string(), + )); + }; + + let is_sync = args.promise_id.is_none(); + + let fut = async move { + let fs_file = open_options.open(path).await?; + let mut state = state_.borrow_mut(); + let rid = state.resource_table.add( + "fsFile", + Box::new(StreamResource::FsFile(fs_file, FileMetadata::default())), + ); + Ok(json!(rid)) + }; + + if is_sync { + let buf = futures::executor::block_on(fut)?; + Ok(JsonOp::Sync(buf)) + } else { + Ok(JsonOp::Async(fut.boxed_local())) + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct SeekArgs { + promise_id: Option<u64>, + rid: i32, + offset: i32, + whence: i32, +} + +fn op_seek( + state: &State, + args: Value, + _zero_copy: Option<ZeroCopyBuf>, +) -> Result<JsonOp, OpError> { + let args: SeekArgs = serde_json::from_value(args)?; + let rid = args.rid as u32; + let offset = args.offset; + let whence = args.whence as u32; + // Translate seek mode to Rust repr. + let seek_from = match whence { + 0 => SeekFrom::Start(offset as u64), + 1 => SeekFrom::Current(i64::from(offset)), + 2 => SeekFrom::End(i64::from(offset)), + _ => { + return Err(OpError::type_error(format!( + "Invalid seek mode: {}", + whence + ))); + } + }; + + let state = state.borrow(); + let resource = state + .resource_table + .get::<StreamResource>(rid) + .ok_or_else(OpError::bad_resource_id)?; + + let tokio_file = match resource { + StreamResource::FsFile(ref file, _) => file, + _ => return Err(OpError::bad_resource_id()), + }; + let mut file = futures::executor::block_on(tokio_file.try_clone())?; + + let fut = async move { + let pos = file.seek(seek_from).await?; + Ok(json!(pos)) + }; + + if args.promise_id.is_none() { + let buf = futures::executor::block_on(fut)?; + Ok(JsonOp::Sync(buf)) + } else { + Ok(JsonOp::Async(fut.boxed_local())) + } +} + +#[derive(Deserialize)] struct ChdirArgs { directory: String, } |