From 1a7cb832285ea120319994157035faec85f5884b Mon Sep 17 00:00:00 2001 From: James Bronder <36022278+jbronder@users.noreply.github.com> Date: Sat, 11 Jan 2025 13:56:28 -0800 Subject: [PATCH 1/6] feat(fs/unstable): added import references for chmod --- _tools/node_test_runner/run_test.mjs | 1 + fs/deno.json | 1 + 2 files changed, 2 insertions(+) diff --git a/_tools/node_test_runner/run_test.mjs b/_tools/node_test_runner/run_test.mjs index a622ed529acd..8a22a103fda2 100644 --- a/_tools/node_test_runner/run_test.mjs +++ b/_tools/node_test_runner/run_test.mjs @@ -51,6 +51,7 @@ import "../../collections/without_all_test.ts"; import "../../collections/zip_test.ts"; import "../../fs/unstable_stat_test.ts"; import "../../fs/unstable_lstat_test.ts"; +import "../../fs/unstable_chmod_test.ts"; for (const testDef of testDefinitions) { test(testDef.name, testDef.fn); diff --git a/fs/deno.json b/fs/deno.json index 267f80a1bdec..3dadbd2742c0 100644 --- a/fs/deno.json +++ b/fs/deno.json @@ -13,6 +13,7 @@ "./exists": "./exists.ts", "./expand-glob": "./expand_glob.ts", "./move": "./move.ts", + "./unstable-chmod": "./unstable_chmod.ts", "./unstable-lstat": "./unstable_lstat.ts", "./unstable-stat": "./unstable_stat.ts", "./unstable-types": "./unstable_types.ts", From ca14f0d8f6110302b6271d9d3a2d780a4f1dcade Mon Sep 17 00:00:00 2001 From: James Bronder <36022278+jbronder@users.noreply.github.com> Date: Sat, 11 Jan 2025 13:59:05 -0800 Subject: [PATCH 2/6] feat(fs/unstable): added chmod and chmodSync functions with tests --- fs/unstable_chmod.ts | 88 +++++++++++++++++++ fs/unstable_chmod_test.ts | 176 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 fs/unstable_chmod.ts create mode 100644 fs/unstable_chmod_test.ts diff --git a/fs/unstable_chmod.ts b/fs/unstable_chmod.ts new file mode 100644 index 000000000000..0a84b984e18a --- /dev/null +++ b/fs/unstable_chmod.ts @@ -0,0 +1,88 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +import { getNodeFs, isDeno } from "./_utils.ts"; +import { mapError } from "./_map_error.ts"; + +/** + * Changes the permission of a specific file/directory of specified path. + * Ignores the process's umask. + * + * Requires `allow-write` permission. + * + * The mode is a sequence of 3 octal numbers. The first/left-most number + * specifies the permissions for the owner. The second number specifies the + * permissions for the group. The last/right-most number specifies the + * permissions for others. For example, with a mode of 0o764, the owner (7) + * can read/write/execute, the group (6) can read/write and everyone else (4) + * can read only. + * + * | Number | Description | + * | ------ | ----------- | + * | 7 | read, write, and execute | + * | 6 | read and write | + * | 5 | read and execute | + * | 4 | read only | + * | 3 | write and execute | + * | 2 | write only | + * | 1 | execute only | + * | 0 | no permission | + * + * NOTE: This API currently throws on Windows. + * + * @example Usage + * ```ts + * import { chmod } from "@std/fs/unstable-chmod"; + * + * await chmod("README.md", 0o444); + * ``` + * + * @tags allow-write + * + * @param path The path to the file or directory. + * @param mode A sequence of 3 octal numbers representing file permissions. + */ +export async function chmod(path: string | URL, mode: number) { + if (isDeno) { + await Deno.chmod(path, mode); + } else { + try { + await getNodeFs().promises.chmod(path, mode); + } catch (error) { + throw mapError(error); + } + } +} + +/** + * Synchronously changes the permission of a specific file/directory of + * specified path. Ignores the process's umask. + * + * Requires `allow-write` permission. + * + * For a full description, see {@linkcode chmod}. + * + * NOTE: This API currently throws on Windows. + * + * @example Usage + * ```ts + * import { chmodSync } from "@std/fs/unstable-chmod"; + * + * chmodSync("README.md", 0o666); + * ``` + * + * @tags allow-write + * + * @param path The path to the file or directory. + * @param mode A sequence of 3 octal numbers representing permissions. See {@linkcode chmod}. + */ +export function chmodSync(path: string | URL, mode: number) { + if (isDeno) { + Deno.chmodSync(path, mode); + } else { + try { + getNodeFs().chmodSync(path, mode); + } catch (error) { + throw mapError(error); + } + } +} diff --git a/fs/unstable_chmod_test.ts b/fs/unstable_chmod_test.ts new file mode 100644 index 000000000000..08f6a7574f10 --- /dev/null +++ b/fs/unstable_chmod_test.ts @@ -0,0 +1,176 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +import { + assertEquals, + assertExists, + assertRejects, + assertThrows, +} from "@std/assert"; +import { resolve } from "@std/path"; +import { chmod, chmodSync } from "./unstable_chmod.ts"; +import { NotFound } from "./unstable_errors.js"; + +Deno.test({ + name: "chmod() sets read only permission bits on regular files", + ignore: Deno.build.os === "windows", + fn: async () => { + const tempDirPath = await Deno.makeTempDir({ prefix: "chmod_" }); + const testFile = resolve(tempDirPath, "chmod_file.txt"); + using _tempFile = await Deno.create(testFile); + + // Check initial testFile permissions are 0o644 (-rw-r--r--). + const fileStatBefore = await Deno.stat(testFile); + assertExists(fileStatBefore.mode, "mode property is null"); + assertEquals(fileStatBefore.mode & 0o644, 0o644); + + // Set testFile permission bits to read only, 0o444 (-r--r--r--). + await chmod(testFile, 0o444); + const fileStatAfter = await Deno.stat(testFile); + assertExists(fileStatAfter.mode, "mode property is null"); + assertEquals(fileStatAfter.mode & 0o444, 0o444); + + await Deno.remove(tempDirPath, { recursive: true }); + }, +}); + +Deno.test({ + name: "chmod() sets read only permission bits on a directory", + ignore: Deno.build.os === "windows", + fn: async () => { + const tempDirPath = await Deno.makeTempDir({ prefix: "chmod_" }); + const testDir = resolve(tempDirPath, "testDir"); + await Deno.mkdir(testDir); + + // Check initial testDir permissions are 0o755 (drwxr-xr-x). + const dirStatBefore = await Deno.stat(testDir); + assertExists(dirStatBefore.mode, "mode property is null"); + assertEquals(dirStatBefore.mode & 0o755, 0o755); + + // Set testDir permission bits to read only to 0o444 (dr--r--r--). + await chmod(testDir, 0o444); + const dirStatAfter = await Deno.stat(testDir); + assertExists(dirStatAfter.mode, "mode property is null"); + assertEquals(dirStatAfter.mode & 0o444, 0o444); + + await Deno.remove(tempDirPath, { recursive: true }); + }, +}); + +Deno.test({ + name: + "chmod() sets write only permission bits of regular file through the symlink", + ignore: Deno.build.os === "windows", + fn: async () => { + const tempDirPath = await Deno.makeTempDir({ prefix: "chmod_" }); + const testFile = resolve(tempDirPath, "chmod_file.txt"); + const testSymlink = resolve(tempDirPath, "chmod_file.txt.link"); + + using _tempFile = await Deno.create(testFile); + await Deno.symlink(testFile, testSymlink); + + // Check initial testFile permission bits are 0o644 (-rw-r-xr-x) reading through testSymlink. + const symlinkStatBefore = await Deno.stat(testSymlink); + assertExists(symlinkStatBefore.mode, "mode property via symlink is null"); + assertEquals(symlinkStatBefore.mode & 0o644, 0o644); + + // Set write only permission bits of testFile through testSymlink to 0o222 (--w--w--w-). + await chmod(testSymlink, 0o222); + const symlinkStatAfter = await Deno.stat(testSymlink); + assertExists(symlinkStatAfter.mode, "mode property via symlink is null"); + const fileStatAfter = await Deno.stat(testFile); + assertExists(fileStatAfter.mode, "mode property via file is null"); + + // Check if both regular file mode and the mode read through symlink are both write only. + assertEquals(symlinkStatAfter.mode, fileStatAfter.mode); + + await Deno.remove(tempDirPath, { recursive: true }); + }, +}); + +Deno.test("chmod() rejects with NotFound for a non-existent file", async () => { + await assertRejects(async () => { + await chmod("non_existent_file.txt", 0o644); + }, NotFound); +}); + +Deno.test({ + name: "chmodSync() sets read-only permission bits on regular files", + ignore: Deno.build.os === "windows", + fn: () => { + const tempDirPath = Deno.makeTempDirSync({ prefix: "chmodSync_" }); + const testFile = resolve(tempDirPath, "chmod_file.txt"); + using _tempFile = Deno.createSync(testFile); + + // Check initial testFile permissions are 0o644 (-rw-r--r--). + const fileStatBefore = Deno.statSync(testFile); + assertExists(fileStatBefore.mode, "mode property is null"); + assertEquals(fileStatBefore.mode & 0o644, 0o644); + + // Set testFile permission bits to read only, 0o444 (-r--r--r--). + chmodSync(testFile, 0o444); + const fileStatAfter = Deno.statSync(testFile); + assertExists(fileStatAfter.mode, "mode property is null"); + assertEquals(fileStatAfter.mode & 0o444, 0o444); + + Deno.removeSync(tempDirPath, { recursive: true }); + }, +}); + +Deno.test({ + name: "chmodSync() sets read-only permissions bits on directories", + ignore: Deno.build.os === "windows", + fn: () => { + const tempDirPath = Deno.makeTempDirSync({ prefix: "chmodSync_" }); + const testDir = resolve(tempDirPath, "testDir"); + Deno.mkdirSync(testDir); + + // Check initial testDir permissions are 0o755 (drwxr-xr-x). + const dirStatBefore = Deno.statSync(testDir); + assertExists(dirStatBefore.mode, "mode property is null"); + assertEquals(dirStatBefore.mode & 0o755, 0o755); + + // Set testDir permission bits to read only to 0o444 (dr--r--r--). + chmodSync(testDir, 0o444); + const dirStatAfter = Deno.statSync(testDir); + assertExists(dirStatAfter.mode, "mode property is null"); + assertEquals(dirStatAfter.mode & 0o444, 0o444); + + Deno.removeSync(tempDirPath, { recursive: true }); + }, +}); + +Deno.test({ + name: "chmodSync() sets write only permission on a regular file through a symlink", + ignore: Deno.build.os === "windows", + fn: () => { + const tempDirPath = Deno.makeTempDirSync({ prefix: "chmodSync_" }); + const testFile = resolve(tempDirPath, "chmod_file.txt"); + const testSymlink = resolve(tempDirPath, "chmod_file.txt.link"); + + using _tempFile = Deno.createSync(testFile); + Deno.symlinkSync(testFile, testSymlink); + + // Check initial testFile permission bits are 0o644 (-rw-r-xr-x) reading through testSymlink. + const symlinkStatBefore = Deno.statSync(testSymlink); + assertExists(symlinkStatBefore.mode, "mode property via symlink is null"); + assertEquals(symlinkStatBefore.mode & 0o644, 0o644); + + // Set write only permission bits of testFile through testSymlink to 0o222 (--w--w--w-). + chmodSync(testSymlink, 0o222); + const symlinkStatAfter = Deno.statSync(testSymlink); + assertExists(symlinkStatAfter.mode, "mode property via symlink is null"); + const fileStatAfter = Deno.statSync(testFile); + assertExists(fileStatAfter.mode, "mode property via file is null"); + + // Check if both regular file mode and the mode read through symlink are both write only. + assertEquals(symlinkStatAfter.mode, fileStatAfter.mode); + + Deno.removeSync(tempDirPath, { recursive: true }); + }, +}); + +Deno.test("chmodSync() throws with NotFound for a non-existent file", () => { + assertThrows(() => { + chmodSync("non_existent_file.txt", 0o644); + }, NotFound); +}); From ed53828a3cb284542c63ded0319729e59f924fc0 Mon Sep 17 00:00:00 2001 From: James Bronder <36022278+jbronder@users.noreply.github.com> Date: Sat, 11 Jan 2025 14:40:38 -0800 Subject: [PATCH 3/6] fix(fs/unstable): shortened `name:` value to be on same line as `name:` --- fs/unstable_chmod_test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/unstable_chmod_test.ts b/fs/unstable_chmod_test.ts index 08f6a7574f10..5a58adfdf8b1 100644 --- a/fs/unstable_chmod_test.ts +++ b/fs/unstable_chmod_test.ts @@ -57,8 +57,7 @@ Deno.test({ }); Deno.test({ - name: - "chmod() sets write only permission bits of regular file through the symlink", + name: "chmod() sets write only permission bits of regular file via symlink", ignore: Deno.build.os === "windows", fn: async () => { const tempDirPath = await Deno.makeTempDir({ prefix: "chmod_" }); @@ -140,7 +139,7 @@ Deno.test({ }); Deno.test({ - name: "chmodSync() sets write only permission on a regular file through a symlink", + name: "chmodSync() sets write only permission on a regular file via symlink", ignore: Deno.build.os === "windows", fn: () => { const tempDirPath = Deno.makeTempDirSync({ prefix: "chmodSync_" }); From 3bd2293542f935889c2faeee53465faf466ed36b Mon Sep 17 00:00:00 2001 From: James Bronder <36022278+jbronder@users.noreply.github.com> Date: Sat, 11 Jan 2025 14:46:00 -0800 Subject: [PATCH 4/6] fix(fs/unstable): added no-eval for chmod code snippets from throwing on windows --- fs/unstable_chmod.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/unstable_chmod.ts b/fs/unstable_chmod.ts index 0a84b984e18a..92b6f37100ae 100644 --- a/fs/unstable_chmod.ts +++ b/fs/unstable_chmod.ts @@ -30,7 +30,7 @@ import { mapError } from "./_map_error.ts"; * NOTE: This API currently throws on Windows. * * @example Usage - * ```ts + * ```ts no-eval * import { chmod } from "@std/fs/unstable-chmod"; * * await chmod("README.md", 0o444); @@ -64,7 +64,7 @@ export async function chmod(path: string | URL, mode: number) { * NOTE: This API currently throws on Windows. * * @example Usage - * ```ts + * ```ts no-eval * import { chmodSync } from "@std/fs/unstable-chmod"; * * chmodSync("README.md", 0o666); From 28e1ac79afdcee6b2c43809023788e15f7c18df6 Mon Sep 17 00:00:00 2001 From: James Bronder <36022278+jbronder@users.noreply.github.com> Date: Sun, 12 Jan 2025 20:33:08 -0800 Subject: [PATCH 5/6] fix: replace `no-eval` with `ignore` to code snippets to prevent throw on windows --- fs/unstable_chmod.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/unstable_chmod.ts b/fs/unstable_chmod.ts index 92b6f37100ae..43a95a7b4897 100644 --- a/fs/unstable_chmod.ts +++ b/fs/unstable_chmod.ts @@ -30,7 +30,7 @@ import { mapError } from "./_map_error.ts"; * NOTE: This API currently throws on Windows. * * @example Usage - * ```ts no-eval + * ```ts ignore * import { chmod } from "@std/fs/unstable-chmod"; * * await chmod("README.md", 0o444); @@ -64,7 +64,7 @@ export async function chmod(path: string | URL, mode: number) { * NOTE: This API currently throws on Windows. * * @example Usage - * ```ts no-eval + * ```ts ignore * import { chmodSync } from "@std/fs/unstable-chmod"; * * chmodSync("README.md", 0o666); From f429fff5f6f0f6e866556d6649a8479d2c192407 Mon Sep 17 00:00:00 2001 From: James Bronder <36022278+jbronder@users.noreply.github.com> Date: Wed, 15 Jan 2025 22:18:38 -0800 Subject: [PATCH 6/6] test: update tests to run on node and deno --- fs/unstable_chmod_test.ts | 99 ++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/fs/unstable_chmod_test.ts b/fs/unstable_chmod_test.ts index 5a58adfdf8b1..0b648bac50a7 100644 --- a/fs/unstable_chmod_test.ts +++ b/fs/unstable_chmod_test.ts @@ -6,83 +6,96 @@ import { assertRejects, assertThrows, } from "@std/assert"; -import { resolve } from "@std/path"; import { chmod, chmodSync } from "./unstable_chmod.ts"; import { NotFound } from "./unstable_errors.js"; +import { platform, tmpdir } from "node:os"; +import { join, resolve } from "node:path"; +import { mkdir, mkdtemp, open, rm, stat, symlink } from "node:fs/promises"; +import { + closeSync, + mkdirSync, + mkdtempSync, + openSync, + rmSync, + statSync, + symlinkSync, +} from "node:fs"; Deno.test({ name: "chmod() sets read only permission bits on regular files", - ignore: Deno.build.os === "windows", + ignore: platform() === "win32", fn: async () => { - const tempDirPath = await Deno.makeTempDir({ prefix: "chmod_" }); - const testFile = resolve(tempDirPath, "chmod_file.txt"); - using _tempFile = await Deno.create(testFile); + const tempDirPath = await mkdtemp(resolve(tmpdir(), "chmod_")); + const testFile = join(tempDirPath, "chmod_file.txt"); + const tempFh = await open(testFile, "w"); // Check initial testFile permissions are 0o644 (-rw-r--r--). - const fileStatBefore = await Deno.stat(testFile); + const fileStatBefore = await stat(testFile); assertExists(fileStatBefore.mode, "mode property is null"); assertEquals(fileStatBefore.mode & 0o644, 0o644); // Set testFile permission bits to read only, 0o444 (-r--r--r--). await chmod(testFile, 0o444); - const fileStatAfter = await Deno.stat(testFile); + const fileStatAfter = await stat(testFile); assertExists(fileStatAfter.mode, "mode property is null"); assertEquals(fileStatAfter.mode & 0o444, 0o444); - await Deno.remove(tempDirPath, { recursive: true }); + await tempFh.close(); + await rm(tempDirPath, { recursive: true, force: true }); }, }); Deno.test({ name: "chmod() sets read only permission bits on a directory", - ignore: Deno.build.os === "windows", + ignore: platform() === "win32", fn: async () => { - const tempDirPath = await Deno.makeTempDir({ prefix: "chmod_" }); + const tempDirPath = await mkdtemp(resolve(tmpdir(), "chmod_")); const testDir = resolve(tempDirPath, "testDir"); - await Deno.mkdir(testDir); + await mkdir(testDir); // Check initial testDir permissions are 0o755 (drwxr-xr-x). - const dirStatBefore = await Deno.stat(testDir); + const dirStatBefore = await stat(testDir); assertExists(dirStatBefore.mode, "mode property is null"); assertEquals(dirStatBefore.mode & 0o755, 0o755); // Set testDir permission bits to read only to 0o444 (dr--r--r--). await chmod(testDir, 0o444); - const dirStatAfter = await Deno.stat(testDir); + const dirStatAfter = await stat(testDir); assertExists(dirStatAfter.mode, "mode property is null"); assertEquals(dirStatAfter.mode & 0o444, 0o444); - await Deno.remove(tempDirPath, { recursive: true }); + await rm(tempDirPath, { recursive: true, force: true }); }, }); Deno.test({ name: "chmod() sets write only permission bits of regular file via symlink", - ignore: Deno.build.os === "windows", + ignore: platform() === "win32", fn: async () => { - const tempDirPath = await Deno.makeTempDir({ prefix: "chmod_" }); + const tempDirPath = await mkdtemp(resolve(tmpdir(), "chmod_")); const testFile = resolve(tempDirPath, "chmod_file.txt"); const testSymlink = resolve(tempDirPath, "chmod_file.txt.link"); - using _tempFile = await Deno.create(testFile); - await Deno.symlink(testFile, testSymlink); + const tempFh = await open(testFile, "w"); + await symlink(testFile, testSymlink); // Check initial testFile permission bits are 0o644 (-rw-r-xr-x) reading through testSymlink. - const symlinkStatBefore = await Deno.stat(testSymlink); + const symlinkStatBefore = await stat(testSymlink); assertExists(symlinkStatBefore.mode, "mode property via symlink is null"); assertEquals(symlinkStatBefore.mode & 0o644, 0o644); // Set write only permission bits of testFile through testSymlink to 0o222 (--w--w--w-). await chmod(testSymlink, 0o222); - const symlinkStatAfter = await Deno.stat(testSymlink); + const symlinkStatAfter = await stat(testSymlink); assertExists(symlinkStatAfter.mode, "mode property via symlink is null"); - const fileStatAfter = await Deno.stat(testFile); + const fileStatAfter = await stat(testFile); assertExists(fileStatAfter.mode, "mode property via file is null"); // Check if both regular file mode and the mode read through symlink are both write only. assertEquals(symlinkStatAfter.mode, fileStatAfter.mode); - await Deno.remove(tempDirPath, { recursive: true }); + await tempFh.close(); + await rm(tempDirPath, { recursive: true, force: true }); }, }); @@ -94,77 +107,79 @@ Deno.test("chmod() rejects with NotFound for a non-existent file", async () => { Deno.test({ name: "chmodSync() sets read-only permission bits on regular files", - ignore: Deno.build.os === "windows", + ignore: platform() === "win32", fn: () => { - const tempDirPath = Deno.makeTempDirSync({ prefix: "chmodSync_" }); + const tempDirPath = mkdtempSync(resolve(tmpdir(), "chmodSync_")); const testFile = resolve(tempDirPath, "chmod_file.txt"); - using _tempFile = Deno.createSync(testFile); + const tempFd = openSync(testFile, "w"); // Check initial testFile permissions are 0o644 (-rw-r--r--). - const fileStatBefore = Deno.statSync(testFile); + const fileStatBefore = statSync(testFile); assertExists(fileStatBefore.mode, "mode property is null"); assertEquals(fileStatBefore.mode & 0o644, 0o644); // Set testFile permission bits to read only, 0o444 (-r--r--r--). chmodSync(testFile, 0o444); - const fileStatAfter = Deno.statSync(testFile); + const fileStatAfter = statSync(testFile); assertExists(fileStatAfter.mode, "mode property is null"); assertEquals(fileStatAfter.mode & 0o444, 0o444); - Deno.removeSync(tempDirPath, { recursive: true }); + closeSync(tempFd); + rmSync(tempDirPath, { recursive: true, force: true }); }, }); Deno.test({ name: "chmodSync() sets read-only permissions bits on directories", - ignore: Deno.build.os === "windows", + ignore: platform() === "win32", fn: () => { - const tempDirPath = Deno.makeTempDirSync({ prefix: "chmodSync_" }); + const tempDirPath = mkdtempSync(resolve(tmpdir(), "chmodSync_")); const testDir = resolve(tempDirPath, "testDir"); - Deno.mkdirSync(testDir); + mkdirSync(testDir); // Check initial testDir permissions are 0o755 (drwxr-xr-x). - const dirStatBefore = Deno.statSync(testDir); + const dirStatBefore = statSync(testDir); assertExists(dirStatBefore.mode, "mode property is null"); assertEquals(dirStatBefore.mode & 0o755, 0o755); // Set testDir permission bits to read only to 0o444 (dr--r--r--). chmodSync(testDir, 0o444); - const dirStatAfter = Deno.statSync(testDir); + const dirStatAfter = statSync(testDir); assertExists(dirStatAfter.mode, "mode property is null"); assertEquals(dirStatAfter.mode & 0o444, 0o444); - Deno.removeSync(tempDirPath, { recursive: true }); + rmSync(tempDirPath, { recursive: true, force: true }); }, }); Deno.test({ name: "chmodSync() sets write only permission on a regular file via symlink", - ignore: Deno.build.os === "windows", + ignore: platform() === "win32", fn: () => { - const tempDirPath = Deno.makeTempDirSync({ prefix: "chmodSync_" }); + const tempDirPath = mkdtempSync(resolve(tmpdir(), "chmodSync_")); const testFile = resolve(tempDirPath, "chmod_file.txt"); const testSymlink = resolve(tempDirPath, "chmod_file.txt.link"); - using _tempFile = Deno.createSync(testFile); - Deno.symlinkSync(testFile, testSymlink); + const tempFd = openSync(testFile, "w"); + symlinkSync(testFile, testSymlink); // Check initial testFile permission bits are 0o644 (-rw-r-xr-x) reading through testSymlink. - const symlinkStatBefore = Deno.statSync(testSymlink); + const symlinkStatBefore = statSync(testSymlink); assertExists(symlinkStatBefore.mode, "mode property via symlink is null"); assertEquals(symlinkStatBefore.mode & 0o644, 0o644); // Set write only permission bits of testFile through testSymlink to 0o222 (--w--w--w-). chmodSync(testSymlink, 0o222); - const symlinkStatAfter = Deno.statSync(testSymlink); + const symlinkStatAfter = statSync(testSymlink); assertExists(symlinkStatAfter.mode, "mode property via symlink is null"); - const fileStatAfter = Deno.statSync(testFile); + const fileStatAfter = statSync(testFile); assertExists(fileStatAfter.mode, "mode property via file is null"); // Check if both regular file mode and the mode read through symlink are both write only. assertEquals(symlinkStatAfter.mode, fileStatAfter.mode); - Deno.removeSync(tempDirPath, { recursive: true }); + closeSync(tempFd); + rmSync(tempDirPath, { recursive: true, force: true }); }, });