diff --git a/API.md b/API.md index dbbc70d4f4..e552d328cc 100644 --- a/API.md +++ b/API.md @@ -114,6 +114,8 @@ Available globally [writeFileSync](https://nodejs.org/api/fs.html#fswritefilesyncfile-data-options) +[chmodSync](https://nodejs.org/api/fs.html#fschmodsyncpath-mode) + ## fs/promises [access](https://nodejs.org/api/fs.html#fsstatpath-options-callback) @@ -136,6 +138,8 @@ Available globally [writeFile](https://nodejs.org/api/fs.html#fspromiseswritefilefile-data-options) +[chmod](https://nodejs.org/api/fs.html#fspromiseschmodpath-mode) + ## module [createRequire](https://nodejs.org/api/module.html#modulecreaterequirefilename) diff --git a/modules/llrt_fs/src/chmod.rs b/modules/llrt_fs/src/chmod.rs new file mode 100644 index 0000000000..f7632b69ad --- /dev/null +++ b/modules/llrt_fs/src/chmod.rs @@ -0,0 +1,49 @@ +#[cfg(unix)] +use llrt_utils::result::ResultExt; +use rquickjs::{Ctx, Result}; +#[cfg(unix)] +use std::os::unix::prelude::PermissionsExt; + +#[cfg(unix)] +pub(crate) fn chmod_error(path: &str) -> String { + ["Can't set permissions of \"", path, "\""].concat() +} + +pub(crate) async fn set_mode(ctx: Ctx<'_>, path: &str, mode: u32) -> Result<()> { + #[cfg(unix)] + { + tokio::fs::set_permissions(path, PermissionsExt::from_mode(mode)) + .await + .or_throw_msg(&ctx, &chmod_error(path))?; + } + #[cfg(not(unix))] + { + _ = ctx; + _ = path; + _ = mode; + } + Ok(()) +} + +pub(crate) fn set_mode_sync(ctx: Ctx<'_>, path: &str, mode: u32) -> Result<()> { + #[cfg(unix)] + { + std::fs::set_permissions(path, PermissionsExt::from_mode(mode)) + .or_throw_msg(&ctx, &chmod_error(path))?; + } + #[cfg(not(unix))] + { + _ = ctx; + _ = path; + _ = mode; + } + Ok(()) +} + +pub async fn chmod(ctx: Ctx<'_>, path: String, mode: u32) -> Result<()> { + set_mode(ctx, &path, mode).await +} + +pub fn chmod_sync(ctx: Ctx<'_>, path: String, mode: u32) -> Result<()> { + set_mode_sync(ctx, &path, mode) +} diff --git a/modules/llrt_fs/src/lib.rs b/modules/llrt_fs/src/lib.rs index 3628c05f7e..8f542d4cce 100644 --- a/modules/llrt_fs/src/lib.rs +++ b/modules/llrt_fs/src/lib.rs @@ -1,6 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 mod access; +mod chmod; mod file_handle; mod mkdir; mod open; @@ -18,6 +19,7 @@ use rquickjs::{ use rquickjs::{Class, Ctx, Object, Result}; use self::access::{access, access_sync}; +use self::chmod::{chmod, chmod_sync}; use self::file_handle::FileHandle; use self::mkdir::{mkdir, mkdir_sync, mkdtemp, mkdtemp_sync}; use self::open::open; @@ -50,6 +52,7 @@ impl ModuleDef for FsPromisesModule { declare.declare("rmdir")?; declare.declare("stat")?; declare.declare("constants")?; + declare.declare("chmod")?; declare.declare("default")?; @@ -95,6 +98,7 @@ impl ModuleDef for FsModule { declare.declare("statSync")?; declare.declare("writeFileSync")?; declare.declare("constants")?; + declare.declare("chmodSync")?; declare.declare("default")?; @@ -123,6 +127,7 @@ impl ModuleDef for FsModule { default.set("rmSync", Func::from(rmfile_sync))?; default.set("statSync", Func::from(stat_fn_sync))?; default.set("writeFileSync", Func::from(write_file_sync))?; + default.set("chmodSync", Func::from(chmod_sync))?; Ok(()) }) @@ -145,6 +150,7 @@ fn export_promises<'js>(ctx: &Ctx<'js>, exports: &Object<'js>) -> Result<()> { exports.set("rm", Func::from(Async(rmfile)))?; exports.set("rmdir", Func::from(Async(rmdir)))?; exports.set("stat", Func::from(Async(stat_fn)))?; + exports.set("chmod", Func::from(Async(chmod)))?; Ok(()) } diff --git a/modules/llrt_fs/src/mkdir.rs b/modules/llrt_fs/src/mkdir.rs index d5629cbe3e..c94ad286b6 100644 --- a/modules/llrt_fs/src/mkdir.rs +++ b/modules/llrt_fs/src/mkdir.rs @@ -1,8 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -#[cfg(unix)] -use std::os::unix::prelude::PermissionsExt; - +use crate::chmod::{set_mode, set_mode_sync}; use llrt_utils::result::ResultExt; use ring::rand::{SecureRandom, SystemRandom}; use rquickjs::{function::Opt, Ctx, Object, Result}; @@ -18,16 +16,7 @@ pub async fn mkdir<'js>(ctx: Ctx<'js>, path: String, options: Opt>) } .or_throw_msg(&ctx, &["Can't create dir \"", &path, "\""].concat())?; - #[cfg(unix)] - { - fs::set_permissions(&path, PermissionsExt::from_mode(mode)) - .await - .or_throw_msg(&ctx, &["Can't set permissions of \"", &path, "\""].concat())?; - } - #[cfg(not(unix))] - { - _ = mode; - } + set_mode(ctx, &path, mode).await?; Ok(path) } @@ -42,15 +31,7 @@ pub fn mkdir_sync<'js>(ctx: Ctx<'js>, path: String, options: Opt>) - } .or_throw_msg(&ctx, &["Can't create dir \"", &path, "\""].concat())?; - #[cfg(unix)] - { - std::fs::set_permissions(&path, PermissionsExt::from_mode(mode)) - .or_throw_msg(&ctx, &["Can't set permissions of \"", &path, "\""].concat())?; - } - #[cfg(not(unix))] - { - _ = mode; - } + set_mode_sync(ctx, &path, mode)?; Ok(path) } diff --git a/types/fs.d.ts b/types/fs.d.ts index 77f8103a03..cb0a97b21d 100644 --- a/types/fs.d.ts +++ b/types/fs.d.ts @@ -325,4 +325,12 @@ declare module "fs" { * @param [mode=fs.constants.F_OK] */ export function accessSync(path: PathLike, mode?: Mode): void; + + /** + * For detailed information, see the documentation of the asynchronous version of + * this API: {@link chmod}. + * + * See the POSIX [`chmod(2)`](http://man7.org/linux/man-pages/man2/chmod.2.html) documentation for more detail. + */ + export function chmodSync(path: PathLike, mode: Mode): void; } diff --git a/types/fs/promises.d.ts b/types/fs/promises.d.ts index 9aa309cabe..e215ba6e62 100644 --- a/types/fs/promises.d.ts +++ b/types/fs/promises.d.ts @@ -502,4 +502,10 @@ declare module "fs/promises" { } | BufferEncoding ): Promise; + + /** + * Changes the permissions of a file. + * @return Fulfills with `undefined` upon success. + */ + function chmod(path: PathLike, mode: Mode): Promise; }