fix(fs/ensure_dir): allow links to directories (#4132)

Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com>
Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
This commit is contained in:
Joe Hillenbrand 2024-04-22 04:51:39 -07:00 committed by GitHub
parent ac5723de73
commit 06866a6d47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 66 additions and 16 deletions

View File

@ -19,7 +19,7 @@ import { getFileInfoType } from "./_get_file_info_type.ts";
*/
export async function ensureDir(dir: string | URL) {
try {
const fileInfo = await Deno.lstat(dir);
const fileInfo = await Deno.stat(dir);
if (!fileInfo.isDirectory) {
throw new Error(
`Ensure path exists, expected 'dir', got '${
@ -35,7 +35,7 @@ export async function ensureDir(dir: string | URL) {
}
// The dir doesn't exist. Create it.
// This can be racy. So we catch AlreadyExists and check lstat again.
// This can be racy. So we catch AlreadyExists and check stat again.
try {
await Deno.mkdir(dir, { recursive: true });
} catch (err) {
@ -43,7 +43,7 @@ export async function ensureDir(dir: string | URL) {
throw err;
}
const fileInfo = await Deno.lstat(dir);
const fileInfo = await Deno.stat(dir);
if (!fileInfo.isDirectory) {
throw new Error(
`Ensure path exists, expected 'dir', got '${
@ -72,7 +72,7 @@ export async function ensureDir(dir: string | URL) {
*/
export function ensureDirSync(dir: string | URL) {
try {
const fileInfo = Deno.lstatSync(dir);
const fileInfo = Deno.statSync(dir);
if (!fileInfo.isDirectory) {
throw new Error(
`Ensure path exists, expected 'dir', got '${
@ -88,7 +88,7 @@ export function ensureDirSync(dir: string | URL) {
}
// The dir doesn't exist. Create it.
// This can be racy. So we catch AlreadyExists and check lstat again.
// This can be racy. So we catch AlreadyExists and check stat again.
try {
Deno.mkdirSync(dir, { recursive: true });
} catch (err) {
@ -96,7 +96,7 @@ export function ensureDirSync(dir: string | URL) {
throw err;
}
const fileInfo = Deno.lstatSync(dir);
const fileInfo = Deno.statSync(dir);
if (!fileInfo.isDirectory) {
throw new Error(
`Ensure path exists, expected 'dir', got '${

View File

@ -1,14 +1,14 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assertRejects, assertThrows } from "../assert/mod.ts";
import { assertEquals, assertRejects, assertThrows } from "../assert/mod.ts";
import * as path from "../path/mod.ts";
import { ensureDir, ensureDirSync } from "./ensure_dir.ts";
import { ensureFile, ensureFileSync } from "./ensure_file.ts";
const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
const testdataDir = path.resolve(moduleDir, "testdata");
const testdataDir = path.resolve(moduleDir, "testdata", "ensure_dir");
Deno.test("ensureDir() creates dir if it does not exist", async function () {
const baseDir = path.join(testdataDir, "ensure_dir_not_exist");
const baseDir = path.join(testdataDir, "not_exist");
const testDir = path.join(baseDir, "test");
try {
@ -22,7 +22,7 @@ Deno.test("ensureDir() creates dir if it does not exist", async function () {
});
Deno.test("ensureDirSync() creates dir if it does not exist", function () {
const baseDir = path.join(testdataDir, "ensure_dir_sync_not_exist");
const baseDir = path.join(testdataDir, "sync_not_exist");
const testDir = path.join(baseDir, "test");
try {
@ -36,7 +36,7 @@ Deno.test("ensureDirSync() creates dir if it does not exist", function () {
});
Deno.test("ensureDir() ensures existing dir exists", async function () {
const baseDir = path.join(testdataDir, "ensure_dir_exist");
const baseDir = path.join(testdataDir, "exist");
const testDir = path.join(baseDir, "test");
try {
@ -53,7 +53,7 @@ Deno.test("ensureDir() ensures existing dir exists", async function () {
});
Deno.test("ensureDirSync() ensures existing dir exists", function () {
const baseDir = path.join(testdataDir, "ensure_dir_sync_exist");
const baseDir = path.join(testdataDir, "sync_exist");
const testDir = path.join(baseDir, "test");
try {
@ -69,8 +69,32 @@ Deno.test("ensureDirSync() ensures existing dir exists", function () {
}
});
Deno.test("ensureDir() accepts links to dirs", async function () {
const ldir = path.join(testdataDir, "ldir");
await ensureDir(ldir);
// test dir should still exists.
await Deno.stat(ldir);
// ldir should be still be a symlink
const { isSymlink } = await Deno.lstat(ldir);
assertEquals(isSymlink, true);
});
Deno.test("ensureDirSync() accepts links to dirs", function () {
const ldir = path.join(testdataDir, "ldir");
ensureDirSync(ldir);
// test dir should still exists.
Deno.statSync(ldir);
// ldir should be still be a symlink
const { isSymlink } = Deno.lstatSync(ldir);
assertEquals(isSymlink, true);
});
Deno.test("ensureDir() rejects if input is a file", async function () {
const baseDir = path.join(testdataDir, "ensure_dir_exist_file");
const baseDir = path.join(testdataDir, "exist_file");
const testFile = path.join(baseDir, "test");
try {
@ -89,7 +113,7 @@ Deno.test("ensureDir() rejects if input is a file", async function () {
});
Deno.test("ensureDirSync() throws if input is a file", function () {
const baseDir = path.join(testdataDir, "ensure_dir_exist_file_async");
const baseDir = path.join(testdataDir, "exist_file_async");
const testFile = path.join(baseDir, "test");
try {
@ -107,11 +131,35 @@ Deno.test("ensureDirSync() throws if input is a file", function () {
}
});
Deno.test("ensureDir() rejects links to files", async function () {
const lf = path.join(testdataDir, "lf");
await assertRejects(
async () => {
await ensureDir(lf);
},
Error,
`Ensure path exists, expected 'dir', got 'file'`,
);
});
Deno.test("ensureDirSync() rejects links to files", function () {
const lf = path.join(testdataDir, "lf");
assertThrows(
() => {
ensureDirSync(lf);
},
Error,
`Ensure path exists, expected 'dir', got 'file'`,
);
});
Deno.test({
name: "ensureDir() rejects permission fs write error",
permissions: { read: true },
async fn() {
const baseDir = path.join(testdataDir, "ensure_dir_without_permission");
const baseDir = path.join(testdataDir, "without_permission");
// ensureDir fails because this test doesn't have write permissions,
// but don't swallow that error.
@ -128,7 +176,7 @@ Deno.test({
fn() {
const baseDir = path.join(
testdataDir,
"ensure_dir_sync_without_permission",
"sync_without_permission",
);
// ensureDirSync fails because this test doesn't have write permissions,

0
fs/testdata/ensure_dir/dir/.keep vendored Normal file
View File

0
fs/testdata/ensure_dir/f vendored Normal file
View File

1
fs/testdata/ensure_dir/ldir vendored Symbolic link
View File

@ -0,0 +1 @@
dir

1
fs/testdata/ensure_dir/lf vendored Symbolic link
View File

@ -0,0 +1 @@
f