diff options
Diffstat (limited to 'cli/ops/fs.rs')
-rw-r--r-- | cli/ops/fs.rs | 1702 |
1 files changed, 0 insertions, 1702 deletions
diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs deleted file mode 100644 index 865c5bcca..000000000 --- a/cli/ops/fs.rs +++ /dev/null @@ -1,1702 +0,0 @@ -// 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::io::std_file_resource; -use super::io::{FileMetadata, StreamResource, StreamResourceHolder}; -use crate::fs_util::canonicalize_path; -use crate::permissions::Permissions; -use deno_core::error::custom_error; -use deno_core::error::type_error; -use deno_core::error::AnyError; -use deno_core::serde_json; -use deno_core::serde_json::json; -use deno_core::serde_json::Value; -use deno_core::BufVec; -use deno_core::OpState; -use deno_core::ZeroCopyBuf; -use deno_crypto::rand::thread_rng; -use deno_crypto::rand::Rng; -use serde::Deserialize; -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; -use std::time::UNIX_EPOCH; - -#[cfg(not(unix))] -use deno_core::error::generic_error; -#[cfg(not(unix))] -use deno_core::error::not_supported; - -pub fn init(rt: &mut deno_core::JsRuntime) { - super::reg_json_sync(rt, "op_open_sync", op_open_sync); - super::reg_json_async(rt, "op_open_async", op_open_async); - - super::reg_json_sync(rt, "op_seek_sync", op_seek_sync); - super::reg_json_async(rt, "op_seek_async", op_seek_async); - - super::reg_json_sync(rt, "op_fdatasync_sync", op_fdatasync_sync); - super::reg_json_async(rt, "op_fdatasync_async", op_fdatasync_async); - - super::reg_json_sync(rt, "op_fsync_sync", op_fsync_sync); - super::reg_json_async(rt, "op_fsync_async", op_fsync_async); - - super::reg_json_sync(rt, "op_fstat_sync", op_fstat_sync); - super::reg_json_async(rt, "op_fstat_async", op_fstat_async); - - super::reg_json_sync(rt, "op_umask", op_umask); - super::reg_json_sync(rt, "op_chdir", op_chdir); - - super::reg_json_sync(rt, "op_mkdir_sync", op_mkdir_sync); - super::reg_json_async(rt, "op_mkdir_async", op_mkdir_async); - - super::reg_json_sync(rt, "op_chmod_sync", op_chmod_sync); - super::reg_json_async(rt, "op_chmod_async", op_chmod_async); - - super::reg_json_sync(rt, "op_chown_sync", op_chown_sync); - super::reg_json_async(rt, "op_chown_async", op_chown_async); - - super::reg_json_sync(rt, "op_remove_sync", op_remove_sync); - super::reg_json_async(rt, "op_remove_async", op_remove_async); - - super::reg_json_sync(rt, "op_copy_file_sync", op_copy_file_sync); - super::reg_json_async(rt, "op_copy_file_async", op_copy_file_async); - - super::reg_json_sync(rt, "op_stat_sync", op_stat_sync); - super::reg_json_async(rt, "op_stat_async", op_stat_async); - - super::reg_json_sync(rt, "op_realpath_sync", op_realpath_sync); - super::reg_json_async(rt, "op_realpath_async", op_realpath_async); - - super::reg_json_sync(rt, "op_read_dir_sync", op_read_dir_sync); - super::reg_json_async(rt, "op_read_dir_async", op_read_dir_async); - - super::reg_json_sync(rt, "op_rename_sync", op_rename_sync); - super::reg_json_async(rt, "op_rename_async", op_rename_async); - - super::reg_json_sync(rt, "op_link_sync", op_link_sync); - super::reg_json_async(rt, "op_link_async", op_link_async); - - super::reg_json_sync(rt, "op_symlink_sync", op_symlink_sync); - super::reg_json_async(rt, "op_symlink_async", op_symlink_async); - - super::reg_json_sync(rt, "op_read_link_sync", op_read_link_sync); - super::reg_json_async(rt, "op_read_link_async", op_read_link_async); - - super::reg_json_sync(rt, "op_ftruncate_sync", op_ftruncate_sync); - super::reg_json_async(rt, "op_ftruncate_async", op_ftruncate_async); - - super::reg_json_sync(rt, "op_truncate_sync", op_truncate_sync); - super::reg_json_async(rt, "op_truncate_async", op_truncate_async); - - super::reg_json_sync(rt, "op_make_temp_dir_sync", op_make_temp_dir_sync); - super::reg_json_async(rt, "op_make_temp_dir_async", op_make_temp_dir_async); - - super::reg_json_sync(rt, "op_make_temp_file_sync", op_make_temp_file_sync); - super::reg_json_async(rt, "op_make_temp_file_async", op_make_temp_file_async); - - super::reg_json_sync(rt, "op_cwd", op_cwd); - - super::reg_json_sync(rt, "op_futime_sync", op_futime_sync); - super::reg_json_async(rt, "op_futime_async", op_futime_async); - - super::reg_json_sync(rt, "op_utime_sync", op_utime_sync); - super::reg_json_async(rt, "op_utime_async", op_utime_async); -} - -fn into_string(s: std::ffi::OsString) -> Result<String, AnyError> { - s.into_string().map_err(|s| { - let message = format!("File name or path {:?} is not valid UTF-8", s); - custom_error("InvalidData", message) - }) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct OpenArgs { - path: String, - mode: Option<u32>, - options: OpenOptions, -} - -#[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 open_helper( - state: &mut OpState, - args: Value, -) -> Result<(PathBuf, std::fs::OpenOptions), AnyError> { - let args: OpenArgs = serde_json::from_value(args)?; - let path = Path::new(&args.path).to_path_buf(); - - let mut open_options = std::fs::OpenOptions::new(); - - if let Some(mode) = args.mode { - // mode only used if creating the file on Unix - // if not specified, defaults to 0o666 - #[cfg(unix)] - { - use std::os::unix::fs::OpenOptionsExt; - open_options.mode(mode & 0o777); - } - #[cfg(not(unix))] - let _ = mode; // avoid unused warning - } - - let permissions = state.borrow::<Permissions>(); - let options = args.options; - - if options.read { - permissions.check_read(&path)?; - } - - if options.write || options.append { - permissions.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); - - Ok((path, open_options)) -} - -fn op_open_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let (path, open_options) = open_helper(state, args)?; - let std_file = open_options.open(path)?; - let tokio_file = tokio::fs::File::from_std(std_file); - let rid = state.resource_table.add( - "fsFile", - Box::new(StreamResourceHolder::new(StreamResource::FsFile(Some(( - tokio_file, - FileMetadata::default(), - ))))), - ); - Ok(json!(rid)) -} - -async fn op_open_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let (path, open_options) = open_helper(&mut state.borrow_mut(), args)?; - let tokio_file = tokio::fs::OpenOptions::from(open_options) - .open(path) - .await?; - let rid = state.borrow_mut().resource_table.add( - "fsFile", - Box::new(StreamResourceHolder::new(StreamResource::FsFile(Some(( - tokio_file, - FileMetadata::default(), - ))))), - ); - Ok(json!(rid)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct SeekArgs { - rid: i32, - offset: i64, - whence: i32, -} - -fn seek_helper(args: Value) -> Result<(u32, SeekFrom), AnyError> { - 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(offset), - 2 => SeekFrom::End(offset), - _ => { - return Err(type_error(format!("Invalid seek mode: {}", whence))); - } - }; - - Ok((rid, seek_from)) -} - -fn op_seek_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let (rid, seek_from) = seek_helper(args)?; - let pos = std_file_resource(state, rid, |r| match r { - Ok(std_file) => std_file.seek(seek_from).map_err(AnyError::from), - Err(_) => Err(type_error( - "cannot seek on this type of resource".to_string(), - )), - })?; - Ok(json!(pos)) -} - -async fn op_seek_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - 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 pos = std_file_resource(&mut state.borrow_mut(), rid, |r| match r { - Ok(std_file) => std_file.seek(seek_from).map_err(AnyError::from), - Err(_) => Err(type_error( - "cannot seek on this type of resource".to_string(), - )), - })?; - Ok(json!(pos)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct FdatasyncArgs { - rid: i32, -} - -fn op_fdatasync_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: FdatasyncArgs = serde_json::from_value(args)?; - let rid = args.rid as u32; - std_file_resource(state, rid, |r| match r { - Ok(std_file) => std_file.sync_data().map_err(AnyError::from), - Err(_) => Err(type_error("cannot sync this type of resource".to_string())), - })?; - Ok(json!({})) -} - -async fn op_fdatasync_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: FdatasyncArgs = serde_json::from_value(args)?; - let rid = args.rid as u32; - std_file_resource(&mut state.borrow_mut(), rid, |r| match r { - Ok(std_file) => std_file.sync_data().map_err(AnyError::from), - Err(_) => Err(type_error("cannot sync this type of resource".to_string())), - })?; - Ok(json!({})) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct FsyncArgs { - rid: i32, -} - -fn op_fsync_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: FsyncArgs = serde_json::from_value(args)?; - let rid = args.rid as u32; - std_file_resource(state, rid, |r| match r { - Ok(std_file) => std_file.sync_all().map_err(AnyError::from), - Err(_) => Err(type_error("cannot sync this type of resource".to_string())), - })?; - Ok(json!({})) -} - -async fn op_fsync_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: FsyncArgs = serde_json::from_value(args)?; - let rid = args.rid as u32; - std_file_resource(&mut state.borrow_mut(), rid, |r| match r { - Ok(std_file) => std_file.sync_all().map_err(AnyError::from), - Err(_) => Err(type_error("cannot sync this type of resource".to_string())), - })?; - Ok(json!({})) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct FstatArgs { - rid: i32, -} - -fn op_fstat_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - super::check_unstable(state, "Deno.fstat"); - let args: FstatArgs = serde_json::from_value(args)?; - let rid = args.rid as u32; - let metadata = std_file_resource(state, rid, |r| match r { - Ok(std_file) => std_file.metadata().map_err(AnyError::from), - Err(_) => Err(type_error("cannot stat this type of resource".to_string())), - })?; - Ok(get_stat_json(metadata)) -} - -async fn op_fstat_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - super::check_unstable2(&state, "Deno.fstat"); - - let args: FstatArgs = serde_json::from_value(args)?; - let rid = args.rid as u32; - let metadata = - std_file_resource(&mut state.borrow_mut(), rid, |r| match r { - Ok(std_file) => std_file.metadata().map_err(AnyError::from), - Err(_) => { - Err(type_error("cannot stat this type of resource".to_string())) - } - })?; - Ok(get_stat_json(metadata)) -} - -#[derive(Deserialize)] -struct UmaskArgs { - mask: Option<u32>, -} - -fn op_umask( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - super::check_unstable(state, "Deno.umask"); - let args: UmaskArgs = serde_json::from_value(args)?; - // TODO implement umask for Windows - // see https://github.com/nodejs/node/blob/master/src/node_process_methods.cc - // and https://docs.microsoft.com/fr-fr/cpp/c-runtime-library/reference/umask?view=vs-2019 - #[cfg(not(unix))] - { - let _ = args.mask; // avoid unused warning. - Err(not_supported()) - } - #[cfg(unix)] - { - use nix::sys::stat::mode_t; - use nix::sys::stat::umask; - use nix::sys::stat::Mode; - let r = if let Some(mask) = args.mask { - // If mask provided, return previous. - umask(Mode::from_bits_truncate(mask as mode_t)) - } else { - // If no mask provided, we query the current. Requires two syscalls. - let prev = umask(Mode::from_bits_truncate(0o777)); - let _ = umask(prev); - prev - }; - Ok(json!(r.bits() as u32)) - } -} - -#[derive(Deserialize)] -struct ChdirArgs { - directory: String, -} - -fn op_chdir( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: ChdirArgs = serde_json::from_value(args)?; - let d = PathBuf::from(&args.directory); - state.borrow::<Permissions>().check_read(&d)?; - set_current_dir(&d)?; - Ok(json!({})) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct MkdirArgs { - path: String, - recursive: bool, - mode: Option<u32>, -} - -fn op_mkdir_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - 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.borrow::<Permissions>().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!({})) -} - -async fn op_mkdir_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - 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; - - { - let state = state.borrow(); - state.borrow::<Permissions>().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); - #[cfg(unix)] - { - use std::os::unix::fs::DirBuilderExt; - builder.mode(mode); - } - builder.create(path)?; - Ok(json!({})) - }) - .await - .unwrap() -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct ChmodArgs { - path: String, - mode: u32, -} - -fn op_chmod_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: ChmodArgs = serde_json::from_value(args)?; - let path = Path::new(&args.path).to_path_buf(); - let mode = args.mode & 0o777; - - state.borrow::<Permissions>().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(generic_error("Not implemented")) - } -} - -async fn op_chmod_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: ChmodArgs = serde_json::from_value(args)?; - let path = Path::new(&args.path).to_path_buf(); - let mode = args.mode & 0o777; - - { - let state = state.borrow(); - state.borrow::<Permissions>().check_write(&path)?; - } - - tokio::task::spawn_blocking(move || { - debug!("op_chmod_async {} {: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(not_supported()) - } - }) - .await - .unwrap() -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct ChownArgs { - path: String, - uid: Option<u32>, - gid: Option<u32>, -} - -fn op_chown_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: ChownArgs = serde_json::from_value(args)?; - let path = Path::new(&args.path).to_path_buf(); - state.borrow::<Permissions>().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(generic_error("Not implemented")) - } -} - -async fn op_chown_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: ChownArgs = serde_json::from_value(args)?; - let path = Path::new(&args.path).to_path_buf(); - - { - let state = state.borrow(); - state.borrow::<Permissions>().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}; - 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(not_supported()) - }) - .await - .unwrap() -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct RemoveArgs { - path: String, - recursive: bool, -} - -fn op_remove_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: RemoveArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - let recursive = args.recursive; - - state.borrow::<Permissions>().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<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: RemoveArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - let recursive = args.recursive; - - { - let state = state.borrow(); - state.borrow::<Permissions>().check_write(&path)?; - } - - tokio::task::spawn_blocking(move || { - #[cfg(not(unix))] - use std::os::windows::prelude::MetadataExt; - - let metadata = std::fs::symlink_metadata(&path)?; - - debug!("op_remove_async {} {}", 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!({})) - }) - .await - .unwrap() -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct CopyFileArgs { - from: String, - to: String, -} - -fn op_copy_file_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: CopyFileArgs = serde_json::from_value(args)?; - let from = PathBuf::from(&args.from); - let to = PathBuf::from(&args.to); - - let permissions = state.borrow::<Permissions>(); - permissions.check_read(&from)?; - permissions.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(custom_error("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<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: CopyFileArgs = serde_json::from_value(args)?; - let from = PathBuf::from(&args.from); - let to = PathBuf::from(&args.to); - - { - let state = state.borrow(); - let permissions = state.borrow::<Permissions>(); - permissions.check_read(&from)?; - permissions.check_write(&to)?; - } - - 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. - if cfg!(unix) && !from.is_file() { - return Err(custom_error("NotFound", "File not found")); - } - - // returns size of from as u64 (we ignore) - std::fs::copy(&from, &to)?; - Ok(json!({})) - }) - .await - .unwrap() -} - -fn to_msec(maybe_time: Result<SystemTime, io::Error>) -> Value { - match maybe_time { - Ok(time) => { - let msec = time - .duration_since(UNIX_EPOCH) - .map(|t| t.as_secs_f64() * 1000f64) - .unwrap_or_else(|err| err.duration().as_secs_f64() * -1000f64); - serde_json::Number::from_f64(msec) - .map(Value::Number) - .unwrap_or(Value::Null) - } - Err(_) => Value::Null, - } -} - -#[inline(always)] -fn get_stat_json(metadata: std::fs::Metadata) -> Value { - // Unix stat member (number types only). 0 if not on unix. - macro_rules! usm { - ($member:ident) => {{ - #[cfg(unix)] - { - metadata.$member() - } - #[cfg(not(unix))] - { - 0 - } - }}; - } - - #[cfg(unix)] - use std::os::unix::fs::MetadataExt; - let json_val = json!({ - "isFile": metadata.is_file(), - "isDirectory": metadata.is_dir(), - "isSymlink": metadata.file_type().is_symlink(), - "size": metadata.len(), - // In milliseconds, like JavaScript. Available on both Unix or Windows. - "mtime": to_msec(metadata.modified()), - "atime": to_msec(metadata.accessed()), - "birthtime": to_msec(metadata.created()), - // Following are only valid under Unix. - "dev": usm!(dev), - "ino": usm!(ino), - "mode": usm!(mode), - "nlink": usm!(nlink), - "uid": usm!(uid), - "gid": usm!(gid), - "rdev": usm!(rdev), - // TODO(kevinkassimo): *time_nsec requires BigInt. - // Probably should be treated as String if we need to add them. - "blksize": usm!(blksize), - "blocks": usm!(blocks), - }); - json_val -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct StatArgs { - path: String, - lstat: bool, -} - -fn op_stat_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: StatArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - let lstat = args.lstat; - state.borrow::<Permissions>().check_read(&path)?; - debug!("op_stat_sync {} {}", path.display(), lstat); - let metadata = if lstat { - std::fs::symlink_metadata(&path)? - } else { - std::fs::metadata(&path)? - }; - Ok(get_stat_json(metadata)) -} - -async fn op_stat_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: StatArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - let lstat = args.lstat; - - { - let state = state.borrow(); - state.borrow::<Permissions>().check_read(&path)?; - } - - tokio::task::spawn_blocking(move || { - debug!("op_stat_async {} {}", path.display(), lstat); - let metadata = if lstat { - std::fs::symlink_metadata(&path)? - } else { - std::fs::metadata(&path)? - }; - Ok(get_stat_json(metadata)) - }) - .await - .unwrap() -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct RealpathArgs { - path: String, -} - -fn op_realpath_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: RealpathArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - - let permissions = state.borrow::<Permissions>(); - permissions.check_read(&path)?; - if path.is_relative() { - permissions.check_read_blind(¤t_dir()?, "CWD")?; - } - - debug!("op_realpath_sync {}", path.display()); - // corresponds to the realpath on Unix and - // CreateFile and GetFinalPathNameByHandle on Windows - let realpath = canonicalize_path(&path)?; - let realpath_str = into_string(realpath.into_os_string())?; - Ok(json!(realpath_str)) -} - -async fn op_realpath_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: RealpathArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - - { - let state = state.borrow(); - let permissions = state.borrow::<Permissions>(); - permissions.check_read(&path)?; - if path.is_relative() { - permissions.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 = canonicalize_path(&path)?; - let realpath_str = into_string(realpath.into_os_string())?; - Ok(json!(realpath_str)) - }) - .await - .unwrap() -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct ReadDirArgs { - path: String, -} - -fn op_read_dir_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: ReadDirArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - - state.borrow::<Permissions>().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<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: ReadDirArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - { - let state = state.borrow(); - state.borrow::<Permissions>().check_read(&path)?; - } - 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(); - 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 })) - }) - .await - .unwrap() -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct RenameArgs { - oldpath: String, - newpath: String, -} - -fn op_rename_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: RenameArgs = serde_json::from_value(args)?; - let oldpath = PathBuf::from(&args.oldpath); - let newpath = PathBuf::from(&args.newpath); - - let permissions = state.borrow::<Permissions>(); - permissions.check_read(&oldpath)?; - permissions.check_write(&oldpath)?; - permissions.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<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: RenameArgs = serde_json::from_value(args)?; - let oldpath = PathBuf::from(&args.oldpath); - let newpath = PathBuf::from(&args.newpath); - { - let state = state.borrow(); - let permissions = state.borrow::<Permissions>(); - permissions.check_read(&oldpath)?; - permissions.check_write(&oldpath)?; - permissions.check_write(&newpath)?; - } - 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 { - oldpath: String, - newpath: String, -} - -fn op_link_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - super::check_unstable(state, "Deno.link"); - let args: LinkArgs = serde_json::from_value(args)?; - let oldpath = PathBuf::from(&args.oldpath); - let newpath = PathBuf::from(&args.newpath); - - let permissions = state.borrow::<Permissions>(); - permissions.check_read(&oldpath)?; - permissions.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<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - super::check_unstable2(&state, "Deno.link"); - - let args: LinkArgs = serde_json::from_value(args)?; - let oldpath = PathBuf::from(&args.oldpath); - let newpath = PathBuf::from(&args.newpath); - - { - let state = state.borrow(); - let permissions = state.borrow::<Permissions>(); - permissions.check_read(&oldpath)?; - permissions.check_write(&newpath)?; - } - - 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 { - oldpath: String, - newpath: String, - #[cfg(not(unix))] - options: Option<SymlinkOptions>, -} - -#[cfg(not(unix))] -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct SymlinkOptions { - _type: String, -} - -fn op_symlink_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - super::check_unstable(state, "Deno.symlink"); - let args: SymlinkArgs = serde_json::from_value(args)?; - let oldpath = PathBuf::from(&args.oldpath); - let newpath = PathBuf::from(&args.newpath); - - state.borrow::<Permissions>().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(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(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<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - super::check_unstable2(&state, "Deno.symlink"); - - let args: SymlinkArgs = serde_json::from_value(args)?; - let oldpath = PathBuf::from(&args.oldpath); - let newpath = PathBuf::from(&args.newpath); - - { - let state = state.borrow(); - state.borrow::<Permissions>().check_write(&newpath)?; - } - - tokio::task::spawn_blocking(move || { - debug!("op_symlink_async {} {}", 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(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(type_error("you must pass a `options` argument for non-existent target path in windows".to_string())), - } - } - }; - Ok(json!({})) - } - }) - .await - .unwrap() -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct ReadLinkArgs { - path: String, -} - -fn op_read_link_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: ReadLinkArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - - state.borrow::<Permissions>().check_read(&path)?; - - 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<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: ReadLinkArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - { - let state = state.borrow(); - state.borrow::<Permissions>().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 { - rid: i32, - len: i32, -} - -fn op_ftruncate_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - super::check_unstable(state, "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(state, rid, |r| match r { - Ok(std_file) => std_file.set_len(len).map_err(AnyError::from), - Err(_) => Err(type_error("cannot truncate this type of resource")), - })?; - Ok(json!({})) -} - -async fn op_ftruncate_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - super::check_unstable2(&state, "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(&mut state.borrow_mut(), rid, |r| match r { - Ok(std_file) => std_file.set_len(len).map_err(AnyError::from), - Err(_) => Err(type_error("cannot truncate this type of resource")), - })?; - Ok(json!({})) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct TruncateArgs { - path: String, - len: u64, -} - -fn op_truncate_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let args: TruncateArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - let len = args.len; - - state.borrow::<Permissions>().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<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let args: TruncateArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - let len = args.len; - { - let state = state.borrow(); - state.borrow::<Permissions>().check_write(&path)?; - } - 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( - dir: Option<&Path>, - prefix: Option<&str>, - suffix: Option<&str>, - is_dir: bool, -) -> std::io::Result<PathBuf> { - let prefix_ = prefix.unwrap_or(""); - let suffix_ = suffix.unwrap_or(""); - let mut buf: PathBuf = match dir { - Some(ref p) => p.to_path_buf(), - None => temp_dir(), - } - .join("_"); - let mut rng = thread_rng(); - loop { - let unique = rng.gen::<u32>(); - buf.set_file_name(format!("{}{:08x}{}", prefix_, unique, suffix_)); - let r = if is_dir { - #[allow(unused_mut)] - let mut builder = std::fs::DirBuilder::new(); - #[cfg(unix)] - { - use std::os::unix::fs::DirBuilderExt; - builder.mode(0o700); - } - builder.create(buf.as_path()) - } else { - let mut open_options = std::fs::OpenOptions::new(); - open_options.write(true).create_new(true); - #[cfg(unix)] - { - use std::os::unix::fs::OpenOptionsExt; - open_options.mode(0o600); - } - open_options.open(buf.as_path())?; - Ok(()) - }; - match r { - Err(ref e) if e.kind() == std::io::ErrorKind::AlreadyExists => continue, - Ok(_) => return Ok(buf), - Err(e) => return Err(e), - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct MakeTempArgs { - dir: Option<String>, - prefix: Option<String>, - suffix: Option<String>, -} - -fn op_make_temp_dir_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - 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 - .borrow::<Permissions>() - .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<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - 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); - { - let state = state.borrow(); - state - .borrow::<Permissions>() - .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; - } - 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. - 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)) - }) - .await - .unwrap() -} - -fn op_make_temp_file_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - 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 - .borrow::<Permissions>() - .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<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - 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); - { - let state = state.borrow(); - state - .borrow::<Permissions>() - .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; - } - 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. - 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)) - }) - .await - .unwrap() -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct FutimeArgs { - rid: i32, - atime: (i64, u32), - mtime: (i64, u32), -} - -fn op_futime_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - super::check_unstable(state, "Deno.futimeSync"); - let args: FutimeArgs = serde_json::from_value(args)?; - let rid = args.rid as u32; - let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1); - let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1); - - std_file_resource(state, rid, |r| match r { - Ok(std_file) => { - filetime::set_file_handle_times(std_file, Some(atime), Some(mtime)) - .map_err(AnyError::from) - } - Err(_) => Err(type_error( - "cannot futime on this type of resource".to_string(), - )), - })?; - - Ok(json!({})) -} - -async fn op_futime_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let mut state = state.borrow_mut(); - super::check_unstable(&state, "Deno.futime"); - let args: FutimeArgs = serde_json::from_value(args)?; - let rid = args.rid as u32; - let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1); - let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1); - // TODO Not actually async! https://github.com/denoland/deno/issues/7400 - std_file_resource(&mut state, rid, |r| match r { - Ok(std_file) => { - filetime::set_file_handle_times(std_file, Some(atime), Some(mtime)) - .map_err(AnyError::from) - } - Err(_) => Err(type_error( - "cannot futime on this type of resource".to_string(), - )), - })?; - - Ok(json!({})) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct UtimeArgs { - path: String, - atime: (i64, u32), - mtime: (i64, u32), -} - -fn op_utime_sync( - state: &mut OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - super::check_unstable(state, "Deno.utime"); - - let args: UtimeArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1); - let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1); - - state.borrow::<Permissions>().check_write(&path)?; - filetime::set_file_times(path, atime, mtime)?; - Ok(json!({})) -} - -async fn op_utime_async( - state: Rc<RefCell<OpState>>, - args: Value, - _zero_copy: BufVec, -) -> Result<Value, AnyError> { - let state = state.borrow(); - super::check_unstable(&state, "Deno.utime"); - - let args: UtimeArgs = serde_json::from_value(args)?; - let path = PathBuf::from(&args.path); - let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1); - let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1); - - state.borrow::<Permissions>().check_write(&path)?; - - tokio::task::spawn_blocking(move || { - filetime::set_file_times(path, atime, mtime)?; - Ok(json!({})) - }) - .await - .unwrap() -} - -fn op_cwd( - state: &mut OpState, - _args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let path = current_dir()?; - state - .borrow::<Permissions>() - .check_read_blind(&path, "CWD")?; - let path_str = into_string(path.into_os_string())?; - Ok(json!(path_str)) -} |